Merge "Adding some more gestures and actions for accessibility."
diff --git a/Android.mk b/Android.mk
index ab06058..3b2d32d 100644
--- a/Android.mk
+++ b/Android.mk
@@ -329,7 +329,10 @@
)
# include definition of libcore_to_document
-include $(LOCAL_PATH)/../../libcore/Docs.mk
+include libcore/Docs.mk
+
+# include definition of junit_to_document
+include external/junit/Common.mk
non_base_dirs := \
../../external/apache-http/src/org/apache/http
@@ -353,7 +356,8 @@
# Common sources for doc check and api check
common_src_files := \
$(call find-other-html-files, $(html_dirs)) \
- $(addprefix ../../libcore/, $(call libcore_to_document, $(LOCAL_PATH)/../../libcore))
+ $(addprefix ../../libcore/, $(call libcore_to_document, $(LOCAL_PATH)/../../libcore)) \
+ $(addprefix ../../external/junit/, $(call junit_to_document, $(LOCAL_PATH)/../../external/junit))
# These are relative to frameworks/base
framework_docs_LOCAL_SRC_FILES := \
diff --git a/CleanSpec.mk b/CleanSpec.mk
index 1cd5d01..939c117 100644
--- a/CleanSpec.mk
+++ b/CleanSpec.mk
@@ -126,6 +126,9 @@
$(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/SHARED_LIBRARIES/libRS_intermediates)
$(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/STATIC_LIBRARIES/libRSDriver_intermediates)
$(call add-clean-step, rm -rf $(OUT_DIR)/host/$(HOST_PREBUILT_TAG)/obj/STATIC_LIBRARIES/libRS_intermediates)
+$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/framework_intermediates/src/core/java/android/accessibilityservice/IEventListener.java)
+$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/framework_intermediates/src/core/java/android/accessibilityservice/IEventListener.P)
+$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/framework_intermediates/src/core/java/android/view/accessibility/IAccessibilityManager.P)
# ************************************************
# NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST
# ************************************************
diff --git a/api/16.txt b/api/16.txt
index 0e3a140..9e9f880 100644
--- a/api/16.txt
+++ b/api/16.txt
@@ -9513,7 +9513,7 @@
method public abstract void onSensorChanged(int, float[]);
}
- public class SensorManager {
+ public abstract class SensorManager {
method public static float getAltitude(float, float);
method public static void getAngleChange(float[], float[], float[]);
method public android.hardware.Sensor getDefaultSensor(int);
@@ -24806,7 +24806,7 @@
enum_constant public static final android.webkit.ConsoleMessage.MessageLevel WARNING;
}
- public final class CookieManager {
+ public class CookieManager {
method public synchronized boolean acceptCookie();
method public static boolean allowFileSchemeCookies();
method public java.lang.String getCookie(java.lang.String);
@@ -24838,7 +24838,7 @@
method public abstract void onDownloadStart(java.lang.String, java.lang.String, java.lang.String, java.lang.String, long);
}
- public final class GeolocationPermissions {
+ public class GeolocationPermissions {
method public void allow(java.lang.String);
method public void clear(java.lang.String);
method public void clearAll();
@@ -24864,8 +24864,6 @@
public class JsResult {
method public final void cancel();
method public final void confirm();
- method protected final void wakeUp();
- field protected boolean mResult;
}
public class MimeTypeMap {
@@ -24958,7 +24956,7 @@
method public java.lang.String getUrl();
}
- public final class WebIconDatabase {
+ public class WebIconDatabase {
method public void close();
method public static android.webkit.WebIconDatabase getInstance();
method public void open(java.lang.String);
@@ -25127,7 +25125,7 @@
enum_constant public static final android.webkit.WebSettings.ZoomDensity MEDIUM;
}
- public final class WebStorage {
+ public class WebStorage {
method public void deleteAllData();
method public void deleteOrigin(java.lang.String);
method public static android.webkit.WebStorage getInstance();
diff --git a/api/current.txt b/api/current.txt
index b4cfe6c..d8387c1 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -534,7 +534,7 @@
field public static final int imeSubtypeLocale = 16843500; // 0x10102ec
field public static final int imeSubtypeMode = 16843501; // 0x10102ed
field public static final int immersive = 16843456; // 0x10102c0
- field public static final int importantForAccessibility = 16843699; // 0x10103b3
+ field public static final int importantForAccessibility = 16843698; // 0x10103b2
field public static final int inAnimation = 16843127; // 0x1010177
field public static final int includeFontPadding = 16843103; // 0x101015f
field public static final int includeInGlobalSearch = 16843374; // 0x101026e
@@ -936,7 +936,6 @@
field public static final int summaryOff = 16843248; // 0x10101f0
field public static final int summaryOn = 16843247; // 0x10101ef
field public static final int supportsRtl = 16843688; // 0x10103a8
- field public static final int supportsSentenceSpellCheck = 16843698; // 0x10103b2
field public static final int supportsUploading = 16843419; // 0x101029b
field public static final int switchMinWidth = 16843632; // 0x1010370
field public static final int switchPadding = 16843633; // 0x1010371
@@ -2325,6 +2324,8 @@
ctor public LayoutTransition();
method public void addChild(android.view.ViewGroup, android.view.View);
method public void addTransitionListener(android.animation.LayoutTransition.TransitionListener);
+ method public void disableTransitionType(int);
+ method public void enableTransitionType(int);
method public android.animation.Animator getAnimator(int);
method public long getDuration(int);
method public android.animation.TimeInterpolator getInterpolator(int);
@@ -2335,6 +2336,7 @@
method public void hideChild(android.view.ViewGroup, android.view.View, int);
method public boolean isChangingLayout();
method public boolean isRunning();
+ method public boolean isTransitionTypeEnabled(int);
method public void removeChild(android.view.ViewGroup, android.view.View);
method public void removeTransitionListener(android.animation.LayoutTransition.TransitionListener);
method public void setAnimateParentHierarchy(boolean);
@@ -2349,6 +2351,7 @@
field public static final int APPEARING = 2; // 0x2
field public static final int CHANGE_APPEARING = 0; // 0x0
field public static final int CHANGE_DISAPPEARING = 1; // 0x1
+ field public static final int CHANGING = 4; // 0x4
field public static final int DISAPPEARING = 3; // 0x3
}
@@ -2909,6 +2912,7 @@
public class ActivityOptions {
method public void join(android.app.ActivityOptions);
method public static android.app.ActivityOptions makeCustomAnimation(android.content.Context, int, int);
+ method public static android.app.ActivityOptions makeScaleUpAnimation(android.view.View, int, int, int, int);
method public static android.app.ActivityOptions makeThumbnailScaleUpAnimation(android.view.View, android.graphics.Bitmap, int, int);
method public android.os.Bundle toBundle();
}
@@ -3278,6 +3282,7 @@
method public android.app.DownloadManager.Request addRequestHeader(java.lang.String, java.lang.String);
method public void allowScanningByMediaScanner();
method public android.app.DownloadManager.Request setAllowedNetworkTypes(int);
+ method public android.app.DownloadManager.Request setAllowedOverMetered(boolean);
method public android.app.DownloadManager.Request setAllowedOverRoaming(boolean);
method public android.app.DownloadManager.Request setDescription(java.lang.CharSequence);
method public android.app.DownloadManager.Request setDestinationInExternalFilesDir(android.content.Context, java.lang.String, java.lang.String);
@@ -3783,6 +3788,12 @@
method public android.app.Notification.Builder setWhen(long);
}
+ public static class Notification.InboxStyle {
+ ctor public Notification.InboxStyle(android.app.Notification.Builder);
+ method public android.app.Notification.InboxStyle addLine(java.lang.CharSequence);
+ method public android.app.Notification build();
+ }
+
public class NotificationManager {
method public void cancel(int);
method public void cancel(java.lang.String, int);
@@ -9030,6 +9041,8 @@
public class SurfaceTexture {
ctor public SurfaceTexture(int);
+ method public void attachToGLContext(int);
+ method public void detachFromGLContext();
method public long getTimestamp();
method public void getTransformMatrix(float[]);
method public void release();
@@ -9792,7 +9805,7 @@
method public abstract void onSensorChanged(int, float[]);
}
- public class SensorManager {
+ public abstract class SensorManager {
method public static float getAltitude(float, float);
method public static void getAngleChange(float[], float[], float[]);
method public android.hardware.Sensor getDefaultSensor(int);
@@ -9808,8 +9821,8 @@
method public boolean registerListener(android.hardware.SensorEventListener, android.hardware.Sensor, int);
method public boolean registerListener(android.hardware.SensorEventListener, android.hardware.Sensor, int, android.os.Handler);
method public static boolean remapCoordinateSystem(float[], int, int, float[]);
- method public deprecated void unregisterListener(android.hardware.SensorListener, int);
method public deprecated void unregisterListener(android.hardware.SensorListener);
+ method public deprecated void unregisterListener(android.hardware.SensorListener, int);
method public void unregisterListener(android.hardware.SensorEventListener, android.hardware.Sensor);
method public void unregisterListener(android.hardware.SensorEventListener);
field public static final int AXIS_MINUS_X = 129; // 0x81
@@ -10948,6 +10961,103 @@
field public static final int STOP_VIDEO_RECORDING = 3; // 0x3
}
+ public final class MediaCodec {
+ method public void configure(java.util.Map<java.lang.String, java.lang.Object>, android.view.Surface, android.media.MediaCrypto, int);
+ method public static android.media.MediaCodec createByCodecName(java.lang.String);
+ method public static android.media.MediaCodec createDecoderByType(java.lang.String);
+ method public static android.media.MediaCodec createEncoderByType(java.lang.String);
+ method public final int dequeueInputBuffer(long);
+ method public final int dequeueOutputBuffer(android.media.MediaCodec.BufferInfo, long);
+ method public final void flush();
+ method public java.nio.ByteBuffer[] getInputBuffers();
+ method public java.nio.ByteBuffer[] getOutputBuffers();
+ method public final java.util.Map<java.lang.String, java.lang.Object> getOutputFormat();
+ method public final void queueInputBuffer(int, int, int, long, int);
+ method public final void queueSecureInputBuffer(int, int, android.media.MediaCodec.CryptoInfo, long, int);
+ method public final void release();
+ method public final void releaseOutputBuffer(int, boolean);
+ method public final void start();
+ method public final void stop();
+ field public static int CONFIGURE_FLAG_ENCODE;
+ field public static final int FLAG_CODECCONFIG = 2; // 0x2
+ field public static final int FLAG_EOS = 4; // 0x4
+ field public static final int FLAG_SYNCFRAME = 1; // 0x1
+ field public static final int INFO_OUTPUT_BUFFERS_CHANGED = -3; // 0xfffffffd
+ field public static final int INFO_OUTPUT_FORMAT_CHANGED = -2; // 0xfffffffe
+ field public static final int INFO_TRY_AGAIN_LATER = -1; // 0xffffffff
+ field public static final int MODE_AES_CTR = 1; // 0x1
+ field public static final int MODE_UNENCRYPTED = 0; // 0x0
+ }
+
+ public static final class MediaCodec.BufferInfo {
+ ctor public MediaCodec.BufferInfo();
+ method public void set(int, int, long, int);
+ field public int flags;
+ field public int offset;
+ field public long presentationTimeUs;
+ field public int size;
+ }
+
+ public static final class MediaCodec.CryptoInfo {
+ ctor public MediaCodec.CryptoInfo();
+ method public void set(int, int[], int[], byte[], byte[], int);
+ field public byte[] iv;
+ field public byte[] key;
+ field public int mode;
+ field public int[] numBytesOfClearData;
+ field public int[] numBytesOfEncryptedData;
+ field public int numSubSamples;
+ }
+
+ public final class MediaCodecList {
+ method public static final int countCodecs();
+ method public static final android.media.MediaCodecList.CodecCapabilities getCodecCapabilities(int, java.lang.String);
+ method public static final java.lang.String getCodecName(int);
+ method public static final java.lang.String[] getSupportedTypes(int);
+ method public static final boolean isEncoder(int);
+ }
+
+ public static final class MediaCodecList.CodecCapabilities {
+ ctor public MediaCodecList.CodecCapabilities();
+ field public int[] colorFormats;
+ field public android.media.MediaCodecList.CodecProfileLevel[] profileLevels;
+ }
+
+ public static final class MediaCodecList.CodecProfileLevel {
+ ctor public MediaCodecList.CodecProfileLevel();
+ field public int level;
+ field public int profile;
+ }
+
+ public final class MediaCrypto {
+ ctor public MediaCrypto(byte[], byte[]) throws java.lang.RuntimeException;
+ method public static final boolean isCryptoSchemeSupported(byte[]);
+ method public final void release();
+ method public final boolean requiresSecureDecoderComponent(java.lang.String);
+ }
+
+ public final class MediaExtractor {
+ ctor public MediaExtractor();
+ method public boolean advance();
+ method public int countTracks();
+ method public boolean getSampleCryptoInfo(android.media.MediaCodec.CryptoInfo);
+ method public int getSampleFlags();
+ method public long getSampleTime();
+ method public int getSampleTrackIndex();
+ method public java.util.Map<java.lang.String, java.lang.Object> getTrackFormat(int);
+ method public int readSampleData(java.nio.ByteBuffer, int);
+ method public final void release();
+ method public void seekTo(long);
+ method public void selectTrack(int);
+ method public final void setDataSource(android.content.Context, android.net.Uri, java.util.Map<java.lang.String, java.lang.String>) throws java.io.IOException;
+ method public final void setDataSource(java.lang.String, java.util.Map<java.lang.String, java.lang.String>);
+ method public final void setDataSource(java.lang.String);
+ method public final void setDataSource(java.io.FileDescriptor);
+ method public final void setDataSource(java.io.FileDescriptor, long, long);
+ field public static final int SAMPLE_FLAG_ENCRYPTED = 2; // 0x2
+ field public static final int SAMPLE_FLAG_SYNC = 1; // 0x1
+ }
+
public class MediaMetadataRetriever {
ctor public MediaMetadataRetriever();
method public java.lang.String extractMetadata(int);
@@ -11846,6 +11956,7 @@
method public deprecated boolean getBackgroundDataSetting();
method public android.net.NetworkInfo getNetworkInfo(int);
method public int getNetworkPreference();
+ method public boolean isActiveNetworkMetered();
method public static boolean isNetworkTypeValid(int);
method public boolean requestRouteToHost(int, int);
method public void setNetworkPreference(int);
@@ -12318,6 +12429,86 @@
}
+package android.net.nsd {
+
+ public class DnsSdServiceInfo implements android.os.Parcelable {
+ ctor public DnsSdServiceInfo();
+ method public int describeContents();
+ method public java.net.InetAddress getHost();
+ method public int getPort();
+ method public java.lang.String getServiceName();
+ method public java.lang.String getServiceType();
+ method public void setHost(java.net.InetAddress);
+ method public void setPort(int);
+ method public void setServiceName(java.lang.String);
+ method public void setServiceType(java.lang.String);
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator CREATOR;
+ }
+
+ public class DnsSdTxtRecord implements android.os.Parcelable {
+ ctor public DnsSdTxtRecord();
+ ctor public DnsSdTxtRecord(byte[]);
+ ctor public DnsSdTxtRecord(android.net.nsd.DnsSdTxtRecord);
+ method public boolean contains(java.lang.String);
+ method public int describeContents();
+ method public java.lang.String get(java.lang.String);
+ method public byte[] getRawData();
+ method public int keyCount();
+ method public int remove(java.lang.String);
+ method public void set(java.lang.String, java.lang.String);
+ method public int size();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator CREATOR;
+ }
+
+ public class NsdManager {
+ method public void deinitialize(android.net.nsd.NsdManager.Channel);
+ method public void discoverServices(android.net.nsd.NsdManager.Channel, java.lang.String, android.net.nsd.NsdManager.DnsSdDiscoveryListener);
+ method public void initialize(android.content.Context, android.os.Looper, android.net.nsd.NsdManager.ChannelListener);
+ method public void registerService(android.net.nsd.NsdManager.Channel, java.lang.String, java.lang.String, int, android.net.nsd.NsdManager.DnsSdRegisterListener);
+ method public void resolveService(android.net.nsd.NsdManager.Channel, java.lang.String, java.lang.String, android.net.nsd.NsdManager.DnsSdResolveListener);
+ method public void stopServiceDiscovery(android.net.nsd.NsdManager.Channel, android.net.nsd.NsdManager.ActionListener);
+ method public void unregisterService(android.net.nsd.NsdManager.Channel, int, android.net.nsd.NsdManager.ActionListener);
+ field public static final int ALREADY_ACTIVE = 3; // 0x3
+ field public static final int BUSY = 2; // 0x2
+ field public static final int ERROR = 0; // 0x0
+ field public static final int MAX_REGS_REACHED = 4; // 0x4
+ field public static final int UNSUPPORTED = 1; // 0x1
+ }
+
+ public static abstract interface NsdManager.ActionListener {
+ method public abstract void onFailure(int);
+ method public abstract void onSuccess();
+ }
+
+ public static class NsdManager.Channel {
+ }
+
+ public static abstract interface NsdManager.ChannelListener {
+ method public abstract void onChannelConnected(android.net.nsd.NsdManager.Channel);
+ method public abstract void onChannelDisconnected();
+ }
+
+ public static abstract interface NsdManager.DnsSdDiscoveryListener {
+ method public abstract void onFailure(int);
+ method public abstract void onServiceFound(android.net.nsd.DnsSdServiceInfo);
+ method public abstract void onServiceLost(android.net.nsd.DnsSdServiceInfo);
+ method public abstract void onStarted(java.lang.String);
+ }
+
+ public static abstract interface NsdManager.DnsSdRegisterListener {
+ method public abstract void onFailure(int);
+ method public abstract void onServiceRegistered(int, android.net.nsd.DnsSdServiceInfo);
+ }
+
+ public static abstract interface NsdManager.DnsSdResolveListener {
+ method public abstract void onFailure(int);
+ method public abstract void onServiceResolved(android.net.nsd.DnsSdServiceInfo);
+ }
+
+}
+
package android.net.rtp {
public class AudioCodec {
@@ -12824,15 +13015,26 @@
}
public class WifiP2pManager {
+ method public void addLocalService(android.net.wifi.p2p.WifiP2pManager.Channel, android.net.wifi.p2p.nsd.WifiP2pServiceInfo, android.net.wifi.p2p.WifiP2pManager.ActionListener);
+ method public void addServiceRequest(android.net.wifi.p2p.WifiP2pManager.Channel, android.net.wifi.p2p.nsd.WifiP2pServiceRequest, android.net.wifi.p2p.WifiP2pManager.ActionListener);
method public void cancelConnect(android.net.wifi.p2p.WifiP2pManager.Channel, android.net.wifi.p2p.WifiP2pManager.ActionListener);
+ method public void clearLocalServices(android.net.wifi.p2p.WifiP2pManager.Channel, android.net.wifi.p2p.WifiP2pManager.ActionListener);
+ method public void clearServiceRequests(android.net.wifi.p2p.WifiP2pManager.Channel, android.net.wifi.p2p.WifiP2pManager.ActionListener);
method public void connect(android.net.wifi.p2p.WifiP2pManager.Channel, android.net.wifi.p2p.WifiP2pConfig, android.net.wifi.p2p.WifiP2pManager.ActionListener);
method public void createGroup(android.net.wifi.p2p.WifiP2pManager.Channel, android.net.wifi.p2p.WifiP2pManager.ActionListener);
method public void discoverPeers(android.net.wifi.p2p.WifiP2pManager.Channel, android.net.wifi.p2p.WifiP2pManager.ActionListener);
+ method public void discoverServices(android.net.wifi.p2p.WifiP2pManager.Channel, android.net.wifi.p2p.WifiP2pManager.ActionListener);
method public android.net.wifi.p2p.WifiP2pManager.Channel initialize(android.content.Context, android.os.Looper, android.net.wifi.p2p.WifiP2pManager.ChannelListener);
method public void removeGroup(android.net.wifi.p2p.WifiP2pManager.Channel, android.net.wifi.p2p.WifiP2pManager.ActionListener);
+ method public void removeLocalService(android.net.wifi.p2p.WifiP2pManager.Channel, android.net.wifi.p2p.nsd.WifiP2pServiceInfo, android.net.wifi.p2p.WifiP2pManager.ActionListener);
+ method public void removeServiceRequest(android.net.wifi.p2p.WifiP2pManager.Channel, android.net.wifi.p2p.nsd.WifiP2pServiceRequest, android.net.wifi.p2p.WifiP2pManager.ActionListener);
method public void requestConnectionInfo(android.net.wifi.p2p.WifiP2pManager.Channel, android.net.wifi.p2p.WifiP2pManager.ConnectionInfoListener);
method public void requestGroupInfo(android.net.wifi.p2p.WifiP2pManager.Channel, android.net.wifi.p2p.WifiP2pManager.GroupInfoListener);
method public void requestPeers(android.net.wifi.p2p.WifiP2pManager.Channel, android.net.wifi.p2p.WifiP2pManager.PeerListListener);
+ method public void setDnsSdResponseListeners(android.net.wifi.p2p.WifiP2pManager.Channel, android.net.wifi.p2p.WifiP2pManager.DnsSdServiceResponseListener, android.net.wifi.p2p.WifiP2pManager.DnsSdTxtRecordListener);
+ method public void setServiceResponseListener(android.net.wifi.p2p.WifiP2pManager.Channel, android.net.wifi.p2p.WifiP2pManager.ServiceResponseListener);
+ method public void setUpnpServiceResponseListener(android.net.wifi.p2p.WifiP2pManager.Channel, android.net.wifi.p2p.WifiP2pManager.UpnpServiceResponseListener);
+ method public void stopPeerDiscovery(android.net.wifi.p2p.WifiP2pManager.Channel, android.net.wifi.p2p.WifiP2pManager.ActionListener);
field public static final int BUSY = 2; // 0x2
field public static final int ERROR = 0; // 0x0
field public static final java.lang.String EXTRA_DISCOVERY_STATE = "discoveryState";
@@ -12868,6 +13070,14 @@
method public abstract void onConnectionInfoAvailable(android.net.wifi.p2p.WifiP2pInfo);
}
+ public static abstract interface WifiP2pManager.DnsSdServiceResponseListener {
+ method public abstract void onDnsSdServiceAvailable(java.lang.String, java.lang.String, android.net.wifi.p2p.WifiP2pDevice);
+ }
+
+ public static abstract interface WifiP2pManager.DnsSdTxtRecordListener {
+ method public abstract void onDnsSdTxtRecordAvailable(java.lang.String, android.net.nsd.DnsSdTxtRecord, android.net.wifi.p2p.WifiP2pDevice);
+ }
+
public static abstract interface WifiP2pManager.GroupInfoListener {
method public abstract void onGroupInfoAvailable(android.net.wifi.p2p.WifiP2pGroup);
}
@@ -12876,6 +13086,53 @@
method public abstract void onPeersAvailable(android.net.wifi.p2p.WifiP2pDeviceList);
}
+ public static abstract interface WifiP2pManager.ServiceResponseListener {
+ method public abstract void onServiceAvailable(int, byte[], android.net.wifi.p2p.WifiP2pDevice);
+ }
+
+ public static abstract interface WifiP2pManager.UpnpServiceResponseListener {
+ method public abstract void onUpnpServiceAvailable(java.util.List<java.lang.String>, android.net.wifi.p2p.WifiP2pDevice);
+ }
+
+}
+
+package android.net.wifi.p2p.nsd {
+
+ public class WifiP2pDnsSdServiceInfo extends android.net.wifi.p2p.nsd.WifiP2pServiceInfo {
+ method public static android.net.wifi.p2p.nsd.WifiP2pDnsSdServiceInfo newInstance(java.lang.String, java.lang.String, android.net.nsd.DnsSdTxtRecord);
+ }
+
+ public class WifiP2pDnsSdServiceRequest extends android.net.wifi.p2p.nsd.WifiP2pServiceRequest {
+ method public static android.net.wifi.p2p.nsd.WifiP2pDnsSdServiceRequest newInstance();
+ method public static android.net.wifi.p2p.nsd.WifiP2pDnsSdServiceRequest newInstance(java.lang.String);
+ method public static android.net.wifi.p2p.nsd.WifiP2pDnsSdServiceRequest newInstance(java.lang.String, java.lang.String);
+ }
+
+ public class WifiP2pServiceInfo implements android.os.Parcelable {
+ method public int describeContents();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final int SERVICE_TYPE_ALL = 0; // 0x0
+ field public static final int SERVICE_TYPE_BONJOUR = 1; // 0x1
+ field public static final int SERVICE_TYPE_UPNP = 2; // 0x2
+ field public static final int SERVICE_TYPE_VENDOR_SPECIFIC = 255; // 0xff
+ }
+
+ public class WifiP2pServiceRequest implements android.os.Parcelable {
+ method public int describeContents();
+ method public static android.net.wifi.p2p.nsd.WifiP2pServiceRequest newInstance(int, java.lang.String);
+ method public static android.net.wifi.p2p.nsd.WifiP2pServiceRequest newInstance(int);
+ method public void writeToParcel(android.os.Parcel, int);
+ }
+
+ public class WifiP2pUpnpServiceInfo extends android.net.wifi.p2p.nsd.WifiP2pServiceInfo {
+ method public static android.net.wifi.p2p.nsd.WifiP2pUpnpServiceInfo newInstance(java.lang.String, java.lang.String, java.util.List<java.lang.String>);
+ }
+
+ public class WifiP2pUpnpServiceRequest extends android.net.wifi.p2p.nsd.WifiP2pServiceRequest {
+ method public static android.net.wifi.p2p.nsd.WifiP2pUpnpServiceRequest newInstance();
+ method public static android.net.wifi.p2p.nsd.WifiP2pUpnpServiceRequest newInstance(java.lang.String);
+ }
+
}
package android.nfc {
@@ -16039,6 +16296,8 @@
protected static abstract interface CalendarContract.AttendeesColumns {
field public static final java.lang.String ATTENDEE_EMAIL = "attendeeEmail";
+ field public static final java.lang.String ATTENDEE_IDENTITY = "attendeeIdentity";
+ field public static final java.lang.String ATTENDEE_ID_NAMESPACE = "attendeeIdNamespace";
field public static final java.lang.String ATTENDEE_NAME = "attendeeName";
field public static final java.lang.String ATTENDEE_RELATIONSHIP = "attendeeRelationship";
field public static final java.lang.String ATTENDEE_STATUS = "attendeeStatus";
@@ -23316,6 +23575,7 @@
method public android.graphics.Canvas lockCanvas(android.graphics.Rect);
method protected final void onDraw(android.graphics.Canvas);
method public void setOpaque(boolean);
+ method public void setSurfaceTexture(android.graphics.SurfaceTexture);
method public void setSurfaceTextureListener(android.view.TextureView.SurfaceTextureListener);
method public void setTransform(android.graphics.Matrix);
method public void unlockCanvasAndPost(android.graphics.Canvas);
@@ -24140,6 +24400,7 @@
method public android.view.View getFocusedChild();
method public android.view.animation.LayoutAnimationController getLayoutAnimation();
method public android.view.animation.Animation.AnimationListener getLayoutAnimationListener();
+ method public int getLayoutMode();
method public android.animation.LayoutTransition getLayoutTransition();
method public int getPersistentDrawingCache();
method public int indexOfChild(android.view.View);
@@ -24187,6 +24448,7 @@
method public void setDescendantFocusability(int);
method public void setLayoutAnimation(android.view.animation.LayoutAnimationController);
method public void setLayoutAnimationListener(android.view.animation.Animation.AnimationListener);
+ method public void setLayoutMode(int);
method public void setLayoutTransition(android.animation.LayoutTransition);
method public void setMotionEventSplittingEnabled(boolean);
method public void setOnHierarchyChangeListener(android.view.ViewGroup.OnHierarchyChangeListener);
@@ -24199,9 +24461,11 @@
method public void startViewTransition(android.view.View);
method public void updateViewLayout(android.view.View, android.view.ViewGroup.LayoutParams);
field protected static final int CLIP_TO_PADDING_MASK = 34; // 0x22
+ field public static final int COMPONENT_BOUNDS = 0; // 0x0
field public static final int FOCUS_AFTER_DESCENDANTS = 262144; // 0x40000
field public static final int FOCUS_BEFORE_DESCENDANTS = 131072; // 0x20000
field public static final int FOCUS_BLOCK_DESCENDANTS = 393216; // 0x60000
+ field public static final int LAYOUT_BOUNDS = 1; // 0x1
field public static final int PERSISTENT_ALL_CACHES = 3; // 0x3
field public static final int PERSISTENT_ANIMATION_CACHE = 1; // 0x1
field public static final int PERSISTENT_NO_CACHE = 0; // 0x0
@@ -25439,9 +25703,8 @@
method public void close();
method public void getSentenceSuggestions(android.view.textservice.TextInfo[], int);
method public android.view.textservice.SpellCheckerInfo getSpellChecker();
- method public void getSuggestions(android.view.textservice.TextInfo, int);
- method public void getSuggestions(android.view.textservice.TextInfo[], int, boolean);
- method public boolean isSentenceSpellCheckSupported();
+ method public deprecated void getSuggestions(android.view.textservice.TextInfo, int);
+ method public deprecated void getSuggestions(android.view.textservice.TextInfo[], int, boolean);
method public boolean isSessionDisconnected();
field public static final java.lang.String SERVICE_META_DATA = "android.view.textservice.scs";
}
@@ -25549,7 +25812,7 @@
enum_constant public static final android.webkit.ConsoleMessage.MessageLevel WARNING;
}
- public final class CookieManager {
+ public class CookieManager {
method public synchronized boolean acceptCookie();
method public static boolean allowFileSchemeCookies();
method public java.lang.String getCookie(java.lang.String);
@@ -25581,7 +25844,7 @@
method public abstract void onDownloadStart(java.lang.String, java.lang.String, java.lang.String, java.lang.String, long);
}
- public final class GeolocationPermissions {
+ public class GeolocationPermissions {
method public void allow(java.lang.String);
method public void clear(java.lang.String);
method public void clearAll();
@@ -25607,8 +25870,6 @@
public class JsResult {
method public final void cancel();
method public final void confirm();
- method protected final void wakeUp();
- field protected boolean mResult;
}
public class MimeTypeMap {
@@ -25701,7 +25962,7 @@
method public java.lang.String getUrl();
}
- public final class WebIconDatabase {
+ public class WebIconDatabase {
method public void close();
method public static android.webkit.WebIconDatabase getInstance();
method public void open(java.lang.String);
@@ -25870,7 +26131,7 @@
enum_constant public static final android.webkit.WebSettings.ZoomDensity MEDIUM;
}
- public final class WebStorage {
+ public class WebStorage {
method public void deleteAllData();
method public void deleteOrigin(java.lang.String);
method public static android.webkit.WebStorage getInstance();
diff --git a/core/java/android/animation/LayoutTransition.java b/core/java/android/animation/LayoutTransition.java
index 634e4d8..c643137 100644
--- a/core/java/android/animation/LayoutTransition.java
+++ b/core/java/android/animation/LayoutTransition.java
@@ -119,6 +119,24 @@
public static final int DISAPPEARING = 3;
/**
+ * A flag indicating the animation that runs on those items that are changing
+ * due to a layout change not caused by items being added to or removed
+ * from the container. This transition type is not enabled by default; it can be
+ * enabled via {@link #enableTransitionType(int)}.
+ */
+ public static final int CHANGING = 4;
+
+ /**
+ * Private bit fields used to set the collection of enabled transition types for
+ * mTransitionTypes.
+ */
+ private static final int FLAG_APPEARING = 0x01;
+ private static final int FLAG_DISAPPEARING = 0x02;
+ private static final int FLAG_CHANGE_APPEARING = 0x04;
+ private static final int FLAG_CHANGE_DISAPPEARING = 0x08;
+ private static final int FLAG_CHANGING = 0x10;
+
+ /**
* These variables hold the animations that are currently used to run the transition effects.
* These animations are set to defaults, but can be changed to custom animations by
* calls to setAnimator().
@@ -127,11 +145,13 @@
private Animator mAppearingAnim = null;
private Animator mChangingAppearingAnim = null;
private Animator mChangingDisappearingAnim = null;
+ private Animator mChangingAnim = null;
/**
* These are the default animations, defined in the constructor, that will be used
* unless the user specifies custom animations.
*/
+ private static ObjectAnimator defaultChange;
private static ObjectAnimator defaultChangeIn;
private static ObjectAnimator defaultChangeOut;
private static ObjectAnimator defaultFadeIn;
@@ -143,15 +163,16 @@
private static long DEFAULT_DURATION = 300;
/**
- * The durations of the four different animations
+ * The durations of the different animations
*/
private long mChangingAppearingDuration = DEFAULT_DURATION;
private long mChangingDisappearingDuration = DEFAULT_DURATION;
+ private long mChangingDuration = DEFAULT_DURATION;
private long mAppearingDuration = DEFAULT_DURATION;
private long mDisappearingDuration = DEFAULT_DURATION;
/**
- * The start delays of the four different animations. Note that the default behavior of
+ * The start delays of the different animations. Note that the default behavior of
* the appearing item is the default duration, since it should wait for the items to move
* before fading it. Same for the changing animation when disappearing; it waits for the item
* to fade out before moving the other items.
@@ -160,12 +181,14 @@
private long mDisappearingDelay = 0;
private long mChangingAppearingDelay = 0;
private long mChangingDisappearingDelay = DEFAULT_DURATION;
+ private long mChangingDelay = 0;
/**
- * The inter-animation delays used on the two changing animations
+ * The inter-animation delays used on the changing animations
*/
private long mChangingAppearingStagger = 0;
private long mChangingDisappearingStagger = 0;
+ private long mChangingStagger = 0;
/**
* The default interpolators used for the animations
@@ -174,6 +197,7 @@
private TimeInterpolator mDisappearingInterpolator = new AccelerateDecelerateInterpolator();
private TimeInterpolator mChangingAppearingInterpolator = new DecelerateInterpolator();
private TimeInterpolator mChangingDisappearingInterpolator = new DecelerateInterpolator();
+ private TimeInterpolator mChangingInterpolator = new DecelerateInterpolator();
/**
* These hashmaps are used to store the animations that are currently running as part of
@@ -212,6 +236,13 @@
private long staggerDelay;
/**
+ * These are the types of transition animations that the LayoutTransition is reacting
+ * to. By default, appearing/disappearing and the change animations related to them are
+ * enabled (not CHANGING).
+ */
+ private int mTransitionTypes = FLAG_CHANGE_APPEARING | FLAG_CHANGE_DISAPPEARING |
+ FLAG_APPEARING | FLAG_DISAPPEARING;
+ /**
* The set of listeners that should be notified when APPEARING/DISAPPEARING transitions
* start and end.
*/
@@ -248,6 +279,9 @@
defaultChangeOut = defaultChangeIn.clone();
defaultChangeOut.setStartDelay(mChangingDisappearingDelay);
defaultChangeOut.setInterpolator(mChangingDisappearingInterpolator);
+ defaultChange = defaultChangeIn.clone();
+ defaultChange.setStartDelay(mChangingDelay);
+ defaultChange.setInterpolator(mChangingInterpolator);
defaultFadeIn = ObjectAnimator.ofFloat(null, "alpha", 0f, 1f);
defaultFadeIn.setDuration(DEFAULT_DURATION);
@@ -260,6 +294,7 @@
}
mChangingAppearingAnim = defaultChangeIn;
mChangingDisappearingAnim = defaultChangeOut;
+ mChangingAnim = defaultChange;
mAppearingAnim = defaultFadeIn;
mDisappearingAnim = defaultFadeOut;
}
@@ -275,18 +310,101 @@
public void setDuration(long duration) {
mChangingAppearingDuration = duration;
mChangingDisappearingDuration = duration;
+ mChangingDuration = duration;
mAppearingDuration = duration;
mDisappearingDuration = duration;
}
/**
+ * Enables the specified transitionType for this LayoutTransition object.
+ * By default, a LayoutTransition listens for changes in children being
+ * added/remove/hidden/shown in the container, and runs the animations associated with
+ * those events. That is, all transition types besides {@link #CHANGING} are enabled by default.
+ * You can also enable {@link #CHANGING} animations by calling this method with the
+ * {@link #CHANGING} transitionType.
+ *
+ * @param transitionType One of {@link #CHANGE_APPEARING}, {@link #CHANGE_DISAPPEARING},
+ * {@link #CHANGING}, {@link #APPEARING}, or {@link #DISAPPEARING}.
+ */
+ public void enableTransitionType(int transitionType) {
+ switch (transitionType) {
+ case APPEARING:
+ mTransitionTypes |= FLAG_APPEARING;
+ break;
+ case DISAPPEARING:
+ mTransitionTypes |= FLAG_DISAPPEARING;
+ break;
+ case CHANGE_APPEARING:
+ mTransitionTypes |= FLAG_CHANGE_APPEARING;
+ break;
+ case CHANGE_DISAPPEARING:
+ mTransitionTypes |= FLAG_CHANGE_DISAPPEARING;
+ break;
+ case CHANGING:
+ mTransitionTypes |= FLAG_CHANGING;
+ break;
+ }
+ }
+
+ /**
+ * Disables the specified transitionType for this LayoutTransition object.
+ * By default, all transition types except {@link #CHANGING} are enabled.
+ *
+ * @param transitionType One of {@link #CHANGE_APPEARING}, {@link #CHANGE_DISAPPEARING},
+ * {@link #CHANGING}, {@link #APPEARING}, or {@link #DISAPPEARING}.
+ */
+ public void disableTransitionType(int transitionType) {
+ switch (transitionType) {
+ case APPEARING:
+ mTransitionTypes &= ~FLAG_APPEARING;
+ break;
+ case DISAPPEARING:
+ mTransitionTypes &= ~FLAG_DISAPPEARING;
+ break;
+ case CHANGE_APPEARING:
+ mTransitionTypes &= ~FLAG_CHANGE_APPEARING;
+ break;
+ case CHANGE_DISAPPEARING:
+ mTransitionTypes &= ~FLAG_CHANGE_DISAPPEARING;
+ break;
+ case CHANGING:
+ mTransitionTypes &= ~FLAG_CHANGING;
+ break;
+ }
+ }
+
+ /**
+ * Returns whether the specified transitionType is enabled for this LayoutTransition object.
+ * By default, all transition types except {@link #CHANGING} are enabled.
+ *
+ * @param transitionType One of {@link #CHANGE_APPEARING}, {@link #CHANGE_DISAPPEARING},
+ * {@link #CHANGING}, {@link #APPEARING}, or {@link #DISAPPEARING}.
+ * @return true if the specified transitionType is currently enabled, false otherwise.
+ */
+ public boolean isTransitionTypeEnabled(int transitionType) {
+ switch (transitionType) {
+ case APPEARING:
+ return (mTransitionTypes & FLAG_APPEARING) == FLAG_APPEARING;
+ case DISAPPEARING:
+ return (mTransitionTypes & FLAG_DISAPPEARING) == FLAG_DISAPPEARING;
+ case CHANGE_APPEARING:
+ return (mTransitionTypes & FLAG_CHANGE_APPEARING) == FLAG_CHANGE_APPEARING;
+ case CHANGE_DISAPPEARING:
+ return (mTransitionTypes & FLAG_CHANGE_DISAPPEARING) == FLAG_CHANGE_DISAPPEARING;
+ case CHANGING:
+ return (mTransitionTypes & FLAG_CHANGING) == FLAG_CHANGING;
+ }
+ return false;
+ }
+
+ /**
* Sets the start delay on one of the animation objects used by this transition. The
* <code>transitionType</code> parameter determines the animation whose start delay
* is being set.
*
- * @param transitionType one of {@link #CHANGE_APPEARING}, {@link #CHANGE_DISAPPEARING},
- * {@link #APPEARING}, or {@link #DISAPPEARING}, which determines the animation whose start
- * delay is being set.
+ * @param transitionType One of {@link #CHANGE_APPEARING}, {@link #CHANGE_DISAPPEARING},
+ * {@link #CHANGING}, {@link #APPEARING}, or {@link #DISAPPEARING}, which determines
+ * the animation whose start delay is being set.
* @param delay The length of time, in milliseconds, to delay before starting the animation.
* @see Animator#setStartDelay(long)
*/
@@ -298,6 +416,9 @@
case CHANGE_DISAPPEARING:
mChangingDisappearingDelay = delay;
break;
+ case CHANGING:
+ mChangingDelay = delay;
+ break;
case APPEARING:
mAppearingDelay = delay;
break;
@@ -312,9 +433,9 @@
* <code>transitionType</code> parameter determines the animation whose start delay
* is returned.
*
- * @param transitionType one of {@link #CHANGE_APPEARING}, {@link #CHANGE_DISAPPEARING},
- * {@link #APPEARING}, or {@link #DISAPPEARING}, which determines the animation whose start
- * delay is returned.
+ * @param transitionType One of {@link #CHANGE_APPEARING}, {@link #CHANGE_DISAPPEARING},
+ * {@link #CHANGING}, {@link #APPEARING}, or {@link #DISAPPEARING}, which determines
+ * the animation whose start delay is returned.
* @return long The start delay of the specified animation.
* @see Animator#getStartDelay()
*/
@@ -324,6 +445,8 @@
return mChangingAppearingDelay;
case CHANGE_DISAPPEARING:
return mChangingDisappearingDelay;
+ case CHANGING:
+ return mChangingDelay;
case APPEARING:
return mAppearingDelay;
case DISAPPEARING:
@@ -338,9 +461,9 @@
* <code>transitionType</code> parameter determines the animation whose duration
* is being set.
*
- * @param transitionType one of {@link #CHANGE_APPEARING}, {@link #CHANGE_DISAPPEARING},
- * {@link #APPEARING}, or {@link #DISAPPEARING}, which determines the animation whose
- * duration is being set.
+ * @param transitionType One of {@link #CHANGE_APPEARING}, {@link #CHANGE_DISAPPEARING},
+ * {@link #CHANGING}, {@link #APPEARING}, or {@link #DISAPPEARING}, which determines
+ * the animation whose duration is being set.
* @param duration The length of time, in milliseconds, that the specified animation should run.
* @see Animator#setDuration(long)
*/
@@ -352,6 +475,9 @@
case CHANGE_DISAPPEARING:
mChangingDisappearingDuration = duration;
break;
+ case CHANGING:
+ mChangingDuration = duration;
+ break;
case APPEARING:
mAppearingDuration = duration;
break;
@@ -366,9 +492,9 @@
* <code>transitionType</code> parameter determines the animation whose duration
* is returned.
*
- * @param transitionType one of {@link #CHANGE_APPEARING}, {@link #CHANGE_DISAPPEARING},
- * {@link #APPEARING}, or {@link #DISAPPEARING}, which determines the animation whose
- * duration is returned.
+ * @param transitionType One of {@link #CHANGE_APPEARING}, {@link #CHANGE_DISAPPEARING},
+ * {@link #CHANGING}, {@link #APPEARING}, or {@link #DISAPPEARING}, which determines
+ * the animation whose duration is returned.
* @return long The duration of the specified animation.
* @see Animator#getDuration()
*/
@@ -378,6 +504,8 @@
return mChangingAppearingDuration;
case CHANGE_DISAPPEARING:
return mChangingDisappearingDuration;
+ case CHANGING:
+ return mChangingDuration;
case APPEARING:
return mAppearingDuration;
case DISAPPEARING:
@@ -389,9 +517,10 @@
/**
* Sets the length of time to delay between starting each animation during one of the
- * CHANGE animations.
+ * change animations.
*
- * @param transitionType A value of {@link #CHANGE_APPEARING} or @link #CHANGE_DISAPPEARING}.
+ * @param transitionType A value of {@link #CHANGE_APPEARING}, {@link #CHANGE_DISAPPEARING}, or
+ * {@link #CHANGING}.
* @param duration The length of time, in milliseconds, to delay before launching the next
* animation in the sequence.
*/
@@ -403,15 +532,19 @@
case CHANGE_DISAPPEARING:
mChangingDisappearingStagger = duration;
break;
+ case CHANGING:
+ mChangingStagger = duration;
+ break;
// noop other cases
}
}
/**
- * Tets the length of time to delay between starting each animation during one of the
- * CHANGE animations.
+ * Gets the length of time to delay between starting each animation during one of the
+ * change animations.
*
- * @param transitionType A value of {@link #CHANGE_APPEARING} or @link #CHANGE_DISAPPEARING}.
+ * @param transitionType A value of {@link #CHANGE_APPEARING}, {@link #CHANGE_DISAPPEARING}, or
+ * {@link #CHANGING}.
* @return long The length of time, in milliseconds, to delay before launching the next
* animation in the sequence.
*/
@@ -421,6 +554,8 @@
return mChangingAppearingStagger;
case CHANGE_DISAPPEARING:
return mChangingDisappearingStagger;
+ case CHANGING:
+ return mChangingStagger;
}
// shouldn't reach here
return 0;
@@ -431,9 +566,9 @@
* <code>transitionType</code> parameter determines the animation whose interpolator
* is being set.
*
- * @param transitionType one of {@link #CHANGE_APPEARING}, {@link #CHANGE_DISAPPEARING},
- * {@link #APPEARING}, or {@link #DISAPPEARING}, which determines the animation whose
- * duration is being set.
+ * @param transitionType One of {@link #CHANGE_APPEARING}, {@link #CHANGE_DISAPPEARING},
+ * {@link #CHANGING}, {@link #APPEARING}, or {@link #DISAPPEARING}, which determines
+ * the animation whose interpolator is being set.
* @param interpolator The interpolator that the specified animation should use.
* @see Animator#setInterpolator(TimeInterpolator)
*/
@@ -445,6 +580,9 @@
case CHANGE_DISAPPEARING:
mChangingDisappearingInterpolator = interpolator;
break;
+ case CHANGING:
+ mChangingInterpolator = interpolator;
+ break;
case APPEARING:
mAppearingInterpolator = interpolator;
break;
@@ -459,9 +597,9 @@
* <code>transitionType</code> parameter determines the animation whose interpolator
* is returned.
*
- * @param transitionType one of {@link #CHANGE_APPEARING}, {@link #CHANGE_DISAPPEARING},
- * {@link #APPEARING}, or {@link #DISAPPEARING}, which determines the animation whose
- * duration is being set.
+ * @param transitionType One of {@link #CHANGE_APPEARING}, {@link #CHANGE_DISAPPEARING},
+ * {@link #CHANGING}, {@link #APPEARING}, or {@link #DISAPPEARING}, which determines
+ * the animation whose interpolator is being returned.
* @return TimeInterpolator The interpolator that the specified animation uses.
* @see Animator#setInterpolator(TimeInterpolator)
*/
@@ -471,6 +609,8 @@
return mChangingAppearingInterpolator;
case CHANGE_DISAPPEARING:
return mChangingDisappearingInterpolator;
+ case CHANGING:
+ return mChangingInterpolator;
case APPEARING:
return mAppearingInterpolator;
case DISAPPEARING:
@@ -504,9 +644,9 @@
* values queried when the transition begins may need to use a different mechanism
* than a standard ObjectAnimator object.</p>
*
- * @param transitionType one of {@link #CHANGE_APPEARING}, {@link #CHANGE_DISAPPEARING},
- * {@link #APPEARING}, or {@link #DISAPPEARING}, which determines the animation whose
- * duration is being set.
+ * @param transitionType One of {@link #CHANGE_APPEARING}, {@link #CHANGE_DISAPPEARING},
+ * {@link #CHANGING}, {@link #APPEARING}, or {@link #DISAPPEARING}, which determines the
+ * animation whose animator is being set.
* @param animator The animation being assigned. A value of <code>null</code> means that no
* animation will be run for the specified transitionType.
*/
@@ -518,6 +658,9 @@
case CHANGE_DISAPPEARING:
mChangingDisappearingAnim = animator;
break;
+ case CHANGING:
+ mChangingAnim = animator;
+ break;
case APPEARING:
mAppearingAnim = animator;
break;
@@ -530,9 +673,9 @@
/**
* Gets the animation used during one of the transition types that may run.
*
- * @param transitionType one of {@link #CHANGE_APPEARING}, {@link #CHANGE_DISAPPEARING},
- * {@link #APPEARING}, or {@link #DISAPPEARING}, which determines the animation whose
- * duration is being set.
+ * @param transitionType One of {@link #CHANGE_APPEARING}, {@link #CHANGE_DISAPPEARING},
+ * {@link #CHANGING}, {@link #APPEARING}, or {@link #DISAPPEARING}, which determines
+ * the animation whose animator is being returned.
* @return Animator The animation being used for the given transition type.
* @see #setAnimator(int, Animator)
*/
@@ -542,6 +685,8 @@
return mChangingAppearingAnim;
case CHANGE_DISAPPEARING:
return mChangingDisappearingAnim;
+ case CHANGING:
+ return mChangingAnim;
case APPEARING:
return mAppearingAnim;
case DISAPPEARING:
@@ -554,20 +699,44 @@
/**
* This function sets up animations on all of the views that change during layout.
* For every child in the parent, we create a change animation of the appropriate
- * type (appearing or disappearing) and ask it to populate its start values from its
+ * type (appearing, disappearing, or changing) and ask it to populate its start values from its
* target view. We add layout listeners to all child views and listen for changes. For
* those views that change, we populate the end values for those animations and start them.
* Animations are not run on unchanging views.
*
- * @param parent The container which is undergoing an appearing or disappearing change.
- * @param newView The view being added to or removed from the parent.
- * @param changeReason A value of APPEARING or DISAPPEARING, indicating whether the
- * transition is occuring because an item is being added to or removed from the parent.
+ * @param parent The container which is undergoing a change.
+ * @param newView The view being added to or removed from the parent. May be null if the
+ * changeReason is CHANGING.
+ * @param changeReason A value of APPEARING, DISAPPEARING, or CHANGING, indicating whether the
+ * transition is occurring because an item is being added to or removed from the parent, or
+ * if it is running in response to a layout operation (that is, if the value is CHANGING).
*/
private void runChangeTransition(final ViewGroup parent, View newView, final int changeReason) {
- Animator baseAnimator = (changeReason == APPEARING) ?
- mChangingAppearingAnim : mChangingDisappearingAnim;
+ Animator baseAnimator = null;
+ Animator parentAnimator = null;
+ final long duration;
+ switch (changeReason) {
+ case APPEARING:
+ baseAnimator = mChangingAppearingAnim;
+ duration = mChangingAppearingDuration;
+ parentAnimator = defaultChangeIn;
+ break;
+ case DISAPPEARING:
+ baseAnimator = mChangingDisappearingAnim;
+ duration = mChangingDisappearingDuration;
+ parentAnimator = defaultChangeOut;
+ break;
+ case CHANGING:
+ baseAnimator = mChangingAnim;
+ duration = mChangingDuration;
+ parentAnimator = defaultChange;
+ break;
+ default:
+ // Shouldn't reach here
+ duration = 0;
+ break;
+ }
// If the animation is null, there's nothing to do
if (baseAnimator == null) {
return;
@@ -575,8 +744,6 @@
// reset the inter-animation delay, in case we use it later
staggerDelay = 0;
- final long duration = (changeReason == APPEARING) ?
- mChangingAppearingDuration : mChangingDisappearingDuration;
final ViewTreeObserver observer = parent.getViewTreeObserver(); // used for later cleanup
if (!observer.isAlive()) {
@@ -594,8 +761,6 @@
}
}
if (mAnimateParentHierarchy) {
- Animator parentAnimator = (changeReason == APPEARING) ?
- defaultChangeIn : defaultChangeOut;
ViewGroup tempParent = parent;
while (tempParent != null) {
ViewParent parentParent = tempParent.getParent();
@@ -727,13 +892,20 @@
}
}
- long startDelay;
- if (changeReason == APPEARING) {
- startDelay = mChangingAppearingDelay + staggerDelay;
- staggerDelay += mChangingAppearingStagger;
- } else {
- startDelay = mChangingDisappearingDelay + staggerDelay;
- staggerDelay += mChangingDisappearingStagger;
+ long startDelay = 0;
+ switch (changeReason) {
+ case APPEARING:
+ startDelay = mChangingAppearingDelay + staggerDelay;
+ staggerDelay += mChangingAppearingStagger;
+ break;
+ case DISAPPEARING:
+ startDelay = mChangingDisappearingDelay + staggerDelay;
+ staggerDelay += mChangingDisappearingStagger;
+ break;
+ case CHANGING:
+ startDelay = mChangingDelay + staggerDelay;
+ staggerDelay += mChangingStagger;
+ break;
}
anim.setStartDelay(startDelay);
anim.setDuration(duration);
@@ -766,7 +938,8 @@
for (TransitionListener listener : mListeners) {
listener.startTransition(LayoutTransition.this, parent, child,
changeReason == APPEARING ?
- CHANGE_APPEARING : CHANGE_DISAPPEARING);
+ CHANGE_APPEARING : changeReason == DISAPPEARING ?
+ CHANGE_DISAPPEARING : CHANGING);
}
}
}
@@ -784,7 +957,8 @@
for (TransitionListener listener : mListeners) {
listener.endTransition(LayoutTransition.this, parent, child,
changeReason == APPEARING ?
- CHANGE_APPEARING : CHANGE_DISAPPEARING);
+ CHANGE_APPEARING : changeReason == DISAPPEARING ?
+ CHANGE_DISAPPEARING : CHANGING);
}
}
}
@@ -831,6 +1005,8 @@
anim.start();
anim.end();
}
+ // listeners should clean up the currentChangingAnimations list, but just in case...
+ currentChangingAnimations.clear();
}
/**
@@ -902,6 +1078,7 @@
switch (transitionType) {
case CHANGE_APPEARING:
case CHANGE_DISAPPEARING:
+ case CHANGING:
if (currentChangingAnimations.size() > 0) {
LinkedHashMap<View, Animator> currentAnimCopy =
(LinkedHashMap<View, Animator>) currentChangingAnimations.clone();
@@ -1031,21 +1208,48 @@
* affect CHANGE_APPEARING or CHANGE_DISAPPEARING animations.
*/
private void addChild(ViewGroup parent, View child, boolean changesLayout) {
- // Want disappearing animations to finish up before proceeding
- cancel(DISAPPEARING);
- if (changesLayout) {
+ if ((mTransitionTypes & FLAG_APPEARING) == FLAG_APPEARING) {
+ // Want disappearing animations to finish up before proceeding
+ cancel(DISAPPEARING);
+ }
+ if (changesLayout && (mTransitionTypes & FLAG_CHANGE_APPEARING) == FLAG_CHANGE_APPEARING) {
// Also, cancel changing animations so that we start fresh ones from current locations
cancel(CHANGE_APPEARING);
+ cancel(CHANGING);
}
- if (mListeners != null) {
+ if (mListeners != null && (mTransitionTypes & FLAG_APPEARING) == FLAG_APPEARING) {
for (TransitionListener listener : mListeners) {
listener.startTransition(this, parent, child, APPEARING);
}
}
- if (changesLayout) {
+ if (changesLayout && (mTransitionTypes & FLAG_CHANGE_APPEARING) == FLAG_CHANGE_APPEARING) {
runChangeTransition(parent, child, APPEARING);
}
- runAppearingTransition(parent, child);
+ if ((mTransitionTypes & FLAG_APPEARING) == FLAG_APPEARING) {
+ runAppearingTransition(parent, child);
+ }
+ }
+
+ /**
+ * This method is called by ViewGroup when there is a call to layout() on the container
+ * with this LayoutTransition. If the CHANGING transition is enabled and if there is no other
+ * transition currently running on the container, then this call runs a CHANGING transition.
+ * The transition does not start immediately; it just sets up the mechanism to run if any
+ * of the children of the container change their layout parameters (similar to
+ * the CHANGE_APPEARING and CHANGE_DISAPPEARING transitions).
+ *
+ * @param parent The ViewGroup whose layout() method has been called.
+ *
+ * @hide
+ */
+ public void layoutChange(ViewGroup parent) {
+ if ((mTransitionTypes & FLAG_CHANGING) == FLAG_CHANGING && !isRunning()) {
+ // This method is called for all calls to layout() in the container, including
+ // those caused by add/remove/hide/show events, which will already have set up
+ // transition animations. Avoid setting up CHANGING animations in this case; only
+ // do so when there is not a transition already running on the container.
+ runChangeTransition(parent, null, CHANGING);
+ }
}
/**
@@ -1097,21 +1301,28 @@
* affect CHANGE_APPEARING or CHANGE_DISAPPEARING animations.
*/
private void removeChild(ViewGroup parent, View child, boolean changesLayout) {
- // Want appearing animations to finish up before proceeding
- cancel(APPEARING);
- if (changesLayout) {
+ if ((mTransitionTypes & FLAG_DISAPPEARING) == FLAG_DISAPPEARING) {
+ // Want appearing animations to finish up before proceeding
+ cancel(APPEARING);
+ }
+ if (changesLayout &&
+ (mTransitionTypes & FLAG_CHANGE_DISAPPEARING) == FLAG_CHANGE_DISAPPEARING) {
// Also, cancel changing animations so that we start fresh ones from current locations
cancel(CHANGE_DISAPPEARING);
+ cancel(CHANGING);
}
- if (mListeners != null) {
+ if (mListeners != null && (mTransitionTypes & FLAG_DISAPPEARING) == FLAG_DISAPPEARING) {
for (TransitionListener listener : mListeners) {
listener.startTransition(this, parent, child, DISAPPEARING);
}
}
- if (changesLayout) {
+ if (changesLayout &&
+ (mTransitionTypes & FLAG_CHANGE_DISAPPEARING) == FLAG_CHANGE_DISAPPEARING) {
runChangeTransition(parent, child, DISAPPEARING);
}
- runDisappearingTransition(parent, child);
+ if ((mTransitionTypes & FLAG_DISAPPEARING) == FLAG_DISAPPEARING) {
+ runDisappearingTransition(parent, child);
+ }
}
/**
diff --git a/core/java/android/animation/ValueAnimator.java b/core/java/android/animation/ValueAnimator.java
index fade20c..2154b14 100755
--- a/core/java/android/animation/ValueAnimator.java
+++ b/core/java/android/animation/ValueAnimator.java
@@ -150,6 +150,13 @@
private boolean mStarted = false;
/**
+ * Tracks whether we've notified listeners of the onAnimationSTart() event. This can be
+ * complex to keep track of since we notify listeners at different times depending on
+ * startDelay and whether start() was called before end().
+ */
+ private boolean mStartListenersCalled = false;
+
+ /**
* Flag that denotes whether the animation is set up and ready to go. Used to
* set up animation that has not yet been started.
*/
@@ -885,6 +892,18 @@
}
}
+ private void notifyStartListeners() {
+ if (mListeners != null && !mStartListenersCalled) {
+ ArrayList<AnimatorListener> tmpListeners =
+ (ArrayList<AnimatorListener>) mListeners.clone();
+ int numListeners = tmpListeners.size();
+ for (int i = 0; i < numListeners; ++i) {
+ tmpListeners.get(i).onAnimationStart(this);
+ }
+ }
+ mStartListenersCalled = true;
+ }
+
/**
* Start the animation playing. This version of start() takes a boolean flag that indicates
* whether the animation should play in reverse. The flag is usually false, but may be set
@@ -914,15 +933,7 @@
setCurrentPlayTime(getCurrentPlayTime());
mPlayingState = STOPPED;
mRunning = true;
-
- if (mListeners != null) {
- ArrayList<AnimatorListener> tmpListeners =
- (ArrayList<AnimatorListener>) mListeners.clone();
- int numListeners = tmpListeners.size();
- for (int i = 0; i < numListeners; ++i) {
- tmpListeners.get(i).onAnimationStart(this);
- }
- }
+ notifyStartListeners();
}
animationHandler.sendEmptyMessage(ANIMATION_START);
}
@@ -941,7 +952,11 @@
|| handler.mPendingAnimations.contains(this)
|| handler.mDelayedAnims.contains(this)) {
// Only notify listeners if the animator has actually started
- if (mRunning && mListeners != null) {
+ if ((mStarted || mRunning) && mListeners != null) {
+ if (!mRunning) {
+ // If it's not yet running, then start listeners weren't called. Call them now.
+ notifyStartListeners();
+ }
ArrayList<AnimatorListener> tmpListeners =
(ArrayList<AnimatorListener>) mListeners.clone();
for (AnimatorListener listener : tmpListeners) {
@@ -959,6 +974,7 @@
// Special case if the animation has not yet started; get it ready for ending
mStartedDelay = false;
startAnimation(handler);
+ mStarted = true;
} else if (!mInitialized) {
initAnimation();
}
@@ -1010,7 +1026,11 @@
handler.mPendingAnimations.remove(this);
handler.mDelayedAnims.remove(this);
mPlayingState = STOPPED;
- if (mRunning && mListeners != null) {
+ if ((mStarted || mRunning) && mListeners != null) {
+ if (!mRunning) {
+ // If it's not yet running, then start listeners weren't called. Call them now.
+ notifyStartListeners();
+ }
ArrayList<AnimatorListener> tmpListeners =
(ArrayList<AnimatorListener>) mListeners.clone();
int numListeners = tmpListeners.size();
@@ -1020,6 +1040,7 @@
}
mRunning = false;
mStarted = false;
+ mStartListenersCalled = false;
}
/**
@@ -1032,12 +1053,7 @@
if (mStartDelay > 0 && mListeners != null) {
// Listeners were already notified in start() if startDelay is 0; this is
// just for delayed animations
- ArrayList<AnimatorListener> tmpListeners =
- (ArrayList<AnimatorListener>) mListeners.clone();
- int numListeners = tmpListeners.size();
- for (int i = 0; i < numListeners; ++i) {
- tmpListeners.get(i).onAnimationStart(this);
- }
+ notifyStartListeners();
}
}
diff --git a/core/java/android/app/ActivityOptions.java b/core/java/android/app/ActivityOptions.java
index c3cceaf..423b02a 100644
--- a/core/java/android/app/ActivityOptions.java
+++ b/core/java/android/app/ActivityOptions.java
@@ -73,6 +73,18 @@
public static final String KEY_ANIM_START_Y = "android:animStartY";
/**
+ * Initial width of the animation.
+ * @hide
+ */
+ public static final String KEY_ANIM_START_WIDTH = "android:animStartWidth";
+
+ /**
+ * Initial height of the animation.
+ * @hide
+ */
+ public static final String KEY_ANIM_START_HEIGHT = "android:animStartHeight";
+
+ /**
* Callback for when animation is started.
* @hide
*/
@@ -83,7 +95,9 @@
/** @hide */
public static final int ANIM_CUSTOM = 1;
/** @hide */
- public static final int ANIM_THUMBNAIL = 2;
+ public static final int ANIM_SCALE_UP = 2;
+ /** @hide */
+ public static final int ANIM_THUMBNAIL = 3;
private String mPackageName;
private int mAnimationType = ANIM_NONE;
@@ -92,6 +106,8 @@
private Bitmap mThumbnail;
private int mStartX;
private int mStartY;
+ private int mStartWidth;
+ private int mStartHeight;
private IRemoteCallback mAnimationStartedListener;
/**
@@ -127,6 +143,34 @@
}
/**
+ * Create an ActivityOptions specifying an animation where the new
+ * activity is scaled from a small originating area of the screen to
+ * its final full representation.
+ *
+ * @param source The View that the new activity is animating from. This
+ * defines the coordinate space for <var>startX</var> and <var>startY</var>.
+ * @param startX The x starting location of the new activity, relative to <var>source</var>.
+ * @param startY The y starting location of the activity, relative to <var>source</var>.
+ * @param startWidth The initial width of the new activity.
+ * @param startWidth The initial height of the new activity.
+ * @return Returns a new ActivityOptions object that you can use to
+ * supply these options as the options Bundle when starting an activity.
+ */
+ public static ActivityOptions makeScaleUpAnimation(View source,
+ int startX, int startY, int startWidth, int startHeight) {
+ ActivityOptions opts = new ActivityOptions();
+ opts.mPackageName = source.getContext().getPackageName();
+ opts.mAnimationType = ANIM_SCALE_UP;
+ int[] pts = new int[2];
+ source.getLocationOnScreen(pts);
+ opts.mStartX = pts[0] + startX;
+ opts.mStartY = pts[1] + startY;
+ opts.mStartWidth = startWidth;
+ opts.mStartHeight = startHeight;
+ return opts;
+ }
+
+ /**
* Create an ActivityOptions specifying an animation where a thumbnail
* is scaled from a given position to the new activity window that is
* being started.
@@ -135,8 +179,8 @@
* defines the coordinate space for <var>startX</var> and <var>startY</var>.
* @param thumbnail The bitmap that will be shown as the initial thumbnail
* of the animation.
- * @param startX The x starting location of the bitmap, in screen coordiantes.
- * @param startY The y starting location of the bitmap, in screen coordinates.
+ * @param startX The x starting location of the bitmap, relative to <var>source</var>.
+ * @param startY The y starting location of the bitmap, relative to <var>source</var>.
* @return Returns a new ActivityOptions object that you can use to
* supply these options as the options Bundle when starting an activity.
*/
@@ -154,8 +198,8 @@
* defines the coordinate space for <var>startX</var> and <var>startY</var>.
* @param thumbnail The bitmap that will be shown as the initial thumbnail
* of the animation.
- * @param startX The x starting location of the bitmap, in screen coordiantes.
- * @param startY The y starting location of the bitmap, in screen coordinates.
+ * @param startX The x starting location of the bitmap, relative to <var>source</var>.
+ * @param startY The y starting location of the bitmap, relative to <var>source</var>.
* @param listener Optional OnAnimationStartedListener to find out when the
* requested animation has started running. If for some reason the animation
* is not executed, the callback will happen immediately.
@@ -199,6 +243,11 @@
if (mAnimationType == ANIM_CUSTOM) {
mCustomEnterResId = opts.getInt(KEY_ANIM_ENTER_RES_ID, 0);
mCustomExitResId = opts.getInt(KEY_ANIM_EXIT_RES_ID, 0);
+ } else if (mAnimationType == ANIM_SCALE_UP) {
+ mStartX = opts.getInt(KEY_ANIM_START_X, 0);
+ mStartY = opts.getInt(KEY_ANIM_START_Y, 0);
+ mStartWidth = opts.getInt(KEY_ANIM_START_WIDTH, 0);
+ mStartHeight = opts.getInt(KEY_ANIM_START_HEIGHT, 0);
} else if (mAnimationType == ANIM_THUMBNAIL) {
mThumbnail = (Bitmap)opts.getParcelable(KEY_ANIM_THUMBNAIL);
mStartX = opts.getInt(KEY_ANIM_START_X, 0);
@@ -244,6 +293,16 @@
}
/** @hide */
+ public int getStartWidth() {
+ return mStartWidth;
+ }
+
+ /** @hide */
+ public int getStartHeight() {
+ return mStartHeight;
+ }
+
+ /** @hide */
public IRemoteCallback getOnAnimationStartListener() {
return mAnimationStartedListener;
}
@@ -281,6 +340,13 @@
mThumbnail = null;
mAnimationStartedListener = null;
break;
+ case ANIM_SCALE_UP:
+ mAnimationType = otherOptions.mAnimationType;
+ mStartX = otherOptions.mStartX;
+ mStartY = otherOptions.mStartY;
+ mStartWidth = otherOptions.mStartWidth;
+ mStartHeight = otherOptions.mStartHeight;
+ break;
case ANIM_THUMBNAIL:
mAnimationType = otherOptions.mAnimationType;
mThumbnail = otherOptions.mThumbnail;
@@ -316,6 +382,13 @@
b.putInt(KEY_ANIM_ENTER_RES_ID, mCustomEnterResId);
b.putInt(KEY_ANIM_EXIT_RES_ID, mCustomExitResId);
break;
+ case ANIM_SCALE_UP:
+ b.putInt(KEY_ANIM_TYPE, mAnimationType);
+ b.putInt(KEY_ANIM_START_X, mStartX);
+ b.putInt(KEY_ANIM_START_Y, mStartY);
+ b.putInt(KEY_ANIM_START_WIDTH, mStartWidth);
+ b.putInt(KEY_ANIM_START_HEIGHT, mStartHeight);
+ break;
case ANIM_THUMBNAIL:
b.putInt(KEY_ANIM_TYPE, mAnimationType);
b.putParcelable(KEY_ANIM_THUMBNAIL, mThumbnail);
@@ -323,6 +396,7 @@
b.putInt(KEY_ANIM_START_Y, mStartY);
b.putIBinder(KEY_ANIM_START_LISTENER, mAnimationStartedListener
!= null ? mAnimationStartedListener.asBinder() : null);
+ break;
}
return b;
}
diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java
index 0645aa9..8942135 100644
--- a/core/java/android/app/ContextImpl.java
+++ b/core/java/android/app/ContextImpl.java
@@ -45,6 +45,7 @@
import android.hardware.ISerialManager;
import android.hardware.SensorManager;
import android.hardware.SerialManager;
+import android.hardware.SystemSensorManager;
import android.hardware.input.IInputManager;
import android.hardware.input.InputManager;
import android.hardware.usb.IUsbManager;
@@ -407,7 +408,7 @@
registerService(SENSOR_SERVICE, new ServiceFetcher() {
public Object createService(ContextImpl ctx) {
- return new SensorManager(ctx.mMainThread.getHandler().getLooper());
+ return new SystemSensorManager(ctx.mMainThread.getHandler().getLooper());
}});
registerService(STATUS_BAR_SERVICE, new ServiceFetcher() {
diff --git a/core/java/android/app/DownloadManager.java b/core/java/android/app/DownloadManager.java
index dd58397..0713127 100644
--- a/core/java/android/app/DownloadManager.java
+++ b/core/java/android/app/DownloadManager.java
@@ -347,8 +347,9 @@
private CharSequence mTitle;
private CharSequence mDescription;
private String mMimeType;
- private boolean mRoamingAllowed = true;
private int mAllowedNetworkTypes = ~0; // default to all network types allowed
+ private boolean mRoamingAllowed = true;
+ private boolean mMeteredAllowed = true;
private boolean mIsVisibleInDownloadsUi = true;
private boolean mScannable = false;
private boolean mUseSystemCache = false;
@@ -609,8 +610,11 @@
}
/**
- * Restrict the types of networks over which this download may proceed. By default, all
- * network types are allowed.
+ * Restrict the types of networks over which this download may proceed.
+ * By default, all network types are allowed. Consider using
+ * {@link #setAllowedOverMetered(boolean)} instead, since it's more
+ * flexible.
+ *
* @param flags any combination of the NETWORK_* bit flags.
* @return this object
*/
@@ -631,6 +635,17 @@
}
/**
+ * Set whether this download may proceed over a metered network
+ * connection. By default, metered networks are allowed.
+ *
+ * @see ConnectivityManager#isActiveNetworkMetered()
+ */
+ public Request setAllowedOverMetered(boolean allow) {
+ mMeteredAllowed = allow;
+ return this;
+ }
+
+ /**
* Set whether this download should be displayed in the system's Downloads UI. True by
* default.
* @param isVisible whether to display this download in the Downloads UI
@@ -675,6 +690,7 @@
values.put(Downloads.Impl.COLUMN_VISIBILITY, mNotificationVisibility);
values.put(Downloads.Impl.COLUMN_ALLOWED_NETWORK_TYPES, mAllowedNetworkTypes);
values.put(Downloads.Impl.COLUMN_ALLOW_ROAMING, mRoamingAllowed);
+ values.put(Downloads.Impl.COLUMN_ALLOW_METERED, mMeteredAllowed);
values.put(Downloads.Impl.COLUMN_IS_VISIBLE_IN_DOWNLOADS_UI, mIsVisibleInDownloadsUi);
return values;
@@ -1324,9 +1340,6 @@
case Downloads.Impl.STATUS_FILE_ALREADY_EXISTS_ERROR:
return ERROR_FILE_ALREADY_EXISTS;
- case Downloads.Impl.STATUS_BLOCKED:
- return ERROR_BLOCKED;
-
default:
return ERROR_UNKNOWN;
}
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index 5cce25f..22d84f0 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -1681,7 +1681,7 @@
}
private RemoteViews makeBigContentView() {
- RemoteViews contentView = mBuilder.applyStandardTemplateWithActions(R.layout.notification_template_base);
+ RemoteViews contentView = mBuilder.applyStandardTemplateWithActions(R.layout.notification_template_big_text);
contentView.setTextViewText(R.id.big_text, mBigText);
contentView.setViewVisibility(R.id.big_text, View.VISIBLE);
@@ -1696,4 +1696,60 @@
return wip;
}
}
+
+ /**
+ * Helper class for generating large-format notifications that include a list of (up to 5) strings.
+ *
+ * This class is a "rebuilder": It consumes a Builder object and modifies its behavior, like so:
+ * <pre class="prettyprint">
+ * Notification noti = new Notification.DigestStyle(
+ * new Notification.Builder()
+ * .setContentTitle("New mail from " + sender.toString())
+ * .setContentText(subject)
+ * .setSmallIcon(R.drawable.new_mail)
+ * .setLargeIcon(aBitmap))
+ * .addLine(str1)
+ * .addLine(str2)
+ * .build();
+ * </pre>
+ *
+ * @see Notification#bigContentView
+ */
+ public static class InboxStyle {
+ private Builder mBuilder;
+ private ArrayList<CharSequence> mTexts = new ArrayList<CharSequence>(5);
+
+ public InboxStyle(Builder builder) {
+ mBuilder = builder;
+ }
+
+ public InboxStyle addLine(CharSequence cs) {
+ mTexts.add(cs);
+ return this;
+ }
+
+ private RemoteViews makeBigContentView() {
+ RemoteViews contentView = mBuilder.applyStandardTemplateWithActions(R.layout.notification_template_inbox);
+
+ int[] rowIds = {R.id.inbox_text0, R.id.inbox_text1, R.id.inbox_text2, R.id.inbox_text3, R.id.inbox_text4};
+
+ int i=0;
+ while (i < mTexts.size() && i < rowIds.length) {
+ CharSequence str = mTexts.get(i);
+ if (str != null && !str.equals("")) {
+ contentView.setViewVisibility(rowIds[i], View.VISIBLE);
+ contentView.setTextViewText(rowIds[i], str);
+ }
+ i++;
+ }
+
+ return contentView;
+ }
+
+ public Notification build() {
+ Notification wip = mBuilder.getNotification();
+ wip.bigContentView = makeBigContentView();
+ return wip;
+ }
+ }
}
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index 19e4372..6653336 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -6576,35 +6576,54 @@
final String action = getAction();
if (ACTION_SEND.equals(action)) {
- final Uri stream;
+ Uri stream = null;
try {
stream = getParcelableExtra(EXTRA_STREAM);
} catch (ClassCastException e) {
- return;
}
- if (stream != null) {
+ final CharSequence text = getCharSequenceExtra(EXTRA_TEXT);
+ final String htmlText = getStringExtra(EXTRA_HTML_TEXT);
+ if (stream != null || text != null || htmlText != null) {
final ClipData clipData = new ClipData(
- null, new String[] { getType() }, new ClipData.Item(stream));
-
+ null, new String[] { getType() },
+ new ClipData.Item(text, htmlText, null, stream));
setClipData(clipData);
addFlags(FLAG_GRANT_READ_URI_PERMISSION);
}
} else if (ACTION_SEND_MULTIPLE.equals(action)) {
- final ArrayList<Uri> streams;
+ ArrayList<Uri> streams = null;
try {
streams = getParcelableArrayListExtra(EXTRA_STREAM);
} catch (ClassCastException e) {
- return;
}
- if (streams != null && streams.size() > 0) {
- final Uri firstStream = streams.get(0);
+ final ArrayList<CharSequence> texts = getCharSequenceArrayListExtra(EXTRA_TEXT);
+ final ArrayList<String> htmlTexts = getStringArrayListExtra(EXTRA_HTML_TEXT);
+ int num = -1;
+ if (streams != null) {
+ num = streams.size();
+ }
+ if (texts != null) {
+ if (num >= 0 && num != texts.size()) {
+ // Wha...! F- you.
+ return;
+ }
+ num = texts.size();
+ }
+ if (htmlTexts != null) {
+ if (num >= 0 && num != htmlTexts.size()) {
+ // Wha...! F- you.
+ return;
+ }
+ num = htmlTexts.size();
+ }
+ if (num > 0) {
final ClipData clipData = new ClipData(
- null, new String[] { getType() }, new ClipData.Item(firstStream));
+ null, new String[] { getType() },
+ makeClipItem(streams, texts, htmlTexts, 0));
- final int size = streams.size();
- for (int i = 1; i < size; i++) {
- clipData.addItem(new ClipData.Item(streams.get(i)));
+ for (int i = 1; i < num; i++) {
+ clipData.addItem(makeClipItem(streams, texts, htmlTexts, i));
}
setClipData(clipData);
@@ -6612,4 +6631,12 @@
}
}
}
+
+ private static ClipData.Item makeClipItem(ArrayList<Uri> streams, ArrayList<CharSequence> texts,
+ ArrayList<String> htmlTexts, int which) {
+ Uri uri = streams != null ? streams.get(which) : null;
+ CharSequence text = texts != null ? texts.get(which) : null;
+ String htmlText = htmlTexts != null ? htmlTexts.get(which) : null;
+ return new ClipData.Item(text, htmlText, null, uri);
+ }
}
diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java
index b6ebbdf..185fcb9 100644
--- a/core/java/android/content/pm/PackageParser.java
+++ b/core/java/android/content/pm/PackageParser.java
@@ -3458,9 +3458,9 @@
ai.disableCompatibilityMode();
}
if (stopped) {
- p.applicationInfo.flags |= ApplicationInfo.FLAG_STOPPED;
+ ai.flags |= ApplicationInfo.FLAG_STOPPED;
} else {
- p.applicationInfo.flags &= ~ApplicationInfo.FLAG_STOPPED;
+ ai.flags &= ~ApplicationInfo.FLAG_STOPPED;
}
if (enabledState == PackageManager.COMPONENT_ENABLED_STATE_ENABLED) {
ai.enabled = true;
diff --git a/core/java/android/database/sqlite/SQLiteConnection.java b/core/java/android/database/sqlite/SQLiteConnection.java
index 254f652..04f6377 100644
--- a/core/java/android/database/sqlite/SQLiteConnection.java
+++ b/core/java/android/database/sqlite/SQLiteConnection.java
@@ -711,6 +711,7 @@
throw new IllegalArgumentException("sql must not be null.");
}
+ int changedRows = 0;
final int cookie = mRecentOperations.beginOperation("executeForChangedRowCount",
sql, bindArgs);
try {
@@ -721,8 +722,9 @@
applyBlockGuardPolicy(statement);
attachCancellationSignal(cancellationSignal);
try {
- return nativeExecuteForChangedRowCount(
+ changedRows = nativeExecuteForChangedRowCount(
mConnectionPtr, statement.mStatementPtr);
+ return changedRows;
} finally {
detachCancellationSignal(cancellationSignal);
}
@@ -733,7 +735,9 @@
mRecentOperations.failOperation(cookie, ex);
throw ex;
} finally {
- mRecentOperations.endOperation(cookie);
+ if (mRecentOperations.endOperationDeferLog(cookie)) {
+ mRecentOperations.logOperation(cookie, "changedRows=" + changedRows);
+ }
}
}
diff --git a/core/java/android/hardware/LegacySensorManager.java b/core/java/android/hardware/LegacySensorManager.java
new file mode 100644
index 0000000..62c194f
--- /dev/null
+++ b/core/java/android/hardware/LegacySensorManager.java
@@ -0,0 +1,434 @@
+/*
+ * Copyright (C) 2012 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.hardware;
+
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.view.IRotationWatcher;
+import android.view.IWindowManager;
+import android.view.Surface;
+
+import java.util.HashMap;
+import java.util.List;
+
+/**
+ * Helper class for implementing the legacy sensor manager API.
+ * @hide
+ */
+@SuppressWarnings("deprecation")
+final class LegacySensorManager {
+ private static boolean sInitialized;
+ private static IWindowManager sWindowManager;
+ private static int sRotation = Surface.ROTATION_0;
+
+ private final SensorManager mSensorManager;
+
+ // List of legacy listeners. Guarded by mLegacyListenersMap.
+ private final HashMap<SensorListener, LegacyListener> mLegacyListenersMap =
+ new HashMap<SensorListener, LegacyListener>();
+
+ public LegacySensorManager(SensorManager sensorManager) {
+ mSensorManager = sensorManager;
+
+ synchronized (SensorManager.class) {
+ if (!sInitialized) {
+ sWindowManager = IWindowManager.Stub.asInterface(
+ ServiceManager.getService("window"));
+ if (sWindowManager != null) {
+ // if it's null we're running in the system process
+ // which won't get the rotated values
+ try {
+ sRotation = sWindowManager.watchRotation(
+ new IRotationWatcher.Stub() {
+ public void onRotationChanged(int rotation) {
+ LegacySensorManager.onRotationChanged(rotation);
+ }
+ }
+ );
+ } catch (RemoteException e) {
+ }
+ }
+ }
+ }
+ }
+
+ public int getSensors() {
+ int result = 0;
+ final List<Sensor> fullList = mSensorManager.getFullSensorList();
+ for (Sensor i : fullList) {
+ switch (i.getType()) {
+ case Sensor.TYPE_ACCELEROMETER:
+ result |= SensorManager.SENSOR_ACCELEROMETER;
+ break;
+ case Sensor.TYPE_MAGNETIC_FIELD:
+ result |= SensorManager.SENSOR_MAGNETIC_FIELD;
+ break;
+ case Sensor.TYPE_ORIENTATION:
+ result |= SensorManager.SENSOR_ORIENTATION
+ | SensorManager.SENSOR_ORIENTATION_RAW;
+ break;
+ }
+ }
+ return result;
+ }
+
+ public boolean registerListener(SensorListener listener, int sensors, int rate) {
+ if (listener == null) {
+ return false;
+ }
+ boolean result = false;
+ result = registerLegacyListener(SensorManager.SENSOR_ACCELEROMETER,
+ Sensor.TYPE_ACCELEROMETER, listener, sensors, rate) || result;
+ result = registerLegacyListener(SensorManager.SENSOR_MAGNETIC_FIELD,
+ Sensor.TYPE_MAGNETIC_FIELD, listener, sensors, rate) || result;
+ result = registerLegacyListener(SensorManager.SENSOR_ORIENTATION_RAW,
+ Sensor.TYPE_ORIENTATION, listener, sensors, rate) || result;
+ result = registerLegacyListener(SensorManager.SENSOR_ORIENTATION,
+ Sensor.TYPE_ORIENTATION, listener, sensors, rate) || result;
+ result = registerLegacyListener(SensorManager.SENSOR_TEMPERATURE,
+ Sensor.TYPE_TEMPERATURE, listener, sensors, rate) || result;
+ return result;
+ }
+
+ private boolean registerLegacyListener(int legacyType, int type,
+ SensorListener listener, int sensors, int rate) {
+ boolean result = false;
+ // Are we activating this legacy sensor?
+ if ((sensors & legacyType) != 0) {
+ // if so, find a suitable Sensor
+ Sensor sensor = mSensorManager.getDefaultSensor(type);
+ if (sensor != null) {
+ // We do all of this work holding the legacy listener lock to ensure
+ // that the invariants around listeners are maintained. This is safe
+ // because neither registerLegacyListener nor unregisterLegacyListener
+ // are called reentrantly while sensors are being registered or unregistered.
+ synchronized (mLegacyListenersMap) {
+ // If we don't already have one, create a LegacyListener
+ // to wrap this listener and process the events as
+ // they are expected by legacy apps.
+ LegacyListener legacyListener = mLegacyListenersMap.get(listener);
+ if (legacyListener == null) {
+ // we didn't find a LegacyListener for this client,
+ // create one, and put it in our list.
+ legacyListener = new LegacyListener(listener);
+ mLegacyListenersMap.put(listener, legacyListener);
+ }
+
+ // register this legacy sensor with this legacy listener
+ if (legacyListener.registerSensor(legacyType)) {
+ // and finally, register the legacy listener with the new apis
+ result = mSensorManager.registerListener(legacyListener, sensor, rate);
+ } else {
+ result = true; // sensor already enabled
+ }
+ }
+ }
+ }
+ return result;
+ }
+
+ public void unregisterListener(SensorListener listener, int sensors) {
+ if (listener == null) {
+ return;
+ }
+ unregisterLegacyListener(SensorManager.SENSOR_ACCELEROMETER, Sensor.TYPE_ACCELEROMETER,
+ listener, sensors);
+ unregisterLegacyListener(SensorManager.SENSOR_MAGNETIC_FIELD, Sensor.TYPE_MAGNETIC_FIELD,
+ listener, sensors);
+ unregisterLegacyListener(SensorManager.SENSOR_ORIENTATION_RAW, Sensor.TYPE_ORIENTATION,
+ listener, sensors);
+ unregisterLegacyListener(SensorManager.SENSOR_ORIENTATION, Sensor.TYPE_ORIENTATION,
+ listener, sensors);
+ unregisterLegacyListener(SensorManager.SENSOR_TEMPERATURE, Sensor.TYPE_TEMPERATURE,
+ listener, sensors);
+ }
+
+ private void unregisterLegacyListener(int legacyType, int type,
+ SensorListener listener, int sensors) {
+ // Are we deactivating this legacy sensor?
+ if ((sensors & legacyType) != 0) {
+ // if so, find the corresponding Sensor
+ Sensor sensor = mSensorManager.getDefaultSensor(type);
+ if (sensor != null) {
+ // We do all of this work holding the legacy listener lock to ensure
+ // that the invariants around listeners are maintained. This is safe
+ // because neither registerLegacyListener nor unregisterLegacyListener
+ // are called re-entrantly while sensors are being registered or unregistered.
+ synchronized (mLegacyListenersMap) {
+ // do we know about this listener?
+ LegacyListener legacyListener = mLegacyListenersMap.get(listener);
+ if (legacyListener != null) {
+ // unregister this legacy sensor and if we don't
+ // need the corresponding Sensor, unregister it too
+ if (legacyListener.unregisterSensor(legacyType)) {
+ // corresponding sensor not needed, unregister
+ mSensorManager.unregisterListener(legacyListener, sensor);
+
+ // finally check if we still need the legacyListener
+ // in our mapping, if not, get rid of it too.
+ if (!legacyListener.hasSensors()) {
+ mLegacyListenersMap.remove(listener);
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ static void onRotationChanged(int rotation) {
+ synchronized (SensorManager.class) {
+ sRotation = rotation;
+ }
+ }
+
+ static int getRotation() {
+ synchronized (SensorManager.class) {
+ return sRotation;
+ }
+ }
+
+ private static final class LegacyListener implements SensorEventListener {
+ private float mValues[] = new float[6];
+ private SensorListener mTarget;
+ private int mSensors;
+ private final LmsFilter mYawfilter = new LmsFilter();
+
+ LegacyListener(SensorListener target) {
+ mTarget = target;
+ mSensors = 0;
+ }
+
+ boolean registerSensor(int legacyType) {
+ if ((mSensors & legacyType) != 0) {
+ return false;
+ }
+ boolean alreadyHasOrientationSensor = hasOrientationSensor(mSensors);
+ mSensors |= legacyType;
+ if (alreadyHasOrientationSensor && hasOrientationSensor(legacyType)) {
+ return false; // don't need to re-register the orientation sensor
+ }
+ return true;
+ }
+
+ boolean unregisterSensor(int legacyType) {
+ if ((mSensors & legacyType) == 0) {
+ return false;
+ }
+ mSensors &= ~legacyType;
+ if (hasOrientationSensor(legacyType) && hasOrientationSensor(mSensors)) {
+ return false; // can't unregister the orientation sensor just yet
+ }
+ return true;
+ }
+
+ boolean hasSensors() {
+ return mSensors != 0;
+ }
+
+ private static boolean hasOrientationSensor(int sensors) {
+ return (sensors & (SensorManager.SENSOR_ORIENTATION
+ | SensorManager.SENSOR_ORIENTATION_RAW)) != 0;
+ }
+
+ public void onAccuracyChanged(Sensor sensor, int accuracy) {
+ try {
+ mTarget.onAccuracyChanged(getLegacySensorType(sensor.getType()), accuracy);
+ } catch (AbstractMethodError e) {
+ // old app that doesn't implement this method
+ // just ignore it.
+ }
+ }
+
+ public void onSensorChanged(SensorEvent event) {
+ final float v[] = mValues;
+ v[0] = event.values[0];
+ v[1] = event.values[1];
+ v[2] = event.values[2];
+ int type = event.sensor.getType();
+ int legacyType = getLegacySensorType(type);
+ mapSensorDataToWindow(legacyType, v, LegacySensorManager.getRotation());
+ if (type == Sensor.TYPE_ORIENTATION) {
+ if ((mSensors & SensorManager.SENSOR_ORIENTATION_RAW)!=0) {
+ mTarget.onSensorChanged(SensorManager.SENSOR_ORIENTATION_RAW, v);
+ }
+ if ((mSensors & SensorManager.SENSOR_ORIENTATION)!=0) {
+ v[0] = mYawfilter.filter(event.timestamp, v[0]);
+ mTarget.onSensorChanged(SensorManager.SENSOR_ORIENTATION, v);
+ }
+ } else {
+ mTarget.onSensorChanged(legacyType, v);
+ }
+ }
+
+ /*
+ * Helper function to convert the specified sensor's data to the windows's
+ * coordinate space from the device's coordinate space.
+ *
+ * output: 3,4,5: values in the old API format
+ * 0,1,2: transformed values in the old API format
+ *
+ */
+ private void mapSensorDataToWindow(int sensor,
+ float[] values, int orientation) {
+ float x = values[0];
+ float y = values[1];
+ float z = values[2];
+
+ switch (sensor) {
+ case SensorManager.SENSOR_ORIENTATION:
+ case SensorManager.SENSOR_ORIENTATION_RAW:
+ z = -z;
+ break;
+ case SensorManager.SENSOR_ACCELEROMETER:
+ x = -x;
+ y = -y;
+ z = -z;
+ break;
+ case SensorManager.SENSOR_MAGNETIC_FIELD:
+ x = -x;
+ y = -y;
+ break;
+ }
+ values[0] = x;
+ values[1] = y;
+ values[2] = z;
+ values[3] = x;
+ values[4] = y;
+ values[5] = z;
+
+ if ((orientation & Surface.ROTATION_90) != 0) {
+ // handles 90 and 270 rotation
+ switch (sensor) {
+ case SensorManager.SENSOR_ACCELEROMETER:
+ case SensorManager.SENSOR_MAGNETIC_FIELD:
+ values[0] =-y;
+ values[1] = x;
+ values[2] = z;
+ break;
+ case SensorManager.SENSOR_ORIENTATION:
+ case SensorManager.SENSOR_ORIENTATION_RAW:
+ values[0] = x + ((x < 270) ? 90 : -270);
+ values[1] = z;
+ values[2] = y;
+ break;
+ }
+ }
+ if ((orientation & Surface.ROTATION_180) != 0) {
+ x = values[0];
+ y = values[1];
+ z = values[2];
+ // handles 180 (flip) and 270 (flip + 90) rotation
+ switch (sensor) {
+ case SensorManager.SENSOR_ACCELEROMETER:
+ case SensorManager.SENSOR_MAGNETIC_FIELD:
+ values[0] =-x;
+ values[1] =-y;
+ values[2] = z;
+ break;
+ case SensorManager.SENSOR_ORIENTATION:
+ case SensorManager.SENSOR_ORIENTATION_RAW:
+ values[0] = (x >= 180) ? (x - 180) : (x + 180);
+ values[1] =-y;
+ values[2] =-z;
+ break;
+ }
+ }
+ }
+
+ private static int getLegacySensorType(int type) {
+ switch (type) {
+ case Sensor.TYPE_ACCELEROMETER:
+ return SensorManager.SENSOR_ACCELEROMETER;
+ case Sensor.TYPE_MAGNETIC_FIELD:
+ return SensorManager.SENSOR_MAGNETIC_FIELD;
+ case Sensor.TYPE_ORIENTATION:
+ return SensorManager.SENSOR_ORIENTATION_RAW;
+ case Sensor.TYPE_TEMPERATURE:
+ return SensorManager.SENSOR_TEMPERATURE;
+ }
+ return 0;
+ }
+ }
+
+ private static final class LmsFilter {
+ private static final int SENSORS_RATE_MS = 20;
+ private static final int COUNT = 12;
+ private static final float PREDICTION_RATIO = 1.0f/3.0f;
+ private static final float PREDICTION_TIME = (SENSORS_RATE_MS*COUNT/1000.0f)*PREDICTION_RATIO;
+ private float mV[] = new float[COUNT*2];
+ private float mT[] = new float[COUNT*2];
+ private int mIndex;
+
+ public LmsFilter() {
+ mIndex = COUNT;
+ }
+
+ public float filter(long time, float in) {
+ float v = in;
+ final float ns = 1.0f / 1000000000.0f;
+ final float t = time*ns;
+ float v1 = mV[mIndex];
+ if ((v-v1) > 180) {
+ v -= 360;
+ } else if ((v1-v) > 180) {
+ v += 360;
+ }
+ /* Manage the circular buffer, we write the data twice spaced
+ * by COUNT values, so that we don't have to copy the array
+ * when it's full
+ */
+ mIndex++;
+ if (mIndex >= COUNT*2)
+ mIndex = COUNT;
+ mV[mIndex] = v;
+ mT[mIndex] = t;
+ mV[mIndex-COUNT] = v;
+ mT[mIndex-COUNT] = t;
+
+ float A, B, C, D, E;
+ float a, b;
+ int i;
+
+ A = B = C = D = E = 0;
+ for (i=0 ; i<COUNT-1 ; i++) {
+ final int j = mIndex - 1 - i;
+ final float Z = mV[j];
+ final float T = 0.5f*(mT[j] + mT[j+1]) - t;
+ float dT = mT[j] - mT[j+1];
+ dT *= dT;
+ A += Z*dT;
+ B += T*(T*dT);
+ C += (T*dT);
+ D += Z*(T*dT);
+ E += dT;
+ }
+ b = (A*B + C*D) / (E*B + C*C);
+ a = (E*b - A) / C;
+ float f = b + PREDICTION_TIME*a;
+
+ // Normalize
+ f *= (1.0f / 360.0f);
+ if (((f>=0)?f:-f) >= 0.5f)
+ f = f - (float)Math.ceil(f + 0.5f) + 1.0f;
+ if (f < 0)
+ f += 1.0f;
+ f *= 360.0f;
+ return f;
+ }
+ }
+}
diff --git a/core/java/android/hardware/Sensor.java b/core/java/android/hardware/Sensor.java
index 63fb32d..3c70dc6 100644
--- a/core/java/android/hardware/Sensor.java
+++ b/core/java/android/hardware/Sensor.java
@@ -131,7 +131,6 @@
private float mResolution;
private float mPower;
private int mMinDelay;
- private int mLegacyType;
Sensor() {
@@ -203,12 +202,4 @@
mMaxRange = max;
mResolution = res;
}
-
- void setLegacyType(int legacyType) {
- mLegacyType = legacyType;
- }
-
- int getLegacyType() {
- return mLegacyType;
- }
}
diff --git a/core/java/android/hardware/SensorManager.java b/core/java/android/hardware/SensorManager.java
index 3fdf246..aeb46cf 100644
--- a/core/java/android/hardware/SensorManager.java
+++ b/core/java/android/hardware/SensorManager.java
@@ -16,23 +16,12 @@
package android.hardware;
-import android.os.Looper;
-import android.os.Process;
-import android.os.RemoteException;
import android.os.Handler;
-import android.os.Message;
-import android.os.ServiceManager;
import android.util.Log;
import android.util.SparseArray;
-import android.util.SparseBooleanArray;
-import android.util.SparseIntArray;
-import android.view.IRotationWatcher;
-import android.view.IWindowManager;
-import android.view.Surface;
import java.util.ArrayList;
import java.util.Collections;
-import java.util.HashMap;
import java.util.List;
/**
@@ -83,11 +72,19 @@
* @see Sensor
*
*/
-public class SensorManager
-{
- private static final String TAG = "SensorManager";
+public abstract class SensorManager {
+ /** @hide */
+ protected static final String TAG = "SensorManager";
+
private static final float[] mTempMatrix = new float[16];
+ // Cached lists of sensors by type. Guarded by mSensorListByType.
+ private final SparseArray<List<Sensor>> mSensorListByType =
+ new SparseArray<List<Sensor>>();
+
+ // Legacy sensor manager implementation. Guarded by mSensorListByType during initialization.
+ private LegacySensorManager mLegacySensorManager;
+
/* NOTE: sensor IDs must be a power of 2 */
/**
@@ -353,340 +350,18 @@
/** see {@link #remapCoordinateSystem} */
public static final int AXIS_MINUS_Z = AXIS_Z | 0x80;
- /*-----------------------------------------------------------------------*/
-
- Looper mMainLooper;
- @SuppressWarnings("deprecation")
- private HashMap<SensorListener, LegacyListener> mLegacyListenersMap =
- new HashMap<SensorListener, LegacyListener>();
-
- /*-----------------------------------------------------------------------*/
-
- private static final int SENSOR_DISABLE = -1;
- private static boolean sSensorModuleInitialized = false;
- private static ArrayList<Sensor> sFullSensorsList = new ArrayList<Sensor>();
- private static SparseArray<List<Sensor>> sSensorListByType = new SparseArray<List<Sensor>>();
- private static IWindowManager sWindowManager;
- private static int sRotation = Surface.ROTATION_0;
- /* The thread and the sensor list are global to the process
- * but the actual thread is spawned on demand */
- private static SensorThread sSensorThread;
- private static int sQueue;
-
- // Used within this module from outside SensorManager, don't make private
- static SparseArray<Sensor> sHandleToSensor = new SparseArray<Sensor>();
- static final ArrayList<ListenerDelegate> sListeners =
- new ArrayList<ListenerDelegate>();
-
- /*-----------------------------------------------------------------------*/
-
- private class SensorEventPool {
- private final int mPoolSize;
- private final SensorEvent mPool[];
- private int mNumItemsInPool;
-
- private SensorEvent createSensorEvent() {
- // maximal size for all legacy events is 3
- return new SensorEvent(3);
- }
-
- SensorEventPool(int poolSize) {
- mPoolSize = poolSize;
- mNumItemsInPool = poolSize;
- mPool = new SensorEvent[poolSize];
- }
-
- SensorEvent getFromPool() {
- SensorEvent t = null;
- synchronized (this) {
- if (mNumItemsInPool > 0) {
- // remove the "top" item from the pool
- final int index = mPoolSize - mNumItemsInPool;
- t = mPool[index];
- mPool[index] = null;
- mNumItemsInPool--;
- }
- }
- if (t == null) {
- // the pool was empty or this item was removed from the pool for
- // the first time. In any case, we need to create a new item.
- t = createSensorEvent();
- }
- return t;
- }
-
- void returnToPool(SensorEvent t) {
- synchronized (this) {
- // is there space left in the pool?
- if (mNumItemsInPool < mPoolSize) {
- // if so, return the item to the pool
- mNumItemsInPool++;
- final int index = mPoolSize - mNumItemsInPool;
- mPool[index] = t;
- }
- }
- }
- }
-
- private static SensorEventPool sPool;
-
- /*-----------------------------------------------------------------------*/
-
- static private class SensorThread {
-
- Thread mThread;
- boolean mSensorsReady;
-
- SensorThread() {
- }
-
- @Override
- protected void finalize() {
- }
-
- // must be called with sListeners lock
- boolean startLocked() {
- try {
- if (mThread == null) {
- mSensorsReady = false;
- SensorThreadRunnable runnable = new SensorThreadRunnable();
- Thread thread = new Thread(runnable, SensorThread.class.getName());
- thread.start();
- synchronized (runnable) {
- while (mSensorsReady == false) {
- runnable.wait();
- }
- }
- mThread = thread;
- }
- } catch (InterruptedException e) {
- }
- return mThread == null ? false : true;
- }
-
- private class SensorThreadRunnable implements Runnable {
- SensorThreadRunnable() {
- }
-
- private boolean open() {
- // NOTE: this cannot synchronize on sListeners, since
- // it's held in the main thread at least until we
- // return from here.
- sQueue = sensors_create_queue();
- return true;
- }
-
- public void run() {
- //Log.d(TAG, "entering main sensor thread");
- final float[] values = new float[3];
- final int[] status = new int[1];
- final long timestamp[] = new long[1];
- Process.setThreadPriority(Process.THREAD_PRIORITY_URGENT_DISPLAY);
-
- if (!open()) {
- return;
- }
-
- synchronized (this) {
- // we've open the driver, we're ready to open the sensors
- mSensorsReady = true;
- this.notify();
- }
-
- while (true) {
- // wait for an event
- final int sensor = sensors_data_poll(sQueue, values, status, timestamp);
-
- int accuracy = status[0];
- synchronized (sListeners) {
- if (sensor == -1 || sListeners.isEmpty()) {
- // we lost the connection to the event stream. this happens
- // when the last listener is removed or if there is an error
- if (sensor == -1 && !sListeners.isEmpty()) {
- // log a warning in case of abnormal termination
- Log.e(TAG, "_sensors_data_poll() failed, we bail out: sensors=" + sensor);
- }
- // we have no more listeners or polling failed, terminate the thread
- sensors_destroy_queue(sQueue);
- sQueue = 0;
- mThread = null;
- break;
- }
- final Sensor sensorObject = sHandleToSensor.get(sensor);
- if (sensorObject != null) {
- // report the sensor event to all listeners that
- // care about it.
- final int size = sListeners.size();
- for (int i=0 ; i<size ; i++) {
- ListenerDelegate listener = sListeners.get(i);
- if (listener.hasSensor(sensorObject)) {
- // this is asynchronous (okay to call
- // with sListeners lock held).
- listener.onSensorChangedLocked(sensorObject,
- values, timestamp, accuracy);
- }
- }
- }
- }
- }
- //Log.d(TAG, "exiting main sensor thread");
- }
- }
- }
-
- /*-----------------------------------------------------------------------*/
-
- private class ListenerDelegate {
- private final SensorEventListener mSensorEventListener;
- private final ArrayList<Sensor> mSensorList = new ArrayList<Sensor>();
- private final Handler mHandler;
- public SparseBooleanArray mSensors = new SparseBooleanArray();
- public SparseBooleanArray mFirstEvent = new SparseBooleanArray();
- public SparseIntArray mSensorAccuracies = new SparseIntArray();
-
- ListenerDelegate(SensorEventListener listener, Sensor sensor, Handler handler) {
- mSensorEventListener = listener;
- Looper looper = (handler != null) ? handler.getLooper() : mMainLooper;
- // currently we create one Handler instance per listener, but we could
- // have one per looper (we'd need to pass the ListenerDelegate
- // instance to handleMessage and keep track of them separately).
- mHandler = new Handler(looper) {
- @Override
- public void handleMessage(Message msg) {
- final SensorEvent t = (SensorEvent)msg.obj;
- final int handle = t.sensor.getHandle();
-
- switch (t.sensor.getType()) {
- // Only report accuracy for sensors that support it.
- case Sensor.TYPE_MAGNETIC_FIELD:
- case Sensor.TYPE_ORIENTATION:
- // call onAccuracyChanged() only if the value changes
- final int accuracy = mSensorAccuracies.get(handle);
- if ((t.accuracy >= 0) && (accuracy != t.accuracy)) {
- mSensorAccuracies.put(handle, t.accuracy);
- mSensorEventListener.onAccuracyChanged(t.sensor, t.accuracy);
- }
- break;
- default:
- // For other sensors, just report the accuracy once
- if (mFirstEvent.get(handle) == false) {
- mFirstEvent.put(handle, true);
- mSensorEventListener.onAccuracyChanged(
- t.sensor, SENSOR_STATUS_ACCURACY_HIGH);
- }
- break;
- }
-
- mSensorEventListener.onSensorChanged(t);
- sPool.returnToPool(t);
- }
- };
- addSensor(sensor);
- }
-
- Object getListener() {
- return mSensorEventListener;
- }
-
- void addSensor(Sensor sensor) {
- mSensors.put(sensor.getHandle(), true);
- mSensorList.add(sensor);
- }
- int removeSensor(Sensor sensor) {
- mSensors.delete(sensor.getHandle());
- mSensorList.remove(sensor);
- return mSensors.size();
- }
- boolean hasSensor(Sensor sensor) {
- return mSensors.get(sensor.getHandle());
- }
- List<Sensor> getSensors() {
- return mSensorList;
- }
-
- void onSensorChangedLocked(Sensor sensor, float[] values, long[] timestamp, int accuracy) {
- SensorEvent t = sPool.getFromPool();
- final float[] v = t.values;
- v[0] = values[0];
- v[1] = values[1];
- v[2] = values[2];
- t.timestamp = timestamp[0];
- t.accuracy = accuracy;
- t.sensor = sensor;
- Message msg = Message.obtain();
- msg.what = 0;
- msg.obj = t;
- msg.setAsynchronous(true);
- mHandler.sendMessage(msg);
- }
- }
/**
* {@hide}
*/
- public SensorManager(Looper mainLooper) {
- mMainLooper = mainLooper;
-
-
- synchronized(sListeners) {
- if (!sSensorModuleInitialized) {
- sSensorModuleInitialized = true;
-
- nativeClassInit();
-
- sWindowManager = IWindowManager.Stub.asInterface(
- ServiceManager.getService("window"));
- if (sWindowManager != null) {
- // if it's null we're running in the system process
- // which won't get the rotated values
- try {
- sRotation = sWindowManager.watchRotation(
- new IRotationWatcher.Stub() {
- public void onRotationChanged(int rotation) {
- SensorManager.this.onRotationChanged(rotation);
- }
- }
- );
- } catch (RemoteException e) {
- }
- }
-
- // initialize the sensor list
- sensors_module_init();
- final ArrayList<Sensor> fullList = sFullSensorsList;
- int i = 0;
- do {
- Sensor sensor = new Sensor();
- i = sensors_module_get_next_sensor(sensor, i);
-
- if (i>=0) {
- //Log.d(TAG, "found sensor: " + sensor.getName() +
- // ", handle=" + sensor.getHandle());
- sensor.setLegacyType(getLegacySensorType(sensor.getType()));
- fullList.add(sensor);
- sHandleToSensor.append(sensor.getHandle(), sensor);
- }
- } while (i>0);
-
- sPool = new SensorEventPool( sFullSensorsList.size()*2 );
- sSensorThread = new SensorThread();
- }
- }
+ public SensorManager() {
}
- private int getLegacySensorType(int type) {
- switch (type) {
- case Sensor.TYPE_ACCELEROMETER:
- return SENSOR_ACCELEROMETER;
- case Sensor.TYPE_MAGNETIC_FIELD:
- return SENSOR_MAGNETIC_FIELD;
- case Sensor.TYPE_ORIENTATION:
- return SENSOR_ORIENTATION_RAW;
- case Sensor.TYPE_TEMPERATURE:
- return SENSOR_TEMPERATURE;
- }
- return 0;
- }
+ /**
+ * Gets the full list of sensors that are available.
+ * @hide
+ */
+ protected abstract List<Sensor> getFullSensorList();
/**
* @return available sensors.
@@ -695,23 +370,7 @@
*/
@Deprecated
public int getSensors() {
- int result = 0;
- final ArrayList<Sensor> fullList = sFullSensorsList;
- for (Sensor i : fullList) {
- switch (i.getType()) {
- case Sensor.TYPE_ACCELEROMETER:
- result |= SensorManager.SENSOR_ACCELEROMETER;
- break;
- case Sensor.TYPE_MAGNETIC_FIELD:
- result |= SensorManager.SENSOR_MAGNETIC_FIELD;
- break;
- case Sensor.TYPE_ORIENTATION:
- result |= SensorManager.SENSOR_ORIENTATION |
- SensorManager.SENSOR_ORIENTATION_RAW;
- break;
- }
- }
- return result;
+ return getLegacySensorManager().getSensors();
}
/**
@@ -731,9 +390,9 @@
public List<Sensor> getSensorList(int type) {
// cache the returned lists the first time
List<Sensor> list;
- final ArrayList<Sensor> fullList = sFullSensorsList;
- synchronized(fullList) {
- list = sSensorListByType.get(type);
+ final List<Sensor> fullList = getFullSensorList();
+ synchronized (mSensorListByType) {
+ list = mSensorListByType.get(type);
if (list == null) {
if (type == Sensor.TYPE_ALL) {
list = fullList;
@@ -745,7 +404,7 @@
}
}
list = Collections.unmodifiableList(list);
- sSensorListByType.append(type, list);
+ mSensorListByType.append(type, list);
}
}
return list;
@@ -817,128 +476,7 @@
*/
@Deprecated
public boolean registerListener(SensorListener listener, int sensors, int rate) {
- if (listener == null) {
- return false;
- }
- boolean result = false;
- result = registerLegacyListener(SENSOR_ACCELEROMETER, Sensor.TYPE_ACCELEROMETER,
- listener, sensors, rate) || result;
- result = registerLegacyListener(SENSOR_MAGNETIC_FIELD, Sensor.TYPE_MAGNETIC_FIELD,
- listener, sensors, rate) || result;
- result = registerLegacyListener(SENSOR_ORIENTATION_RAW, Sensor.TYPE_ORIENTATION,
- listener, sensors, rate) || result;
- result = registerLegacyListener(SENSOR_ORIENTATION, Sensor.TYPE_ORIENTATION,
- listener, sensors, rate) || result;
- result = registerLegacyListener(SENSOR_TEMPERATURE, Sensor.TYPE_TEMPERATURE,
- listener, sensors, rate) || result;
- return result;
- }
-
- @SuppressWarnings("deprecation")
- private boolean registerLegacyListener(int legacyType, int type,
- SensorListener listener, int sensors, int rate)
- {
- if (listener == null) {
- return false;
- }
- boolean result = false;
- // Are we activating this legacy sensor?
- if ((sensors & legacyType) != 0) {
- // if so, find a suitable Sensor
- Sensor sensor = getDefaultSensor(type);
- if (sensor != null) {
- // If we don't already have one, create a LegacyListener
- // to wrap this listener and process the events as
- // they are expected by legacy apps.
- LegacyListener legacyListener = null;
- synchronized (mLegacyListenersMap) {
- legacyListener = mLegacyListenersMap.get(listener);
- if (legacyListener == null) {
- // we didn't find a LegacyListener for this client,
- // create one, and put it in our list.
- legacyListener = new LegacyListener(listener);
- mLegacyListenersMap.put(listener, legacyListener);
- }
- }
- // register this legacy sensor with this legacy listener
- legacyListener.registerSensor(legacyType);
- // and finally, register the legacy listener with the new apis
- result = registerListener(legacyListener, sensor, rate);
- }
- }
- return result;
- }
-
- /**
- * Unregisters a listener for the sensors with which it is registered.
- *
- * @deprecated This method is deprecated, use
- * {@link SensorManager#unregisterListener(SensorEventListener, Sensor)}
- * instead.
- *
- * @param listener
- * a SensorListener object
- *
- * @param sensors
- * a bit masks of the sensors to unregister from
- */
- @Deprecated
- public void unregisterListener(SensorListener listener, int sensors) {
- unregisterLegacyListener(SENSOR_ACCELEROMETER, Sensor.TYPE_ACCELEROMETER,
- listener, sensors);
- unregisterLegacyListener(SENSOR_MAGNETIC_FIELD, Sensor.TYPE_MAGNETIC_FIELD,
- listener, sensors);
- unregisterLegacyListener(SENSOR_ORIENTATION_RAW, Sensor.TYPE_ORIENTATION,
- listener, sensors);
- unregisterLegacyListener(SENSOR_ORIENTATION, Sensor.TYPE_ORIENTATION,
- listener, sensors);
- unregisterLegacyListener(SENSOR_TEMPERATURE, Sensor.TYPE_TEMPERATURE,
- listener, sensors);
- }
-
- @SuppressWarnings("deprecation")
- private void unregisterLegacyListener(int legacyType, int type,
- SensorListener listener, int sensors)
- {
- if (listener == null) {
- return;
- }
- // do we know about this listener?
- LegacyListener legacyListener = null;
- synchronized (mLegacyListenersMap) {
- legacyListener = mLegacyListenersMap.get(listener);
- }
- if (legacyListener != null) {
- // Are we deactivating this legacy sensor?
- if ((sensors & legacyType) != 0) {
- // if so, find the corresponding Sensor
- Sensor sensor = getDefaultSensor(type);
- if (sensor != null) {
- // unregister this legacy sensor and if we don't
- // need the corresponding Sensor, unregister it too
- if (legacyListener.unregisterSensor(legacyType)) {
- // corresponding sensor not needed, unregister
- unregisterListener(legacyListener, sensor);
- // finally check if we still need the legacyListener
- // in our mapping, if not, get rid of it too.
- synchronized(sListeners) {
- boolean found = false;
- for (ListenerDelegate i : sListeners) {
- if (i.getListener() == legacyListener) {
- found = true;
- break;
- }
- }
- if (!found) {
- synchronized (mLegacyListenersMap) {
- mLegacyListenersMap.remove(listener);
- }
- }
- }
- }
- }
- }
- }
+ return getLegacySensorManager().registerListener(listener, sensors, rate);
}
/**
@@ -959,6 +497,24 @@
/**
* Unregisters a listener for the sensors with which it is registered.
*
+ * @deprecated This method is deprecated, use
+ * {@link SensorManager#unregisterListener(SensorEventListener, Sensor)}
+ * instead.
+ *
+ * @param listener
+ * a SensorListener object
+ *
+ * @param sensors
+ * a bit masks of the sensors to unregister from
+ */
+ @Deprecated
+ public void unregisterListener(SensorListener listener, int sensors) {
+ getLegacySensorManager().unregisterListener(listener, sensors);
+ }
+
+ /**
+ * Unregisters a listener for the sensors with which it is registered.
+ *
* @param listener
* a SensorEventListener object
*
@@ -970,7 +526,11 @@
*
*/
public void unregisterListener(SensorEventListener listener, Sensor sensor) {
- unregisterListener((Object)listener, sensor);
+ if (listener == null || sensor == null) {
+ return;
+ }
+
+ unregisterListenerImpl(listener, sensor);
}
/**
@@ -984,9 +544,16 @@
*
*/
public void unregisterListener(SensorEventListener listener) {
- unregisterListener((Object)listener);
+ if (listener == null) {
+ return;
+ }
+
+ unregisterListenerImpl(listener, null);
}
+ /** @hide */
+ protected abstract void unregisterListenerImpl(SensorEventListener listener, Sensor sensor);
+
/**
* Registers a {@link android.hardware.SensorEventListener
* SensorEventListener} for the given sensor.
@@ -1019,31 +586,6 @@
return registerListener(listener, sensor, rate, null);
}
- private boolean enableSensorLocked(Sensor sensor, int delay) {
- boolean result = false;
- for (ListenerDelegate i : sListeners) {
- if (i.hasSensor(sensor)) {
- String name = sensor.getName();
- int handle = sensor.getHandle();
- result = sensors_enable_sensor(sQueue, name, handle, delay);
- break;
- }
- }
- return result;
- }
-
- private boolean disableSensorLocked(Sensor sensor) {
- for (ListenerDelegate i : sListeners) {
- if (i.hasSensor(sensor)) {
- // not an error, it's just that this sensor is still in use
- return true;
- }
- }
- String name = sensor.getName();
- int handle = sensor.getHandle();
- return sensors_enable_sensor(sQueue, name, handle, SENSOR_DISABLE);
- }
-
/**
* Registers a {@link android.hardware.SensorEventListener
* SensorEventListener} for the given sensor.
@@ -1081,7 +623,7 @@
if (listener == null || sensor == null) {
return false;
}
- boolean result = true;
+
int delay = -1;
switch (rate) {
case SENSOR_DELAY_FASTEST:
@@ -1101,92 +643,12 @@
break;
}
- synchronized (sListeners) {
- // look for this listener in our list
- ListenerDelegate l = null;
- for (ListenerDelegate i : sListeners) {
- if (i.getListener() == listener) {
- l = i;
- break;
- }
- }
-
- // if we don't find it, add it to the list
- if (l == null) {
- l = new ListenerDelegate(listener, sensor, handler);
- sListeners.add(l);
- // if the list is not empty, start our main thread
- if (!sListeners.isEmpty()) {
- if (sSensorThread.startLocked()) {
- if (!enableSensorLocked(sensor, delay)) {
- // oops. there was an error
- sListeners.remove(l);
- result = false;
- }
- } else {
- // there was an error, remove the listener
- sListeners.remove(l);
- result = false;
- }
- } else {
- // weird, we couldn't add the listener
- result = false;
- }
- } else {
- l.addSensor(sensor);
- if (!enableSensorLocked(sensor, delay)) {
- // oops. there was an error
- l.removeSensor(sensor);
- result = false;
- }
- }
- }
-
- return result;
+ return registerListenerImpl(listener, sensor, delay, handler);
}
- private void unregisterListener(Object listener, Sensor sensor) {
- if (listener == null || sensor == null) {
- return;
- }
-
- synchronized (sListeners) {
- final int size = sListeners.size();
- for (int i=0 ; i<size ; i++) {
- ListenerDelegate l = sListeners.get(i);
- if (l.getListener() == listener) {
- if (l.removeSensor(sensor) == 0) {
- // if we have no more sensors enabled on this listener,
- // take it off the list.
- sListeners.remove(i);
- }
- break;
- }
- }
- disableSensorLocked(sensor);
- }
- }
-
- private void unregisterListener(Object listener) {
- if (listener == null) {
- return;
- }
-
- synchronized (sListeners) {
- final int size = sListeners.size();
- for (int i=0 ; i<size ; i++) {
- ListenerDelegate l = sListeners.get(i);
- if (l.getListener() == listener) {
- sListeners.remove(i);
- // disable all sensors for this listener
- for (Sensor sensor : l.getSensors()) {
- disableSensorLocked(sensor);
- }
- break;
- }
- }
- }
- }
+ /** @hide */
+ protected abstract boolean registerListenerImpl(SensorEventListener listener, Sensor sensor,
+ int delay, Handler handler);
/**
* <p>
@@ -1653,228 +1115,11 @@
* @param p atmospheric pressure
* @return Altitude in meters
*/
- public static float getAltitude(float p0, float p) {
+ public static float getAltitude(float p0, float p) {
final float coef = 1.0f / 5.255f;
return 44330.0f * (1.0f - (float)Math.pow(p/p0, coef));
}
-
- /**
- * {@hide}
- */
- public void onRotationChanged(int rotation) {
- synchronized(sListeners) {
- sRotation = rotation;
- }
- }
-
- static int getRotation() {
- synchronized(sListeners) {
- return sRotation;
- }
- }
-
- private class LegacyListener implements SensorEventListener {
- private float mValues[] = new float[6];
- @SuppressWarnings("deprecation")
- private SensorListener mTarget;
- private int mSensors;
- private final LmsFilter mYawfilter = new LmsFilter();
-
- @SuppressWarnings("deprecation")
- LegacyListener(SensorListener target) {
- mTarget = target;
- mSensors = 0;
- }
-
- void registerSensor(int legacyType) {
- mSensors |= legacyType;
- }
-
- boolean unregisterSensor(int legacyType) {
- mSensors &= ~legacyType;
- int mask = SENSOR_ORIENTATION|SENSOR_ORIENTATION_RAW;
- if (((legacyType&mask)!=0) && ((mSensors&mask)!=0)) {
- return false;
- }
- return true;
- }
-
- @SuppressWarnings("deprecation")
- public void onAccuracyChanged(Sensor sensor, int accuracy) {
- try {
- mTarget.onAccuracyChanged(sensor.getLegacyType(), accuracy);
- } catch (AbstractMethodError e) {
- // old app that doesn't implement this method
- // just ignore it.
- }
- }
-
- @SuppressWarnings("deprecation")
- public void onSensorChanged(SensorEvent event) {
- final float v[] = mValues;
- v[0] = event.values[0];
- v[1] = event.values[1];
- v[2] = event.values[2];
- int legacyType = event.sensor.getLegacyType();
- mapSensorDataToWindow(legacyType, v, SensorManager.getRotation());
- if (event.sensor.getType() == Sensor.TYPE_ORIENTATION) {
- if ((mSensors & SENSOR_ORIENTATION_RAW)!=0) {
- mTarget.onSensorChanged(SENSOR_ORIENTATION_RAW, v);
- }
- if ((mSensors & SENSOR_ORIENTATION)!=0) {
- v[0] = mYawfilter.filter(event.timestamp, v[0]);
- mTarget.onSensorChanged(SENSOR_ORIENTATION, v);
- }
- } else {
- mTarget.onSensorChanged(legacyType, v);
- }
- }
-
- /*
- * Helper function to convert the specified sensor's data to the windows's
- * coordinate space from the device's coordinate space.
- *
- * output: 3,4,5: values in the old API format
- * 0,1,2: transformed values in the old API format
- *
- */
- private void mapSensorDataToWindow(int sensor,
- float[] values, int orientation) {
- float x = values[0];
- float y = values[1];
- float z = values[2];
-
- switch (sensor) {
- case SensorManager.SENSOR_ORIENTATION:
- case SensorManager.SENSOR_ORIENTATION_RAW:
- z = -z;
- break;
- case SensorManager.SENSOR_ACCELEROMETER:
- x = -x;
- y = -y;
- z = -z;
- break;
- case SensorManager.SENSOR_MAGNETIC_FIELD:
- x = -x;
- y = -y;
- break;
- }
- values[0] = x;
- values[1] = y;
- values[2] = z;
- values[3] = x;
- values[4] = y;
- values[5] = z;
-
- if ((orientation & Surface.ROTATION_90) != 0) {
- // handles 90 and 270 rotation
- switch (sensor) {
- case SENSOR_ACCELEROMETER:
- case SENSOR_MAGNETIC_FIELD:
- values[0] =-y;
- values[1] = x;
- values[2] = z;
- break;
- case SENSOR_ORIENTATION:
- case SENSOR_ORIENTATION_RAW:
- values[0] = x + ((x < 270) ? 90 : -270);
- values[1] = z;
- values[2] = y;
- break;
- }
- }
- if ((orientation & Surface.ROTATION_180) != 0) {
- x = values[0];
- y = values[1];
- z = values[2];
- // handles 180 (flip) and 270 (flip + 90) rotation
- switch (sensor) {
- case SENSOR_ACCELEROMETER:
- case SENSOR_MAGNETIC_FIELD:
- values[0] =-x;
- values[1] =-y;
- values[2] = z;
- break;
- case SENSOR_ORIENTATION:
- case SENSOR_ORIENTATION_RAW:
- values[0] = (x >= 180) ? (x - 180) : (x + 180);
- values[1] =-y;
- values[2] =-z;
- break;
- }
- }
- }
- }
-
- class LmsFilter {
- private static final int SENSORS_RATE_MS = 20;
- private static final int COUNT = 12;
- private static final float PREDICTION_RATIO = 1.0f/3.0f;
- private static final float PREDICTION_TIME = (SENSORS_RATE_MS*COUNT/1000.0f)*PREDICTION_RATIO;
- private float mV[] = new float[COUNT*2];
- private float mT[] = new float[COUNT*2];
- private int mIndex;
-
- public LmsFilter() {
- mIndex = COUNT;
- }
-
- public float filter(long time, float in) {
- float v = in;
- final float ns = 1.0f / 1000000000.0f;
- final float t = time*ns;
- float v1 = mV[mIndex];
- if ((v-v1) > 180) {
- v -= 360;
- } else if ((v1-v) > 180) {
- v += 360;
- }
- /* Manage the circular buffer, we write the data twice spaced
- * by COUNT values, so that we don't have to copy the array
- * when it's full
- */
- mIndex++;
- if (mIndex >= COUNT*2)
- mIndex = COUNT;
- mV[mIndex] = v;
- mT[mIndex] = t;
- mV[mIndex-COUNT] = v;
- mT[mIndex-COUNT] = t;
-
- float A, B, C, D, E;
- float a, b;
- int i;
-
- A = B = C = D = E = 0;
- for (i=0 ; i<COUNT-1 ; i++) {
- final int j = mIndex - 1 - i;
- final float Z = mV[j];
- final float T = 0.5f*(mT[j] + mT[j+1]) - t;
- float dT = mT[j] - mT[j+1];
- dT *= dT;
- A += Z*dT;
- B += T*(T*dT);
- C += (T*dT);
- D += Z*(T*dT);
- E += dT;
- }
- b = (A*B + C*D) / (E*B + C*C);
- a = (E*b - A) / C;
- float f = b + PREDICTION_TIME*a;
-
- // Normalize
- f *= (1.0f / 360.0f);
- if (((f>=0)?f:-f) >= 0.5f)
- f = f - (float)Math.ceil(f + 0.5f) + 1.0f;
- if (f < 0)
- f += 1.0f;
- f *= 360.0f;
- return f;
- }
- }
-
-
/** Helper function to compute the angle change between two rotation matrices.
* Given a current rotation matrix (R) and a previous rotation matrix
* (prevR) computes the rotation around the x,y, and z axes which
@@ -2060,14 +1305,66 @@
Q[3] = rv[2];
}
- private static native void nativeClassInit();
+ private LegacySensorManager getLegacySensorManager() {
+ synchronized (mSensorListByType) {
+ if (mLegacySensorManager == null) {
+ Log.i(TAG, "This application is using deprecated SensorManager API which will "
+ + "be removed someday. Please consider switching to the new API.");
+ mLegacySensorManager = new LegacySensorManager(this);
+ }
+ return mLegacySensorManager;
+ }
+ }
- private static native int sensors_module_init();
- private static native int sensors_module_get_next_sensor(Sensor sensor, int next);
+ /**
+ * Sensor event pool implementation.
+ * @hide
+ */
+ protected static final class SensorEventPool {
+ private final int mPoolSize;
+ private final SensorEvent mPool[];
+ private int mNumItemsInPool;
- // Used within this module from outside SensorManager, don't make private
- static native int sensors_create_queue();
- static native void sensors_destroy_queue(int queue);
- static native boolean sensors_enable_sensor(int queue, String name, int sensor, int enable);
- static native int sensors_data_poll(int queue, float[] values, int[] status, long[] timestamp);
+ private SensorEvent createSensorEvent() {
+ // maximal size for all legacy events is 3
+ return new SensorEvent(3);
+ }
+
+ SensorEventPool(int poolSize) {
+ mPoolSize = poolSize;
+ mNumItemsInPool = poolSize;
+ mPool = new SensorEvent[poolSize];
+ }
+
+ SensorEvent getFromPool() {
+ SensorEvent t = null;
+ synchronized (this) {
+ if (mNumItemsInPool > 0) {
+ // remove the "top" item from the pool
+ final int index = mPoolSize - mNumItemsInPool;
+ t = mPool[index];
+ mPool[index] = null;
+ mNumItemsInPool--;
+ }
+ }
+ if (t == null) {
+ // the pool was empty or this item was removed from the pool for
+ // the first time. In any case, we need to create a new item.
+ t = createSensorEvent();
+ }
+ return t;
+ }
+
+ void returnToPool(SensorEvent t) {
+ synchronized (this) {
+ // is there space left in the pool?
+ if (mNumItemsInPool < mPoolSize) {
+ // if so, return the item to the pool
+ mNumItemsInPool++;
+ final int index = mPoolSize - mNumItemsInPool;
+ mPool[index] = t;
+ }
+ }
+ }
+ }
}
diff --git a/core/java/android/hardware/SystemSensorManager.java b/core/java/android/hardware/SystemSensorManager.java
new file mode 100644
index 0000000..0204e94
--- /dev/null
+++ b/core/java/android/hardware/SystemSensorManager.java
@@ -0,0 +1,398 @@
+/*
+ * Copyright (C) 2012 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.hardware;
+
+import android.os.Looper;
+import android.os.Process;
+import android.os.Handler;
+import android.os.Message;
+import android.util.Log;
+import android.util.SparseArray;
+import android.util.SparseBooleanArray;
+import android.util.SparseIntArray;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Sensor manager implementation that communicates with the built-in
+ * system sensors.
+ *
+ * @hide
+ */
+public class SystemSensorManager extends SensorManager {
+ private static final int SENSOR_DISABLE = -1;
+ private static boolean sSensorModuleInitialized = false;
+ private static ArrayList<Sensor> sFullSensorsList = new ArrayList<Sensor>();
+ /* The thread and the sensor list are global to the process
+ * but the actual thread is spawned on demand */
+ private static SensorThread sSensorThread;
+ private static int sQueue;
+
+ // Used within this module from outside SensorManager, don't make private
+ static SparseArray<Sensor> sHandleToSensor = new SparseArray<Sensor>();
+ static final ArrayList<ListenerDelegate> sListeners =
+ new ArrayList<ListenerDelegate>();
+
+ // Common pool of sensor events.
+ static SensorEventPool sPool;
+
+ // Looper associated with the context in which this instance was created.
+ final Looper mMainLooper;
+
+ /*-----------------------------------------------------------------------*/
+
+ static private class SensorThread {
+
+ Thread mThread;
+ boolean mSensorsReady;
+
+ SensorThread() {
+ }
+
+ @Override
+ protected void finalize() {
+ }
+
+ // must be called with sListeners lock
+ boolean startLocked() {
+ try {
+ if (mThread == null) {
+ mSensorsReady = false;
+ SensorThreadRunnable runnable = new SensorThreadRunnable();
+ Thread thread = new Thread(runnable, SensorThread.class.getName());
+ thread.start();
+ synchronized (runnable) {
+ while (mSensorsReady == false) {
+ runnable.wait();
+ }
+ }
+ mThread = thread;
+ }
+ } catch (InterruptedException e) {
+ }
+ return mThread == null ? false : true;
+ }
+
+ private class SensorThreadRunnable implements Runnable {
+ SensorThreadRunnable() {
+ }
+
+ private boolean open() {
+ // NOTE: this cannot synchronize on sListeners, since
+ // it's held in the main thread at least until we
+ // return from here.
+ sQueue = sensors_create_queue();
+ return true;
+ }
+
+ public void run() {
+ //Log.d(TAG, "entering main sensor thread");
+ final float[] values = new float[3];
+ final int[] status = new int[1];
+ final long timestamp[] = new long[1];
+ Process.setThreadPriority(Process.THREAD_PRIORITY_URGENT_DISPLAY);
+
+ if (!open()) {
+ return;
+ }
+
+ synchronized (this) {
+ // we've open the driver, we're ready to open the sensors
+ mSensorsReady = true;
+ this.notify();
+ }
+
+ while (true) {
+ // wait for an event
+ final int sensor = sensors_data_poll(sQueue, values, status, timestamp);
+
+ int accuracy = status[0];
+ synchronized (sListeners) {
+ if (sensor == -1 || sListeners.isEmpty()) {
+ // we lost the connection to the event stream. this happens
+ // when the last listener is removed or if there is an error
+ if (sensor == -1 && !sListeners.isEmpty()) {
+ // log a warning in case of abnormal termination
+ Log.e(TAG, "_sensors_data_poll() failed, we bail out: sensors=" + sensor);
+ }
+ // we have no more listeners or polling failed, terminate the thread
+ sensors_destroy_queue(sQueue);
+ sQueue = 0;
+ mThread = null;
+ break;
+ }
+ final Sensor sensorObject = sHandleToSensor.get(sensor);
+ if (sensorObject != null) {
+ // report the sensor event to all listeners that
+ // care about it.
+ final int size = sListeners.size();
+ for (int i=0 ; i<size ; i++) {
+ ListenerDelegate listener = sListeners.get(i);
+ if (listener.hasSensor(sensorObject)) {
+ // this is asynchronous (okay to call
+ // with sListeners lock held).
+ listener.onSensorChangedLocked(sensorObject,
+ values, timestamp, accuracy);
+ }
+ }
+ }
+ }
+ }
+ //Log.d(TAG, "exiting main sensor thread");
+ }
+ }
+ }
+
+ /*-----------------------------------------------------------------------*/
+
+ private class ListenerDelegate {
+ private final SensorEventListener mSensorEventListener;
+ private final ArrayList<Sensor> mSensorList = new ArrayList<Sensor>();
+ private final Handler mHandler;
+ public SparseBooleanArray mSensors = new SparseBooleanArray();
+ public SparseBooleanArray mFirstEvent = new SparseBooleanArray();
+ public SparseIntArray mSensorAccuracies = new SparseIntArray();
+
+ ListenerDelegate(SensorEventListener listener, Sensor sensor, Handler handler) {
+ mSensorEventListener = listener;
+ Looper looper = (handler != null) ? handler.getLooper() : mMainLooper;
+ // currently we create one Handler instance per listener, but we could
+ // have one per looper (we'd need to pass the ListenerDelegate
+ // instance to handleMessage and keep track of them separately).
+ mHandler = new Handler(looper) {
+ @Override
+ public void handleMessage(Message msg) {
+ final SensorEvent t = (SensorEvent)msg.obj;
+ final int handle = t.sensor.getHandle();
+
+ switch (t.sensor.getType()) {
+ // Only report accuracy for sensors that support it.
+ case Sensor.TYPE_MAGNETIC_FIELD:
+ case Sensor.TYPE_ORIENTATION:
+ // call onAccuracyChanged() only if the value changes
+ final int accuracy = mSensorAccuracies.get(handle);
+ if ((t.accuracy >= 0) && (accuracy != t.accuracy)) {
+ mSensorAccuracies.put(handle, t.accuracy);
+ mSensorEventListener.onAccuracyChanged(t.sensor, t.accuracy);
+ }
+ break;
+ default:
+ // For other sensors, just report the accuracy once
+ if (mFirstEvent.get(handle) == false) {
+ mFirstEvent.put(handle, true);
+ mSensorEventListener.onAccuracyChanged(
+ t.sensor, SENSOR_STATUS_ACCURACY_HIGH);
+ }
+ break;
+ }
+
+ mSensorEventListener.onSensorChanged(t);
+ sPool.returnToPool(t);
+ }
+ };
+ addSensor(sensor);
+ }
+
+ Object getListener() {
+ return mSensorEventListener;
+ }
+
+ void addSensor(Sensor sensor) {
+ mSensors.put(sensor.getHandle(), true);
+ mSensorList.add(sensor);
+ }
+ int removeSensor(Sensor sensor) {
+ mSensors.delete(sensor.getHandle());
+ mSensorList.remove(sensor);
+ return mSensors.size();
+ }
+ boolean hasSensor(Sensor sensor) {
+ return mSensors.get(sensor.getHandle());
+ }
+ List<Sensor> getSensors() {
+ return mSensorList;
+ }
+
+ void onSensorChangedLocked(Sensor sensor, float[] values, long[] timestamp, int accuracy) {
+ SensorEvent t = sPool.getFromPool();
+ final float[] v = t.values;
+ v[0] = values[0];
+ v[1] = values[1];
+ v[2] = values[2];
+ t.timestamp = timestamp[0];
+ t.accuracy = accuracy;
+ t.sensor = sensor;
+ Message msg = Message.obtain();
+ msg.what = 0;
+ msg.obj = t;
+ msg.setAsynchronous(true);
+ mHandler.sendMessage(msg);
+ }
+ }
+
+ /**
+ * {@hide}
+ */
+ public SystemSensorManager(Looper mainLooper) {
+ mMainLooper = mainLooper;
+
+ synchronized(sListeners) {
+ if (!sSensorModuleInitialized) {
+ sSensorModuleInitialized = true;
+
+ nativeClassInit();
+
+ // initialize the sensor list
+ sensors_module_init();
+ final ArrayList<Sensor> fullList = sFullSensorsList;
+ int i = 0;
+ do {
+ Sensor sensor = new Sensor();
+ i = sensors_module_get_next_sensor(sensor, i);
+
+ if (i>=0) {
+ //Log.d(TAG, "found sensor: " + sensor.getName() +
+ // ", handle=" + sensor.getHandle());
+ fullList.add(sensor);
+ sHandleToSensor.append(sensor.getHandle(), sensor);
+ }
+ } while (i>0);
+
+ sPool = new SensorEventPool( sFullSensorsList.size()*2 );
+ sSensorThread = new SensorThread();
+ }
+ }
+ }
+
+ /** @hide */
+ @Override
+ protected List<Sensor> getFullSensorList() {
+ return sFullSensorsList;
+ }
+
+ private boolean enableSensorLocked(Sensor sensor, int delay) {
+ boolean result = false;
+ for (ListenerDelegate i : sListeners) {
+ if (i.hasSensor(sensor)) {
+ String name = sensor.getName();
+ int handle = sensor.getHandle();
+ result = sensors_enable_sensor(sQueue, name, handle, delay);
+ break;
+ }
+ }
+ return result;
+ }
+
+ private boolean disableSensorLocked(Sensor sensor) {
+ for (ListenerDelegate i : sListeners) {
+ if (i.hasSensor(sensor)) {
+ // not an error, it's just that this sensor is still in use
+ return true;
+ }
+ }
+ String name = sensor.getName();
+ int handle = sensor.getHandle();
+ return sensors_enable_sensor(sQueue, name, handle, SENSOR_DISABLE);
+ }
+
+ /** @hide */
+ @Override
+ protected boolean registerListenerImpl(SensorEventListener listener, Sensor sensor,
+ int delay, Handler handler) {
+ boolean result = true;
+ synchronized (sListeners) {
+ // look for this listener in our list
+ ListenerDelegate l = null;
+ for (ListenerDelegate i : sListeners) {
+ if (i.getListener() == listener) {
+ l = i;
+ break;
+ }
+ }
+
+ // if we don't find it, add it to the list
+ if (l == null) {
+ l = new ListenerDelegate(listener, sensor, handler);
+ sListeners.add(l);
+ // if the list is not empty, start our main thread
+ if (!sListeners.isEmpty()) {
+ if (sSensorThread.startLocked()) {
+ if (!enableSensorLocked(sensor, delay)) {
+ // oops. there was an error
+ sListeners.remove(l);
+ result = false;
+ }
+ } else {
+ // there was an error, remove the listener
+ sListeners.remove(l);
+ result = false;
+ }
+ } else {
+ // weird, we couldn't add the listener
+ result = false;
+ }
+ } else if (!l.hasSensor(sensor)) {
+ l.addSensor(sensor);
+ if (!enableSensorLocked(sensor, delay)) {
+ // oops. there was an error
+ l.removeSensor(sensor);
+ result = false;
+ }
+ }
+ }
+
+ return result;
+ }
+
+ /** @hide */
+ @Override
+ protected void unregisterListenerImpl(SensorEventListener listener, Sensor sensor) {
+ synchronized (sListeners) {
+ final int size = sListeners.size();
+ for (int i=0 ; i<size ; i++) {
+ ListenerDelegate l = sListeners.get(i);
+ if (l.getListener() == listener) {
+ if (sensor == null) {
+ sListeners.remove(i);
+ // disable all sensors for this listener
+ for (Sensor s : l.getSensors()) {
+ disableSensorLocked(s);
+ }
+ } else if (l.removeSensor(sensor) == 0) {
+ // if we have no more sensors enabled on this listener,
+ // take it off the list.
+ sListeners.remove(i);
+ disableSensorLocked(sensor);
+ }
+ break;
+ }
+ }
+ }
+ }
+
+ private static native void nativeClassInit();
+
+ private static native int sensors_module_init();
+ private static native int sensors_module_get_next_sensor(Sensor sensor, int next);
+
+ // Used within this module from outside SensorManager, don't make private
+ static native int sensors_create_queue();
+ static native void sensors_destroy_queue(int queue);
+ static native boolean sensors_enable_sensor(int queue, String name, int sensor, int enable);
+ static native int sensors_data_poll(int queue, float[] values, int[] status, long[] timestamp);
+}
diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java
index de16985..ef4209f 100644
--- a/core/java/android/net/ConnectivityManager.java
+++ b/core/java/android/net/ConnectivityManager.java
@@ -373,10 +373,11 @@
}
/**
- * Gets you info about the current data network.
- * Call {@link NetworkInfo#isConnected()} on the returned {@link NetworkInfo}
- * to check if the device has a data connection.
- */
+ * Returns details about the currently active data network. When connected,
+ * this network is the default route for outgoing connections. You should
+ * always check {@link NetworkInfo#isConnected()} before initiating network
+ * traffic. This may return {@code null} when no networks are available.
+ */
public NetworkInfo getActiveNetworkInfo() {
try {
return mService.getActiveNetworkInfo();
@@ -856,4 +857,19 @@
} catch (RemoteException e) {}
return false;
}
+
+ /**
+ * Returns if the currently active data network is metered. A network is
+ * classified as metered when the user is sensitive to heavy data usage on
+ * that connection. You should check this before doing large data transfers,
+ * and warn the user or delay the operation until another network is
+ * available.
+ */
+ public boolean isActiveNetworkMetered() {
+ try {
+ return mService.isActiveNetworkMetered();
+ } catch (RemoteException e) {
+ return false;
+ }
+ }
}
diff --git a/core/java/android/net/IConnectivityManager.aidl b/core/java/android/net/IConnectivityManager.aidl
index 7046008..92aeff2 100644
--- a/core/java/android/net/IConnectivityManager.aidl
+++ b/core/java/android/net/IConnectivityManager.aidl
@@ -51,6 +51,7 @@
NetworkState[] getAllNetworkState();
NetworkQuotaInfo getActiveNetworkQuotaInfo();
+ boolean isActiveNetworkMetered();
boolean setRadios(boolean onOff);
diff --git a/core/java/android/net/INetworkPolicyManager.aidl b/core/java/android/net/INetworkPolicyManager.aidl
index 89c9c36..3250ae7 100644
--- a/core/java/android/net/INetworkPolicyManager.aidl
+++ b/core/java/android/net/INetworkPolicyManager.aidl
@@ -32,6 +32,7 @@
/** Control UID policies. */
void setAppPolicy(int appId, int policy);
int getAppPolicy(int appId);
+ int[] getAppsWithPolicy(int policy);
boolean isUidForeground(int uid);
@@ -50,5 +51,6 @@
boolean getRestrictBackground();
NetworkQuotaInfo getNetworkQuotaInfo(in NetworkState state);
+ boolean isNetworkMetered(in NetworkState state);
}
diff --git a/core/java/android/net/INetworkStatsService.aidl b/core/java/android/net/INetworkStatsService.aidl
index b4f6367..08d4c6c 100644
--- a/core/java/android/net/INetworkStatsService.aidl
+++ b/core/java/android/net/INetworkStatsService.aidl
@@ -32,6 +32,9 @@
/** Return data layer snapshot of UID network usage. */
NetworkStats getDataLayerSnapshotForUid(int uid);
+ /** Return set of any ifaces associated with mobile networks since boot. */
+ String[] getMobileIfaces();
+
/** Increment data layer count of operations performed for UID and tag. */
void incrementOperationCount(int uid, int tag, int operationCount);
diff --git a/core/java/android/net/NetworkPolicyManager.java b/core/java/android/net/NetworkPolicyManager.java
index 2b36131..07bfd4b 100644
--- a/core/java/android/net/NetworkPolicyManager.java
+++ b/core/java/android/net/NetworkPolicyManager.java
@@ -92,6 +92,14 @@
}
}
+ public int[] getAppsWithPolicy(int policy) {
+ try {
+ return mService.getAppsWithPolicy(policy);
+ } catch (RemoteException e) {
+ return new int[0];
+ }
+ }
+
public void registerListener(INetworkPolicyListener listener) {
try {
mService.registerListener(listener);
diff --git a/core/java/android/net/NetworkTemplate.java b/core/java/android/net/NetworkTemplate.java
index 50432a1..39a4d7b 100644
--- a/core/java/android/net/NetworkTemplate.java
+++ b/core/java/android/net/NetworkTemplate.java
@@ -48,6 +48,8 @@
public static final int MATCH_MOBILE_4G = 3;
public static final int MATCH_WIFI = 4;
public static final int MATCH_ETHERNET = 5;
+ public static final int MATCH_MOBILE_WILDCARD = 6;
+ public static final int MATCH_WIFI_WILDCARD = 7;
/**
* Set of {@link NetworkInfo#getType()} that reflect data usage.
@@ -86,11 +88,19 @@
}
/**
+ * Template to match {@link ConnectivityManager#TYPE_MOBILE} networks,
+ * regardless of IMSI.
+ */
+ public static NetworkTemplate buildTemplateMobileWildcard() {
+ return new NetworkTemplate(MATCH_MOBILE_WILDCARD, null, null);
+ }
+
+ /**
* Template to match all {@link ConnectivityManager#TYPE_WIFI} networks,
* regardless of SSID.
*/
public static NetworkTemplate buildTemplateWifiWildcard() {
- return new NetworkTemplate(MATCH_WIFI, null, null);
+ return new NetworkTemplate(MATCH_WIFI_WILDCARD, null, null);
}
@Deprecated
@@ -198,6 +208,10 @@
return matchesWifi(ident);
case MATCH_ETHERNET:
return matchesEthernet(ident);
+ case MATCH_MOBILE_WILDCARD:
+ return matchesMobileWildcard(ident);
+ case MATCH_WIFI_WILDCARD:
+ return matchesWifiWildcard(ident);
default:
throw new IllegalArgumentException("unknown network template");
}
@@ -257,13 +271,7 @@
private boolean matchesWifi(NetworkIdentity ident) {
switch (ident.mType) {
case TYPE_WIFI:
- if (mNetworkId == null) {
- return true;
- } else {
- return Objects.equal(mNetworkId, ident.mNetworkId);
- }
- case TYPE_WIFI_P2P:
- return mNetworkId == null;
+ return Objects.equal(mNetworkId, ident.mNetworkId);
default:
return false;
}
@@ -279,6 +287,24 @@
return false;
}
+ private boolean matchesMobileWildcard(NetworkIdentity ident) {
+ if (ident.mType == TYPE_WIMAX) {
+ return true;
+ } else {
+ return contains(DATA_USAGE_NETWORK_TYPES, ident.mType);
+ }
+ }
+
+ private boolean matchesWifiWildcard(NetworkIdentity ident) {
+ switch (ident.mType) {
+ case TYPE_WIFI:
+ case TYPE_WIFI_P2P:
+ return true;
+ default:
+ return false;
+ }
+ }
+
private static String getMatchRuleName(int matchRule) {
switch (matchRule) {
case MATCH_MOBILE_3G_LOWER:
@@ -291,6 +317,10 @@
return "WIFI";
case MATCH_ETHERNET:
return "ETHERNET";
+ case MATCH_MOBILE_WILDCARD:
+ return "MOBILE_WILDCARD";
+ case MATCH_WIFI_WILDCARD:
+ return "WIFI_WILDCARD";
default:
return "UNKNOWN";
}
diff --git a/core/java/android/net/TrafficStats.java b/core/java/android/net/TrafficStats.java
index ee3e165..e437d2e 100644
--- a/core/java/android/net/TrafficStats.java
+++ b/core/java/android/net/TrafficStats.java
@@ -88,6 +88,16 @@
*/
public static final int TAG_SYSTEM_BACKUP = 0xFFFFFF03;
+ private static INetworkStatsService sStatsService;
+
+ private synchronized static INetworkStatsService getStatsService() {
+ if (sStatsService == null) {
+ sStatsService = INetworkStatsService.Stub.asInterface(
+ ServiceManager.getService(Context.NETWORK_STATS_SERVICE));
+ }
+ return sStatsService;
+ }
+
/**
* Snapshot of {@link NetworkStats} when the currently active profiling
* session started, or {@code null} if no session active.
@@ -228,11 +238,9 @@
* @param operationCount Number of operations to increment count by.
*/
public static void incrementOperationCount(int tag, int operationCount) {
- final INetworkStatsService statsService = INetworkStatsService.Stub.asInterface(
- ServiceManager.getService(Context.NETWORK_STATS_SERVICE));
final int uid = android.os.Process.myUid();
try {
- statsService.incrementOperationCount(uid, tag, operationCount);
+ getStatsService().incrementOperationCount(uid, tag, operationCount);
} catch (RemoteException e) {
throw new RuntimeException(e);
}
@@ -257,7 +265,13 @@
* @return number of packets. If the statistics are not supported by this device,
* {@link #UNSUPPORTED} will be returned.
*/
- public static native long getMobileTxPackets();
+ public static long getMobileTxPackets() {
+ long total = 0;
+ for (String iface : getMobileIfaces()) {
+ total += getTxPackets(iface);
+ }
+ return total;
+ }
/**
* Get the total number of packets received through the mobile interface.
@@ -265,7 +279,13 @@
* @return number of packets. If the statistics are not supported by this device,
* {@link #UNSUPPORTED} will be returned.
*/
- public static native long getMobileRxPackets();
+ public static long getMobileRxPackets() {
+ long total = 0;
+ for (String iface : getMobileIfaces()) {
+ total += getRxPackets(iface);
+ }
+ return total;
+ }
/**
* Get the total number of bytes transmitted through the mobile interface.
@@ -273,7 +293,13 @@
* @return number of bytes. If the statistics are not supported by this device,
* {@link #UNSUPPORTED} will be returned.
*/
- public static native long getMobileTxBytes();
+ public static long getMobileTxBytes() {
+ long total = 0;
+ for (String iface : getMobileIfaces()) {
+ total += getTxBytes(iface);
+ }
+ return total;
+ }
/**
* Get the total number of bytes received through the mobile interface.
@@ -281,7 +307,13 @@
* @return number of bytes. If the statistics are not supported by this device,
* {@link #UNSUPPORTED} will be returned.
*/
- public static native long getMobileRxBytes();
+ public static long getMobileRxBytes() {
+ long total = 0;
+ for (String iface : getMobileIfaces()) {
+ total += getRxBytes(iface);
+ }
+ return total;
+ }
/**
* Get the total number of packets transmitted through the specified interface.
@@ -290,7 +322,9 @@
* {@link #UNSUPPORTED} will be returned.
* @hide
*/
- public static native long getTxPackets(String iface);
+ public static long getTxPackets(String iface) {
+ return nativeGetIfaceStat(iface, TYPE_TX_PACKETS);
+ }
/**
* Get the total number of packets received through the specified interface.
@@ -299,7 +333,9 @@
* {@link #UNSUPPORTED} will be returned.
* @hide
*/
- public static native long getRxPackets(String iface);
+ public static long getRxPackets(String iface) {
+ return nativeGetIfaceStat(iface, TYPE_RX_PACKETS);
+ }
/**
* Get the total number of bytes transmitted through the specified interface.
@@ -308,7 +344,9 @@
* {@link #UNSUPPORTED} will be returned.
* @hide
*/
- public static native long getTxBytes(String iface);
+ public static long getTxBytes(String iface) {
+ return nativeGetIfaceStat(iface, TYPE_TX_BYTES);
+ }
/**
* Get the total number of bytes received through the specified interface.
@@ -317,8 +355,9 @@
* {@link #UNSUPPORTED} will be returned.
* @hide
*/
- public static native long getRxBytes(String iface);
-
+ public static long getRxBytes(String iface) {
+ return nativeGetIfaceStat(iface, TYPE_RX_BYTES);
+ }
/**
* Get the total number of packets sent through all network interfaces.
@@ -326,7 +365,9 @@
* @return the number of packets. If the statistics are not supported by this device,
* {@link #UNSUPPORTED} will be returned.
*/
- public static native long getTotalTxPackets();
+ public static long getTotalTxPackets() {
+ return nativeGetTotalStat(TYPE_TX_PACKETS);
+ }
/**
* Get the total number of packets received through all network interfaces.
@@ -334,7 +375,9 @@
* @return number of packets. If the statistics are not supported by this device,
* {@link #UNSUPPORTED} will be returned.
*/
- public static native long getTotalRxPackets();
+ public static long getTotalRxPackets() {
+ return nativeGetTotalStat(TYPE_RX_PACKETS);
+ }
/**
* Get the total number of bytes sent through all network interfaces.
@@ -342,7 +385,9 @@
* @return number of bytes. If the statistics are not supported by this device,
* {@link #UNSUPPORTED} will be returned.
*/
- public static native long getTotalTxBytes();
+ public static long getTotalTxBytes() {
+ return nativeGetTotalStat(TYPE_TX_BYTES);
+ }
/**
* Get the total number of bytes received through all network interfaces.
@@ -350,7 +395,9 @@
* @return number of bytes. If the statistics are not supported by this device,
* {@link #UNSUPPORTED} will be returned.
*/
- public static native long getTotalRxBytes();
+ public static long getTotalRxBytes() {
+ return nativeGetTotalStat(TYPE_RX_BYTES);
+ }
/**
* Get the number of bytes sent through the network for this UID.
@@ -483,7 +530,6 @@
*/
public static native long getUidTcpRxSegments(int uid);
-
/**
* Get the number of UDP packets sent for this UID.
* Includes DNS requests.
@@ -515,13 +561,33 @@
* special permission.
*/
private static NetworkStats getDataLayerSnapshotForUid(Context context) {
- final INetworkStatsService statsService = INetworkStatsService.Stub.asInterface(
- ServiceManager.getService(Context.NETWORK_STATS_SERVICE));
final int uid = android.os.Process.myUid();
try {
- return statsService.getDataLayerSnapshotForUid(uid);
+ return getStatsService().getDataLayerSnapshotForUid(uid);
} catch (RemoteException e) {
throw new RuntimeException(e);
}
}
+
+ /**
+ * Return set of any ifaces associated with mobile networks since boot.
+ * Interfaces are never removed from this list, so counters should always be
+ * monotonic.
+ */
+ private static String[] getMobileIfaces() {
+ try {
+ return getStatsService().getMobileIfaces();
+ } catch (RemoteException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ // NOTE: keep these in sync with android_net_TrafficStats.cpp
+ private static final int TYPE_RX_BYTES = 0;
+ private static final int TYPE_RX_PACKETS = 1;
+ private static final int TYPE_TX_BYTES = 2;
+ private static final int TYPE_TX_PACKETS = 3;
+
+ private static native long nativeGetTotalStat(int type);
+ private static native long nativeGetIfaceStat(String iface, int type);
}
diff --git a/core/java/android/net/nsd/DnsSdServiceInfo.java b/core/java/android/net/nsd/DnsSdServiceInfo.java
index 33c3eb9..66abd3a 100644
--- a/core/java/android/net/nsd/DnsSdServiceInfo.java
+++ b/core/java/android/net/nsd/DnsSdServiceInfo.java
@@ -22,8 +22,8 @@
import java.net.InetAddress;
/**
- * Defines a service based on DNS service discovery
- * {@hide}
+ * A class representing service information for network service discovery
+ * {@see NsdManager}
*/
public class DnsSdServiceInfo implements NetworkServiceInfo, Parcelable {
@@ -40,56 +40,63 @@
public DnsSdServiceInfo() {
}
+ /** @hide */
public DnsSdServiceInfo(String sn, String rt, DnsSdTxtRecord tr) {
mServiceName = sn;
mServiceType = rt;
mTxtRecord = tr;
}
+ /** Get the service name */
@Override
- /** @hide */
public String getServiceName() {
return mServiceName;
}
+ /** Set the service name */
@Override
- /** @hide */
public void setServiceName(String s) {
mServiceName = s;
}
+ /** Get the service type */
@Override
- /** @hide */
public String getServiceType() {
return mServiceType;
}
+ /** Set the service type */
@Override
- /** @hide */
public void setServiceType(String s) {
mServiceType = s;
}
+ /** @hide */
public DnsSdTxtRecord getTxtRecord() {
return mTxtRecord;
}
+ /** @hide */
public void setTxtRecord(DnsSdTxtRecord t) {
mTxtRecord = new DnsSdTxtRecord(t);
}
+ /** Get the host address. The host address is valid for a resolved service. */
public InetAddress getHost() {
return mHost;
}
+ /** Set the host address */
public void setHost(InetAddress s) {
mHost = s;
}
+ /** Get port number. The port number is valid for a resolved service. */
public int getPort() {
return mPort;
}
+ /** Set port number */
public void setPort(int p) {
mPort = p;
}
@@ -147,5 +154,4 @@
return new DnsSdServiceInfo[size];
}
};
-
}
diff --git a/core/java/android/net/nsd/DnsSdTxtRecord.java b/core/java/android/net/nsd/DnsSdTxtRecord.java
index 952e02f..ccb9a91 100644
--- a/core/java/android/net/nsd/DnsSdTxtRecord.java
+++ b/core/java/android/net/nsd/DnsSdTxtRecord.java
@@ -37,7 +37,6 @@
* The DnsSdTxtRecord object stores the entire TXT data as a single byte array, traversing it
* as need be to implement its various methods.
*
- * @hide
*/
public class DnsSdTxtRecord implements Parcelable {
private static final byte mSeperator = '=';
diff --git a/core/java/android/net/nsd/NsdManager.java b/core/java/android/net/nsd/NsdManager.java
index 505f11b..dac8d20 100644
--- a/core/java/android/net/nsd/NsdManager.java
+++ b/core/java/android/net/nsd/NsdManager.java
@@ -24,29 +24,110 @@
import android.os.Message;
import android.os.RemoteException;
import android.os.Messenger;
+import android.text.TextUtils;
import android.util.Log;
import com.android.internal.util.AsyncChannel;
import com.android.internal.util.Protocol;
/**
- * The Network Service Discovery Manager class provides the API for service
- * discovery. Service discovery enables applications to discover and connect with services
- * on a network. Example applications include a game application discovering another instance
- * of the game application or a printer application discovering other printers on a network.
+ * The Network Service Discovery Manager class provides the API to discover services
+ * on a network. As an example, if device A and device B are connected over a Wi-Fi
+ * network, a game registered on device A can be discovered by a game on device
+ * B. Another example use case is an application discovering printers on the network.
+ *
+ * <p> The API currently supports DNS based service discovery and discovery is currently
+ * limited to a local network over Multicast DNS. In future, it will be extended to
+ * support wide area discovery and other service discovery mechanisms.
+ * DNS service discovery is described at http://files.dns-sd.org/draft-cheshire-dnsext-dns-sd.txt
*
* <p> The API is asynchronous and responses to requests from an application are on listener
- * callbacks provided by the application. The application needs to do an initialization with
- * {@link #initialize} before doing any operation.
+ * callbacks provided by the application. The application must invoke {@link #initialize} before
+ * doing any other operation.
*
- * <p> Android currently supports DNS based service discovery and it is limited to a local
- * network with the use of multicast DNS. In future, this class will be
- * extended to support other service discovery mechanisms.
+ * <p> There are three main operations the API supports - registration, discovery and resolution.
+ * <pre>
+ * Application start
+ * |
+ * | <----------------------------------------------
+ * initialize() |
+ * | |
+ * | Wait until channel connects |
+ * | before doing any operation |
+ * | |
+ * onChannelConnected() __________ |
+ * | | |
+ * | | |
+ * | onServiceRegistered() | |
+ * Register any local services / | |
+ * to be advertised with \ | | If application needs to
+ * registerService() onFailure() | | do any further operations
+ * | | | again, it needs to
+ * | | | initialize() connection
+ * discoverServices() | | to framework again
+ * | | |
+ * Maintain a list to track | |
+ * discovered services | |
+ * | | |
+ * |---------> |-> onChannelDisconnected()
+ * | | |
+ * | onServiceFound() |
+ * | | |
+ * | add service to list |
+ * | | |
+ * |<---------- |
+ * | |
+ * |---------> |
+ * | | |
+ * | onServiceLost() |
+ * | | |
+ * | remove service from list |
+ * | | |
+ * |<---------- |
+ * | |
+ * | |
+ * | Connect to a service |
+ * | from list ? |
+ * | |
+ * resolveService() |
+ * | |
+ * onServiceResolved() |
+ * | |
+ * Establish connection to service |
+ * with the host and port information |
+ * | |
+ * | ___________|
+ * deinitialize()
+ * when done with all operations
+ * or before quit
+ *
+ * </pre>
+ * An application that needs to advertise itself over a network for other applications to
+ * discover it can do so with a call to {@link #registerService}. If Example is a http based
+ * application that can provide HTML data to peer services, it can register a name "Example"
+ * with service type "_http._tcp". A successful registration is notified with a callback to
+ * {@link DnsSdRegisterListener#onServiceRegistered} and a failure to register is notified
+ * over {@link DnsSdRegisterListener#onFailure}
+ *
+ * <p> A peer application looking for http services can initiate a discovery for "_http._tcp"
+ * with a call to {@link #discoverServices}. A service found is notified with a callback
+ * to {@link DnsSdDiscoveryListener#onServiceFound} and a service lost is notified on
+ * {@link DnsSdDiscoveryListener#onServiceLost}.
+ *
+ * <p> Once the peer application discovers the "Example" http srevice, and needs to receive data
+ * from the "Example" application, it can initiate a resolve with {@link #resolveService} to
+ * resolve the host and port details for the purpose of establishing a connection. A successful
+ * resolve is notified on {@link DnsSdResolveListener#onServiceResolved} and a failure is notified
+ * on {@link DnsSdResolveListener#onFailure}.
+ *
+ * Applications can reserve for a service type at
+ * http://www.iana.org/form/ports-service. Existing services can be found at
+ * http://www.iana.org/assignments/service-names-port-numbers/service-names-port-numbers.xml
*
* Get an instance of this class by calling {@link android.content.Context#getSystemService(String)
* Context.getSystemService(Context.NSD_SERVICE)}.
- * @hide
*
+ * {@see DnsSdServiceInfo}
*/
public class NsdManager {
private static final String TAG = "NsdManager";
@@ -80,27 +161,32 @@
public static final int REGISTER_SERVICE_SUCCEEDED = BASE + 11;
/** @hide */
- public static final int UPDATE_SERVICE = BASE + 12;
+ public static final int UNREGISTER_SERVICE = BASE + 12;
/** @hide */
- public static final int UPDATE_SERVICE_FAILED = BASE + 13;
+ public static final int UNREGISTER_SERVICE_FAILED = BASE + 13;
/** @hide */
- public static final int UPDATE_SERVICE_SUCCEEDED = BASE + 14;
+ public static final int UNREGISTER_SERVICE_SUCCEEDED = BASE + 14;
/** @hide */
- public static final int RESOLVE_SERVICE = BASE + 15;
+ public static final int UPDATE_SERVICE = BASE + 15;
/** @hide */
- public static final int RESOLVE_SERVICE_FAILED = BASE + 16;
+ public static final int UPDATE_SERVICE_FAILED = BASE + 16;
/** @hide */
- public static final int RESOLVE_SERVICE_SUCCEEDED = BASE + 17;
+ public static final int UPDATE_SERVICE_SUCCEEDED = BASE + 17;
/** @hide */
- public static final int STOP_RESOLVE = BASE + 18;
+ public static final int RESOLVE_SERVICE = BASE + 18;
/** @hide */
- public static final int STOP_RESOLVE_FAILED = BASE + 19;
+ public static final int RESOLVE_SERVICE_FAILED = BASE + 19;
/** @hide */
- public static final int STOP_RESOLVE_SUCCEEDED = BASE + 20;
+ public static final int RESOLVE_SERVICE_SUCCEEDED = BASE + 20;
-
+ /** @hide */
+ public static final int STOP_RESOLVE = BASE + 21;
+ /** @hide */
+ public static final int STOP_RESOLVE_FAILED = BASE + 22;
+ /** @hide */
+ public static final int STOP_RESOLVE_SUCCEEDED = BASE + 23;
/**
* Create a new Nsd instance. Applications use
@@ -115,36 +201,44 @@
}
/**
+ * Passed with onFailure() calls.
* Indicates that the operation failed due to an internal error.
*/
public static final int ERROR = 0;
/**
- * Indicates that the operation failed because service discovery is unsupported on the device.
+ * Passed with onFailure() calls.
+ * Indicates that the operation failed because service discovery
+ * is unsupported on the device.
*/
public static final int UNSUPPORTED = 1;
/**
- * Indicates that the operation failed because the framework is busy and
- * unable to service the request.
+ * Passed with onFailure() calls.
+ * Indicates that the operation failed because the framework is
+ * busy and unable to service the request.
*/
public static final int BUSY = 2;
/**
+ * Passed with onFailure() calls.
* Indicates that the operation failed because it is already active.
*/
public static final int ALREADY_ACTIVE = 3;
/**
+ * Passed with onFailure() calls.
* Indicates that the operation failed because maximum limit on
* service registrations has reached.
*/
public static final int MAX_REGS_REACHED = 4;
-
-
/** Interface for callback invocation when framework channel is connected or lost */
public interface ChannelListener {
+ /**
+ * The channel to the framework is connected.
+ * Application can initiate calls into the framework using the channel instance passed.
+ */
public void onChannelConnected(Channel c);
/**
* The channel to the framework has been disconnected.
@@ -153,6 +247,7 @@
public void onChannelDisconnected();
}
+ /** Generic interface for callback invocation for a success or failure */
public interface ActionListener {
public void onFailure(int errorCode);
@@ -160,11 +255,12 @@
public void onSuccess();
}
+ /** Interface for callback invocation for service discovery */
public interface DnsSdDiscoveryListener {
public void onFailure(int errorCode);
- public void onStarted(String registrationType);
+ public void onStarted(String serviceType);
public void onServiceFound(DnsSdServiceInfo serviceInfo);
@@ -172,6 +268,7 @@
}
+ /** Interface for callback invocation for service registration */
public interface DnsSdRegisterListener {
public void onFailure(int errorCode);
@@ -179,6 +276,7 @@
public void onServiceRegistered(int registeredId, DnsSdServiceInfo serviceInfo);
}
+ /** @hide */
public interface DnsSdUpdateRegistrationListener {
public void onFailure(int errorCode);
@@ -186,6 +284,7 @@
public void onServiceUpdated(int registeredId, DnsSdTxtRecord txtRecord);
}
+ /** Interface for callback invocation for service resolution */
public interface DnsSdResolveListener {
public void onFailure(int errorCode);
@@ -208,6 +307,7 @@
private DnsSdDiscoveryListener mDnsSdDiscoveryListener;
private ActionListener mDnsSdStopDiscoveryListener;
private DnsSdRegisterListener mDnsSdRegisterListener;
+ private ActionListener mDnsSdUnregisterListener;
private DnsSdUpdateRegistrationListener mDnsSdUpdateListener;
private DnsSdResolveListener mDnsSdResolveListener;
private ActionListener mDnsSdStopResolveListener;
@@ -279,7 +379,17 @@
(DnsSdServiceInfo) message.obj);
}
break;
- case UPDATE_SERVICE_FAILED:
+ case UNREGISTER_SERVICE_FAILED:
+ if (mDnsSdUnregisterListener != null) {
+ mDnsSdUnregisterListener.onFailure(message.arg1);
+ }
+ break;
+ case UNREGISTER_SERVICE_SUCCEEDED:
+ if (mDnsSdUnregisterListener != null) {
+ mDnsSdUnregisterListener.onSuccess();
+ }
+ break;
+ case UPDATE_SERVICE_FAILED:
if (mDnsSdUpdateListener != null) {
mDnsSdUpdateListener.onFailure(message.arg1);
}
@@ -319,6 +429,10 @@
}
}
+ private static void checkChannel(Channel c) {
+ if (c == null) throw new IllegalArgumentException("Channel needs to be initialized");
+ }
+
/**
* Registers the application with the service discovery framework. This function
* must be the first to be called before any other operations are performed. No service
@@ -327,7 +441,7 @@
*
* @param srcContext is the context of the source
* @param srcLooper is the Looper on which the callbacks are receivied
- * @param listener for callback at loss of framework communication.
+ * @param listener for callback at loss of framework communication. Cannot be null.
*/
public void initialize(Context srcContext, Looper srcLooper, ChannelListener listener) {
Messenger messenger = getMessenger();
@@ -339,88 +453,142 @@
}
/**
- * Set the listener for service discovery. Can be null.
+ * Disconnects application from service discovery framework. No further operations
+ * will succeed until a {@link #initialize} is called again.
+ *
+ * @param c channel initialized with {@link #initialize}
*/
- public void setDiscoveryListener(Channel c, DnsSdDiscoveryListener b) {
- if (c == null) throw new IllegalArgumentException("Channel needs to be initialized");
- c.mDnsSdDiscoveryListener = b;
+ public void deinitialize(Channel c) {
+ checkChannel(c);
+ c.mAsyncChannel.disconnect();
}
/**
- * Set the listener for stop service discovery. Can be null.
+ * Register a service to be discovered by other services.
+ *
+ * <p> The function call immediately returns after sending a request to register service
+ * to the framework. The application is notified of a success to initiate
+ * discovery through the callback {@link DnsSdRegisterListener#onServiceRegistered} or a failure
+ * through {@link DnsSdRegisterListener#onFailure}.
+ *
+ * @param c is the channel created at {@link #initialize}
+ * @param serviceType The service type being advertised.
+ * @param port on which the service is listenering for incoming connections
+ * @param listener for success or failure callback. Can be null.
*/
- public void setStopDiscoveryListener(Channel c, ActionListener a) {
- if (c == null) throw new IllegalArgumentException("Channel needs to be initialized");
- c.mDnsSdStopDiscoveryListener = a;
- }
-
- /**
- * Set the listener for service registration. Can be null.
- */
- public void setRegisterListener(Channel c, DnsSdRegisterListener b) {
- if (c == null) throw new IllegalArgumentException("Channel needs to be initialized");
- c.mDnsSdRegisterListener = b;
- }
-
- /**
- * Set the listener for service registration. Can be null.
- */
- public void setUpdateRegistrationListener(Channel c, DnsSdUpdateRegistrationListener b) {
- if (c == null) throw new IllegalArgumentException("Channel needs to be initialized");
- c.mDnsSdUpdateListener = b;
- }
-
- /**
- * Set the listener for service resolution. Can be null.
- */
- public void setResolveListener(Channel c, DnsSdResolveListener b) {
- if (c == null) throw new IllegalArgumentException("Channel needs to be initialized");
- c.mDnsSdResolveListener = b;
- }
-
- /**
- * Set the listener for stopping service resolution. Can be null.
- */
- public void setStopResolveListener(Channel c, ActionListener b) {
- if (c == null) throw new IllegalArgumentException("Channel needs to be initialized");
- c.mDnsSdStopResolveListener = b;
- }
-
- public void registerService(Channel c, DnsSdServiceInfo serviceInfo) {
- if (c == null) throw new IllegalArgumentException("Channel needs to be initialized");
- if (serviceInfo == null) throw new IllegalArgumentException("Null serviceInfo");
+ public void registerService(Channel c, String serviceName, String serviceType, int port,
+ DnsSdRegisterListener listener) {
+ checkChannel(c);
+ if (TextUtils.isEmpty(serviceName) || TextUtils.isEmpty(serviceType)) {
+ throw new IllegalArgumentException("Service name or type cannot be empty");
+ }
+ if (port <= 0) {
+ throw new IllegalArgumentException("Invalid port number");
+ }
+ DnsSdServiceInfo serviceInfo = new DnsSdServiceInfo(serviceName, serviceType, null);
+ serviceInfo.setPort(port);
+ c.mDnsSdRegisterListener = listener;
c.mAsyncChannel.sendMessage(REGISTER_SERVICE, serviceInfo);
}
+ /**
+ * Unregister a service registered through {@link #registerService}
+ * @param c is the channel created at {@link #initialize}
+ * @param registeredId is obtained at {@link DnsSdRegisterListener#onServiceRegistered}
+ * @param listener provides callbacks for success or failure. Can be null.
+ */
+ public void unregisterService(Channel c, int registeredId, ActionListener listener) {
+ checkChannel(c);
+ c.mDnsSdUnregisterListener = listener;
+ c.mAsyncChannel.sendMessage(UNREGISTER_SERVICE, registeredId);
+ }
+
+ /** @hide */
public void updateService(Channel c, int registeredId, DnsSdTxtRecord txtRecord) {
- if (c == null) throw new IllegalArgumentException("Channel needs to be initialized");
+ checkChannel(c);
c.mAsyncChannel.sendMessage(UPDATE_SERVICE, registeredId, 0, txtRecord);
}
- public void discoverServices(Channel c, String serviceType) {
- if (c == null) throw new IllegalArgumentException("Channel needs to be initialized");
- if (c.mDnsSdDiscoveryListener == null) throw new
- IllegalStateException("Discovery listener needs to be set first");
+ /**
+ * Initiate service discovery to browse for instances of a service type. Service discovery
+ * consumes network bandwidth and will continue until the application calls
+ * {@link #stopServiceDiscovery}.
+ *
+ * <p> The function call immediately returns after sending a request to start service
+ * discovery to the framework. The application is notified of a success to initiate
+ * discovery through the callback {@link DnsSdDiscoveryListener#onStarted} or a failure
+ * through {@link DnsSdDiscoveryListener#onFailure}.
+ *
+ * <p> Upon successful start, application is notified when a service is found with
+ * {@link DnsSdDiscoveryListener#onServiceFound} or when a service is lost with
+ * {@link DnsSdDiscoveryListener#onServiceLost}.
+ *
+ * <p> Upon failure to start, service discovery is not active and application does
+ * not need to invoke {@link #stopServiceDiscovery}
+ *
+ * @param c is the channel created at {@link #initialize}
+ * @param serviceType The service type being discovered. Examples include "_http._tcp" for
+ * http services or "_ipp._tcp" for printers
+ * @param listener provides callbacks when service is found or lost. Cannot be null.
+ */
+ public void discoverServices(Channel c, String serviceType, DnsSdDiscoveryListener listener) {
+ checkChannel(c);
+ if (listener == null) {
+ throw new IllegalStateException("Discovery listener needs to be set first");
+ }
+ if (TextUtils.isEmpty(serviceType)) {
+ throw new IllegalStateException("Service type cannot be empty");
+ }
DnsSdServiceInfo s = new DnsSdServiceInfo();
s.setServiceType(serviceType);
+ c.mDnsSdDiscoveryListener = listener;
c.mAsyncChannel.sendMessage(DISCOVER_SERVICES, s);
}
- public void stopServiceDiscovery(Channel c) {
- if (c == null) throw new IllegalArgumentException("Channel needs to be initialized");
+ /**
+ * Stop service discovery initiated with {@link #discoverServices}. An active service
+ * discovery is notified to the application with {@link DnsSdDiscoveryListener#onStarted}
+ * and it stays active until the application invokes a stop service discovery.
+ *
+ * <p> Upon failure to start service discovery notified through
+ * {@link DnsSdDiscoveryListener#onFailure} service discovery is not active and
+ * application does not need to stop it.
+ *
+ * @param c is the channel created at {@link #initialize}
+ * @param listener notifies success or failure. Can be null.
+ */
+ public void stopServiceDiscovery(Channel c, ActionListener listener) {
+ checkChannel(c);
+ c.mDnsSdStopDiscoveryListener = listener;
c.mAsyncChannel.sendMessage(STOP_DISCOVERY);
}
- public void resolveService(Channel c, DnsSdServiceInfo serviceInfo) {
- if (c == null) throw new IllegalArgumentException("Channel needs to be initialized");
- if (serviceInfo == null) throw new IllegalArgumentException("Null serviceInfo");
- if (c.mDnsSdResolveListener == null) throw new
- IllegalStateException("Resolve listener needs to be set first");
+ /**
+ * Resolve a discovered service. An application can resolve a service right before
+ * establishing a connection to fetch the IP and port details on which to setup
+ * the connection.
+ *
+ * @param c is the channel created at {@link #initialize}
+ * @param serviceName of the the service
+ * @param serviceType of the service
+ * @param listener to receive callback upon success or failure. Cannot be null.
+ */
+ public void resolveService(Channel c, String serviceName, String serviceType,
+ DnsSdResolveListener listener) {
+ checkChannel(c);
+ if (TextUtils.isEmpty(serviceName) || TextUtils.isEmpty(serviceType)) {
+ throw new IllegalArgumentException("Service name or type cannot be empty");
+ }
+ if (listener == null) throw new
+ IllegalStateException("Resolve listener cannot be null");
+ c.mDnsSdResolveListener = listener;
+ DnsSdServiceInfo serviceInfo = new DnsSdServiceInfo(serviceName, serviceType, null);
c.mAsyncChannel.sendMessage(RESOLVE_SERVICE, serviceInfo);
}
+ /** @hide */
public void stopServiceResolve(Channel c) {
- if (c == null) throw new IllegalArgumentException("Channel needs to be initialized");
+ checkChannel(c);
if (c.mDnsSdResolveListener == null) throw new
IllegalStateException("Resolve listener needs to be set first");
c.mAsyncChannel.sendMessage(STOP_RESOLVE);
diff --git a/core/java/android/os/Debug.java b/core/java/android/os/Debug.java
index 20a731e..98fe06a 100644
--- a/core/java/android/os/Debug.java
+++ b/core/java/android/os/Debug.java
@@ -1324,4 +1324,42 @@
return false;
}
}
+
+ /**
+ * Return a String describing the calling method and location at a particular stack depth.
+ * @param callStack the Thread stack
+ * @param depth the depth of stack to return information for.
+ * @return the String describing the caller at that depth.
+ */
+ private static String getCaller(StackTraceElement callStack[], int depth) {
+ // callStack[4] is the caller of the method that called getCallers()
+ if (4 + depth >= callStack.length) {
+ return "<bottom of call stack>";
+ }
+ StackTraceElement caller = callStack[4 + depth];
+ return caller.getClassName() + "." + caller.getMethodName() + ":" + caller.getLineNumber();
+ }
+
+ /**
+ * Return a string consisting of methods and locations at multiple call stack levels.
+ * @param depth the number of levels to return, starting with the immediate caller.
+ * @return a string describing the call stack.
+ * {@hide}
+ */
+ public static String getCallers(final int depth) {
+ final StackTraceElement[] callStack = Thread.currentThread().getStackTrace();
+ StringBuffer sb = new StringBuffer();
+ for (int i = 0; i < depth; i++) {
+ sb.append(getCaller(callStack, i)).append(" ");
+ }
+ return sb.toString();
+ }
+
+ /**
+ * @return a String describing the immediate caller of the calling function.
+ * {@hide}
+ */
+ public static String getCaller() {
+ return getCaller(Thread.currentThread().getStackTrace(), 0);
+ }
}
diff --git a/core/java/android/os/Environment.java b/core/java/android/os/Environment.java
index 11f9445..f7f0263 100644
--- a/core/java/android/os/Environment.java
+++ b/core/java/android/os/Environment.java
@@ -113,19 +113,16 @@
= getDirectory("ANDROID_SECURE_DATA", "/data/secure");
private static final File EXTERNAL_STORAGE_DIRECTORY
- = getDirectory("EXTERNAL_STORAGE", "/mnt/sdcard");
+ = getDirectory("EXTERNAL_STORAGE", "/storage/sdcard0");
- private static final File EXTERNAL_STORAGE_ANDROID_DATA_DIRECTORY
- = new File (new File(getDirectory("EXTERNAL_STORAGE", "/mnt/sdcard"),
- "Android"), "data");
+ private static final File EXTERNAL_STORAGE_ANDROID_DATA_DIRECTORY = new File(new File(
+ getDirectory("EXTERNAL_STORAGE", "/storage/sdcard0"), "Android"), "data");
- private static final File EXTERNAL_STORAGE_ANDROID_MEDIA_DIRECTORY
- = new File (new File(getDirectory("EXTERNAL_STORAGE", "/mnt/sdcard"),
- "Android"), "media");
+ private static final File EXTERNAL_STORAGE_ANDROID_MEDIA_DIRECTORY = new File(new File(
+ getDirectory("EXTERNAL_STORAGE", "/storage/sdcard0"), "Android"), "media");
- private static final File EXTERNAL_STORAGE_ANDROID_OBB_DIRECTORY
- = new File (new File(getDirectory("EXTERNAL_STORAGE", "/mnt/sdcard"),
- "Android"), "obb");
+ private static final File EXTERNAL_STORAGE_ANDROID_OBB_DIRECTORY = new File(new File(
+ getDirectory("EXTERNAL_STORAGE", "/storage/sdcard0"), "Android"), "obb");
private static final File DOWNLOAD_CACHE_DIRECTORY
= getDirectory("DOWNLOAD_CACHE", "/cache");
diff --git a/core/java/android/os/Trace.java b/core/java/android/os/Trace.java
index af94a37..4645fab 100644
--- a/core/java/android/os/Trace.java
+++ b/core/java/android/os/Trace.java
@@ -33,6 +33,7 @@
public static final long TRACE_TAG_GRAPHICS = 1L << 1;
public static final long TRACE_TAG_INPUT = 1L << 2;
public static final long TRACE_TAG_VIEW = 1L << 3;
+ public static final long TRACE_TAG_WEBVIEW = 1L << 4;
private static final long sEnabledTags = nativeGetEnabledTags();
diff --git a/core/java/android/provider/CalendarContract.java b/core/java/android/provider/CalendarContract.java
index 83799c4..c4aa691 100644
--- a/core/java/android/provider/CalendarContract.java
+++ b/core/java/android/provider/CalendarContract.java
@@ -756,6 +756,22 @@
public static final int ATTENDEE_STATUS_DECLINED = 2;
public static final int ATTENDEE_STATUS_INVITED = 3;
public static final int ATTENDEE_STATUS_TENTATIVE = 4;
+
+ /**
+ * The identity of the attendee as referenced in
+ * {@link ContactsContract.CommonDataKinds.Identity#IDENTITY}.
+ * This is required only if {@link #ATTENDEE_ID_NAMESPACE} is present. Column name.
+ * <P>Type: STRING</P>
+ */
+ public static final String ATTENDEE_IDENTITY = "attendeeIdentity";
+
+ /**
+ * The identity name space of the attendee as referenced in
+ * {@link ContactsContract.CommonDataKinds.Identity#NAMESPACE}.
+ * This is required only if {@link #ATTENDEE_IDENTITY} is present. Column name.
+ * <P>Type: STRING</P>
+ */
+ public static final String ATTENDEE_ID_NAMESPACE = "attendeeIdNamespace";
}
/**
@@ -773,6 +789,8 @@
* <li>{@link #ATTENDEE_RELATIONSHIP}</li>
* <li>{@link #ATTENDEE_TYPE}</li>
* <li>{@link #ATTENDEE_STATUS}</li>
+ * <li>{@link #ATTENDEE_IDENTITY}</li>
+ * <li>{@link #ATTENDEE_ID_NAMESPACE}</li>
* </ul>
*/
public static final class Attendees implements BaseColumns, AttendeesColumns, EventsColumns {
@@ -1221,12 +1239,17 @@
Attendees.ATTENDEE_RELATIONSHIP,
Attendees.ATTENDEE_TYPE,
Attendees.ATTENDEE_STATUS,
+ Attendees.ATTENDEE_IDENTITY,
+ Attendees.ATTENDEE_ID_NAMESPACE
};
private static final int COLUMN_ATTENDEE_NAME = 0;
private static final int COLUMN_ATTENDEE_EMAIL = 1;
private static final int COLUMN_ATTENDEE_RELATIONSHIP = 2;
private static final int COLUMN_ATTENDEE_TYPE = 3;
private static final int COLUMN_ATTENDEE_STATUS = 4;
+ private static final int COLUMN_ATTENDEE_IDENTITY = 5;
+ private static final int COLUMN_ATTENDEE_ID_NAMESPACE = 6;
+
private static final String[] EXTENDED_PROJECTION = new String[] {
ExtendedProperties._ID,
ExtendedProperties.NAME,
@@ -1362,6 +1385,10 @@
subCursor.getInt(COLUMN_ATTENDEE_TYPE));
attendeeValues.put(Attendees.ATTENDEE_STATUS,
subCursor.getInt(COLUMN_ATTENDEE_STATUS));
+ attendeeValues.put(Attendees.ATTENDEE_IDENTITY,
+ subCursor.getInt(COLUMN_ATTENDEE_IDENTITY));
+ attendeeValues.put(Attendees.ATTENDEE_ID_NAMESPACE,
+ subCursor.getInt(COLUMN_ATTENDEE_ID_NAMESPACE));
entity.addSubValue(Attendees.CONTENT_URI, attendeeValues);
}
} finally {
diff --git a/core/java/android/provider/Downloads.java b/core/java/android/provider/Downloads.java
index cd8d51f..31ad12b 100644
--- a/core/java/android/provider/Downloads.java
+++ b/core/java/android/provider/Downloads.java
@@ -329,6 +329,14 @@
public static final String COLUMN_IS_PUBLIC_API = "is_public_api";
/**
+ * The name of the column holding a bitmask of allowed network types. This is only used for
+ * public API downloads.
+ * <P>Type: INTEGER</P>
+ * <P>Owner can Init/Read</P>
+ */
+ public static final String COLUMN_ALLOWED_NETWORK_TYPES = "allowed_network_types";
+
+ /**
* The name of the column indicating whether roaming connections can be used. This is only
* used for public API downloads.
* <P>Type: BOOLEAN</P>
@@ -337,12 +345,12 @@
public static final String COLUMN_ALLOW_ROAMING = "allow_roaming";
/**
- * The name of the column holding a bitmask of allowed network types. This is only used for
- * public API downloads.
- * <P>Type: INTEGER</P>
+ * The name of the column indicating whether metered connections can be used. This is only
+ * used for public API downloads.
+ * <P>Type: BOOLEAN</P>
* <P>Owner can Init/Read</P>
*/
- public static final String COLUMN_ALLOWED_NETWORK_TYPES = "allowed_network_types";
+ public static final String COLUMN_ALLOW_METERED = "allow_metered";
/**
* Whether or not this download should be displayed in the system's Downloads UI. Defaults
@@ -701,7 +709,10 @@
* blocked by {@link NetworkPolicyManager}.
*
* @hide
+ * @deprecated since behavior now uses
+ * {@link #STATUS_WAITING_FOR_NETWORK}
*/
+ @Deprecated
public static final int STATUS_BLOCKED = 498;
/** {@hide} */
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 2aaf548..6dfbb2f 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -1464,6 +1464,20 @@
public static final String VIBRATE_ON = "vibrate_on";
/**
+ * If 1, redirects the system vibrator to all currently attached input devices
+ * that support vibration. If there are no such input devices, then the system
+ * vibrator is used instead.
+ * If 0, does not register the system vibrator.
+ *
+ * This setting is mainly intended to provide a compatibility mechanism for
+ * applications that only know about the system vibrator and do not use the
+ * input device vibrator API.
+ *
+ * @hide
+ */
+ public static final String VIBRATE_INPUT_DEVICES = "vibrate_input_devices";
+
+ /**
* Ringer volume. This is used internally, changing this value will not
* change the volume. See AudioManager.
*/
@@ -1970,6 +1984,7 @@
SCREEN_BRIGHTNESS_MODE,
SCREEN_AUTO_BRIGHTNESS_ADJ,
VIBRATE_ON,
+ VIBRATE_INPUT_DEVICES,
MODE_RINGER,
MODE_RINGER_STREAMS_AFFECTED,
MUTE_STREAMS_AFFECTED,
diff --git a/core/java/android/server/BluetoothService.java b/core/java/android/server/BluetoothService.java
index 850349b..36c0189 100755
--- a/core/java/android/server/BluetoothService.java
+++ b/core/java/android/server/BluetoothService.java
@@ -611,6 +611,11 @@
/*package*/ void initBluetoothAfterTurningOn() {
String discoverable = getProperty("Discoverable", false);
String timeout = getProperty("DiscoverableTimeout", false);
+ if (timeout == null) {
+ Log.w(TAG, "Null DiscoverableTimeout property");
+ // assign a number, anything not 0
+ timeout = "1";
+ }
if (discoverable.equals("true") && Integer.valueOf(timeout) != 0) {
setAdapterPropertyBooleanNative("Discoverable", 0);
}
diff --git a/core/java/android/service/textservice/SpellCheckerService.java b/core/java/android/service/textservice/SpellCheckerService.java
index 53ce32d..c579e6e 100644
--- a/core/java/android/service/textservice/SpellCheckerService.java
+++ b/core/java/android/service/textservice/SpellCheckerService.java
@@ -26,12 +26,18 @@
import android.os.IBinder;
import android.os.Process;
import android.os.RemoteException;
+import android.text.TextUtils;
+import android.text.method.WordIterator;
import android.util.Log;
import android.view.textservice.SentenceSuggestionsInfo;
import android.view.textservice.SuggestionsInfo;
import android.view.textservice.TextInfo;
+import android.widget.SpellChecker;
import java.lang.ref.WeakReference;
+import java.text.BreakIterator;
+import java.util.ArrayList;
+import java.util.Locale;
/**
* SpellCheckerService provides an abstract base class for a spell checker.
@@ -92,6 +98,7 @@
*/
public static abstract class Session {
private InternalISpellCheckerSession mInternalSession;
+ private volatile SentenceLevelAdapter mSentenceLevelAdapter;
/**
* @hide
@@ -142,8 +149,8 @@
/**
* Get sentence suggestions for specified texts in an array of TextInfo.
- * The default implementation returns an array of SentenceSuggestionsInfo by simply
- * calling onGetSuggestions.
+ * The default implementation splits the input text to words and returns
+ * {@link SentenceSuggestionsInfo} which contains suggestions for each word.
* This function will run on the incoming IPC thread.
* So, this is not called on the main thread,
* but will be called in series on another thread.
@@ -156,14 +163,41 @@
*/
public SentenceSuggestionsInfo[] onGetSentenceSuggestionsMultiple(TextInfo[] textInfos,
int suggestionsLimit) {
- final int length = textInfos.length;
- final SentenceSuggestionsInfo[] retval = new SentenceSuggestionsInfo[length];
- for (int i = 0; i < length; ++i) {
- final SuggestionsInfo si = onGetSuggestions(textInfos[i], suggestionsLimit);
- si.setCookieAndSequence(textInfos[i].getCookie(), textInfos[i].getSequence());
- final int N = textInfos[i].getText().length();
- retval[i] = new SentenceSuggestionsInfo(
- new SuggestionsInfo[] {si}, new int[]{0}, new int[]{N});
+ if (textInfos == null || textInfos.length == 0) {
+ return SentenceLevelAdapter.EMPTY_SENTENCE_SUGGESTIONS_INFOS;
+ }
+ if (DBG) {
+ Log.d(TAG, "onGetSentenceSuggestionsMultiple: + " + textInfos.length + ", "
+ + suggestionsLimit);
+ }
+ if (mSentenceLevelAdapter == null) {
+ synchronized(this) {
+ if (mSentenceLevelAdapter == null) {
+ final String localeStr = getLocale();
+ if (!TextUtils.isEmpty(localeStr)) {
+ mSentenceLevelAdapter = new SentenceLevelAdapter(new Locale(localeStr));
+ }
+ }
+ }
+ }
+ if (mSentenceLevelAdapter == null) {
+ return SentenceLevelAdapter.EMPTY_SENTENCE_SUGGESTIONS_INFOS;
+ }
+ final int infosSize = textInfos.length;
+ final SentenceSuggestionsInfo[] retval = new SentenceSuggestionsInfo[infosSize];
+ for (int i = 0; i < infosSize; ++i) {
+ final SentenceLevelAdapter.SentenceTextInfoParams textInfoParams =
+ mSentenceLevelAdapter.getSplitWords(textInfos[i]);
+ final ArrayList<SentenceLevelAdapter.SentenceWordItem> mItems =
+ textInfoParams.mItems;
+ final int itemsSize = mItems.size();
+ final TextInfo[] splitTextInfos = new TextInfo[itemsSize];
+ for (int j = 0; j < itemsSize; ++j) {
+ splitTextInfos[j] = mItems.get(j).mTextInfo;
+ }
+ retval[i] = SentenceLevelAdapter.reconstructSuggestions(
+ textInfoParams, onGetSuggestionsMultiple(
+ splitTextInfos, suggestionsLimit, true));
}
return retval;
}
@@ -290,4 +324,135 @@
return internalSession;
}
}
+
+ /**
+ * Adapter class to accommodate word level spell checking APIs to sentence level spell checking
+ * APIs used in
+ * {@link SpellCheckerService.Session#onGetSuggestionsMultiple(TextInfo[], int, boolean)}
+ */
+ private static class SentenceLevelAdapter {
+ public static final SentenceSuggestionsInfo[] EMPTY_SENTENCE_SUGGESTIONS_INFOS =
+ new SentenceSuggestionsInfo[] {};
+ private static final SuggestionsInfo EMPTY_SUGGESTIONS_INFO = new SuggestionsInfo(0, null);
+ /**
+ * Container for split TextInfo parameters
+ */
+ public static class SentenceWordItem {
+ public final TextInfo mTextInfo;
+ public final int mStart;
+ public final int mLength;
+ public SentenceWordItem(TextInfo ti, int start, int end) {
+ mTextInfo = ti;
+ mStart = start;
+ mLength = end - start;
+ }
+ }
+
+ /**
+ * Container for originally queried TextInfo and parameters
+ */
+ public static class SentenceTextInfoParams {
+ final TextInfo mOriginalTextInfo;
+ final ArrayList<SentenceWordItem> mItems;
+ final int mSize;
+ public SentenceTextInfoParams(TextInfo ti, ArrayList<SentenceWordItem> items) {
+ mOriginalTextInfo = ti;
+ mItems = items;
+ mSize = items.size();
+ }
+ }
+
+ private final WordIterator mWordIterator;
+ public SentenceLevelAdapter(Locale locale) {
+ mWordIterator = new WordIterator(locale);
+ }
+
+ private SentenceTextInfoParams getSplitWords(TextInfo originalTextInfo) {
+ final WordIterator wordIterator = mWordIterator;
+ final CharSequence originalText = originalTextInfo.getText();
+ final int cookie = originalTextInfo.getCookie();
+ final int start = 0;
+ final int end = originalText.length();
+ final ArrayList<SentenceWordItem> wordItems = new ArrayList<SentenceWordItem>();
+ wordIterator.setCharSequence(originalText, 0, originalText.length());
+ int wordEnd = wordIterator.following(start);
+ int wordStart = wordIterator.getBeginning(wordEnd);
+ if (DBG) {
+ Log.d(TAG, "iterator: break: ---- 1st word start = " + wordStart + ", end = "
+ + wordEnd + "\n" + originalText);
+ }
+ while (wordStart <= end && wordEnd != BreakIterator.DONE
+ && wordStart != BreakIterator.DONE) {
+ if (wordEnd >= start && wordEnd > wordStart) {
+ final String query = originalText.subSequence(wordStart, wordEnd).toString();
+ final TextInfo ti = new TextInfo(query, cookie, query.hashCode());
+ wordItems.add(new SentenceWordItem(ti, wordStart, wordEnd));
+ if (DBG) {
+ Log.d(TAG, "Adapter: word (" + (wordItems.size() - 1) + ") " + query);
+ }
+ }
+ wordEnd = wordIterator.following(wordEnd);
+ if (wordEnd == BreakIterator.DONE) {
+ break;
+ }
+ wordStart = wordIterator.getBeginning(wordEnd);
+ }
+ if (originalText.length() >= SpellChecker.WORD_ITERATOR_INTERVAL
+ && wordItems.size() >= 2) {
+ if (DBG) {
+ Log.w(TAG, "Remove possibly divided word: "
+ + wordItems.get(0).mTextInfo.getText());
+ }
+ wordItems.remove(0);
+ }
+ return new SentenceTextInfoParams(originalTextInfo, wordItems);
+ }
+
+ public static SentenceSuggestionsInfo reconstructSuggestions(
+ SentenceTextInfoParams originalTextInfoParams, SuggestionsInfo[] results) {
+ if (results == null || results.length == 0) {
+ return null;
+ }
+ if (DBG) {
+ Log.w(TAG, "Adapter: onGetSuggestions: got " + results.length);
+ }
+ if (originalTextInfoParams == null) {
+ if (DBG) {
+ Log.w(TAG, "Adapter: originalTextInfoParams is null.");
+ }
+ return null;
+ }
+ final int originalCookie = originalTextInfoParams.mOriginalTextInfo.getCookie();
+ final int originalSequence =
+ originalTextInfoParams.mOriginalTextInfo.getSequence();
+
+ final int querySize = originalTextInfoParams.mSize;
+ final int[] offsets = new int[querySize];
+ final int[] lengths = new int[querySize];
+ final SuggestionsInfo[] reconstructedSuggestions = new SuggestionsInfo[querySize];
+ for (int i = 0; i < querySize; ++i) {
+ final SentenceWordItem item = originalTextInfoParams.mItems.get(i);
+ SuggestionsInfo result = null;
+ for (int j = 0; j < results.length; ++j) {
+ final SuggestionsInfo cur = results[j];
+ if (cur != null && cur.getSequence() == item.mTextInfo.getSequence()) {
+ result = cur;
+ result.setCookieAndSequence(originalCookie, originalSequence);
+ break;
+ }
+ }
+ offsets[i] = item.mStart;
+ lengths[i] = item.mLength;
+ reconstructedSuggestions[i] = result != null ? result : EMPTY_SUGGESTIONS_INFO;
+ if (DBG) {
+ final int size = reconstructedSuggestions[i].getSuggestionsCount();
+ Log.w(TAG, "reconstructedSuggestions(" + i + ")" + size + ", first = "
+ + (size > 0 ? reconstructedSuggestions[i].getSuggestionAt(0)
+ : "<none>") + ", offset = " + offsets[i] + ", length = "
+ + lengths[i]);
+ }
+ }
+ return new SentenceSuggestionsInfo(reconstructedSuggestions, offsets, lengths);
+ }
+ }
}
diff --git a/core/java/android/view/IWindowManager.aidl b/core/java/android/view/IWindowManager.aidl
index 8fe8e40..b70d7b5 100644
--- a/core/java/android/view/IWindowManager.aidl
+++ b/core/java/android/view/IWindowManager.aidl
@@ -80,6 +80,8 @@
void prepareAppTransition(int transit, boolean alwaysKeepCurrent);
int getPendingAppTransition();
void overridePendingAppTransition(String packageName, int enterAnim, int exitAnim);
+ void overridePendingAppTransitionScaleUp(int startX, int startY, int startWidth,
+ int startHeight);
void overridePendingAppTransitionThumb(in Bitmap srcThumb, int startX, int startY,
IRemoteCallback startedCallback);
void executeAppTransition();
diff --git a/core/java/android/view/TextureView.java b/core/java/android/view/TextureView.java
index 32029ba..214dc5c 100644
--- a/core/java/android/view/TextureView.java
+++ b/core/java/android/view/TextureView.java
@@ -676,7 +676,6 @@
*
* @param surfaceTexture The {@link SurfaceTexture} that the view should use.
* @see SurfaceTexture#detachFromGLContext()
- * @hide
*/
public void setSurfaceTexture(SurfaceTexture surfaceTexture) {
if (surfaceTexture == null) {
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 500b966..2fea8ec 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -24,6 +24,7 @@
import android.graphics.Bitmap;
import android.graphics.Camera;
import android.graphics.Canvas;
+import android.graphics.Insets;
import android.graphics.Interpolator;
import android.graphics.LinearGradient;
import android.graphics.Matrix;
@@ -2698,6 +2699,12 @@
protected int mPaddingBottom;
/**
+ * The layout insets in pixels, that is the distance in pixels between the
+ * visible edges of this view its bounds.
+ */
+ private Insets mLayoutInsets;
+
+ /**
* Briefly describes the view and is primarily used for accessibility support.
*/
private CharSequence mContentDescription;
@@ -13833,6 +13840,29 @@
}
/**
+ * @hide
+ */
+ public Insets getLayoutInsets() {
+ if (mLayoutInsets == null) {
+ if (mBackground == null) {
+ mLayoutInsets = Insets.NONE;
+ } else {
+ Rect insetRect = new Rect();
+ boolean hasInsets = mBackground.getLayoutInsets(insetRect);
+ mLayoutInsets = hasInsets ? Insets.of(insetRect) : Insets.NONE;
+ }
+ }
+ return mLayoutInsets;
+ }
+
+ /**
+ * @hide
+ */
+ public void setLayoutInsets(Insets layoutInsets) {
+ mLayoutInsets = layoutInsets;
+ }
+
+ /**
* Changes the selection state of this view. A view can be selected or not.
* Note that selection is not the same as focus. Views are typically
* selected in the context of an AdapterView like ListView or GridView;
diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java
index 30ea766..91e945b 100644
--- a/core/java/android/view/ViewGroup.java
+++ b/core/java/android/view/ViewGroup.java
@@ -170,6 +170,12 @@
*/
protected int mGroupFlags;
+ /*
+ * THe layout mode: either {@link #UNDEFINED_LAYOUT_MODE}, {@link #COMPONENT_BOUNDS} or
+ * {@link #LAYOUT_BOUNDS}
+ */
+ private int mLayoutMode = UNDEFINED_LAYOUT_MODE;
+
/**
* NOTE: If you change the flags below make sure to reflect the changes
* the DisplayList class
@@ -335,6 +341,22 @@
*/
public static final int PERSISTENT_ALL_CACHES = 0x3;
+ // Layout Modes
+
+ private static final int UNDEFINED_LAYOUT_MODE = -1;
+
+ /**
+ * This constant is a {@link #setLayoutMode(int) layoutMode}.
+ * Component bounds are the raw values of {@link #getLeft() left}, {@link #getTop() top},
+ * {@link #getRight() right} and {@link #getBottom() bottom}.
+ */
+ public static final int COMPONENT_BOUNDS = 0;
+
+ /**
+ * This constant is a {@link #setLayoutMode(int) layoutMode}.
+ */
+ public static final int LAYOUT_BOUNDS = 1;
+
/**
* We clip to padding when FLAG_CLIP_TO_PADDING and FLAG_PADDING_NOT_NULL
* are set at the same time.
@@ -4185,6 +4207,9 @@
@Override
public final void layout(int l, int t, int r, int b) {
if (mTransition == null || !mTransition.isChangingLayout()) {
+ if (mTransition != null) {
+ mTransition.layoutChange(this);
+ }
super.layout(l, t, r, b);
} else {
// record the fact that we noop'd it; request layout when transition finishes
@@ -4424,6 +4449,50 @@
}
/**
+ * Returns the basis of alignment during the layout of this view group:
+ * either {@link #COMPONENT_BOUNDS} or {@link #LAYOUT_BOUNDS}.
+ *
+ * @return the layout mode to use during layout operations
+ *
+ * @see #setLayoutMode(int)
+ */
+ public int getLayoutMode() {
+ if (mLayoutMode == UNDEFINED_LAYOUT_MODE) {
+ ViewParent parent = getParent();
+ if (parent instanceof ViewGroup) {
+ ViewGroup viewGroup = (ViewGroup) parent;
+ return viewGroup.getLayoutMode();
+ } else {
+ int targetSdkVersion = mContext.getApplicationInfo().targetSdkVersion;
+ boolean preJellyBean = targetSdkVersion < Build.VERSION_CODES.JELLY_BEAN;
+ return preJellyBean ? COMPONENT_BOUNDS : LAYOUT_BOUNDS;
+ }
+
+ }
+ return mLayoutMode;
+ }
+
+ /**
+ * Sets the basis of alignment during alignment of this view group.
+ * Valid values are either {@link #COMPONENT_BOUNDS} or {@link #LAYOUT_BOUNDS}.
+ * <p>
+ * The default is to query the property of the parent if this view group has a parent.
+ * If this ViewGroup is the root of the view hierarchy the default
+ * value is {@link #LAYOUT_BOUNDS} for target SDK's greater than JellyBean,
+ * {@link #LAYOUT_BOUNDS} otherwise.
+ *
+ * @param layoutMode the layout mode to use during layout operations
+ *
+ * @see #getLayoutMode()
+ */
+ public void setLayoutMode(int layoutMode) {
+ if (mLayoutMode != layoutMode) {
+ mLayoutMode = layoutMode;
+ requestLayout();
+ }
+ }
+
+ /**
* Returns a new set of layout parameters based on the supplied attributes set.
*
* @param attrs the attributes to build the layout parameters from
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index a1e33ac..3d40b2f 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -2983,7 +2983,10 @@
// be when the window is first being added, and mFocused isn't
// set yet.
final View focused = mView.findFocus();
- if (focused != null && !focused.isFocusableInTouchMode()) {
+ if (focused != null) {
+ if (focused.isFocusableInTouchMode()) {
+ return true;
+ }
final ViewGroup ancestorToTakeFocus =
findAncestorToTakeFocusInTouchMode(focused);
if (ancestorToTakeFocus != null) {
diff --git a/core/java/android/view/textservice/SpellCheckerInfo.java b/core/java/android/view/textservice/SpellCheckerInfo.java
index d05c1af..2167862 100644
--- a/core/java/android/view/textservice/SpellCheckerInfo.java
+++ b/core/java/android/view/textservice/SpellCheckerInfo.java
@@ -45,7 +45,6 @@
private final ResolveInfo mService;
private final String mId;
private final int mLabel;
- private final boolean mSupportsSentenceSpellCheck;
/**
* The spell checker setting activity's name, used by the system settings to
@@ -98,9 +97,6 @@
label = sa.getResourceId(com.android.internal.R.styleable.SpellChecker_label, 0);
settingsActivityComponent = sa.getString(
com.android.internal.R.styleable.SpellChecker_settingsActivity);
- mSupportsSentenceSpellCheck = sa.getBoolean(
- com.android.internal.R.styleable.SpellChecker_supportsSentenceSpellCheck,
- false);
sa.recycle();
final int depth = parser.getDepth();
@@ -142,7 +138,6 @@
*/
public SpellCheckerInfo(Parcel source) {
mLabel = source.readInt();
- mSupportsSentenceSpellCheck = source.readInt() != 0;
mId = source.readString();
mSettingsActivityName = source.readString();
mService = ResolveInfo.CREATOR.createFromParcel(source);
@@ -158,13 +153,6 @@
}
/**
- * @hide
- */
- public boolean isSentenceSpellCheckSupported() {
- return mSupportsSentenceSpellCheck;
- }
-
- /**
* Return the component of the service that implements.
*/
public ComponentName getComponent() {
@@ -188,7 +176,6 @@
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeInt(mLabel);
- dest.writeInt(mSupportsSentenceSpellCheck ? 1 : 0);
dest.writeString(mId);
dest.writeString(mSettingsActivityName);
mService.writeToParcel(dest, flags);
diff --git a/core/java/android/view/textservice/SpellCheckerSession.java b/core/java/android/view/textservice/SpellCheckerSession.java
index 9dc05e4..628da3c 100644
--- a/core/java/android/view/textservice/SpellCheckerSession.java
+++ b/core/java/android/view/textservice/SpellCheckerSession.java
@@ -91,8 +91,6 @@
* This meta-data must reference an XML resource.
**/
public static final String SERVICE_META_DATA = "android.view.textservice.scs";
- private static final String SUPPORT_SENTENCE_SPELL_CHECK = "SupportSentenceSpellCheck";
-
private static final int MSG_ON_GET_SUGGESTION_MULTIPLE = 1;
private static final int MSG_ON_GET_SUGGESTION_MULTIPLE_FOR_SENTENCE = 2;
@@ -191,7 +189,9 @@
* Get candidate strings for a substring of the specified text.
* @param textInfo text metadata for a spell checker
* @param suggestionsLimit the maximum number of suggestions that will be returned
+ * @deprecated use {@link SpellCheckerSession#getSentenceSuggestions(TextInfo[], int)} instead
*/
+ @Deprecated
public void getSuggestions(TextInfo textInfo, int suggestionsLimit) {
getSuggestions(new TextInfo[] {textInfo}, suggestionsLimit, false);
}
@@ -201,13 +201,14 @@
* @param textInfos an array of text metadata for a spell checker
* @param suggestionsLimit the maximum number of suggestions that will be returned
* @param sequentialWords true if textInfos can be treated as sequential words.
+ * @deprecated use {@link SpellCheckerSession#getSentenceSuggestions(TextInfo[], int)} instead
*/
+ @Deprecated
public void getSuggestions(
TextInfo[] textInfos, int suggestionsLimit, boolean sequentialWords) {
if (DBG) {
Log.w(TAG, "getSuggestions from " + mSpellCheckerInfo.getId());
}
- // TODO: Handle multiple words suggestions by using WordBreakIterator
mSpellCheckerSessionListenerImpl.getSuggestionsMultiple(
textInfos, suggestionsLimit, sequentialWords);
}
@@ -281,7 +282,7 @@
break;
case TASK_GET_SUGGESTIONS_MULTIPLE_FOR_SENTENCE:
if (DBG) {
- Log.w(TAG, "Get suggestions from the spell checker.");
+ Log.w(TAG, "Get sentence suggestions from the spell checker.");
}
try {
session.onGetSentenceSuggestionsMultiple(
@@ -492,11 +493,4 @@
public ISpellCheckerSessionListener getSpellCheckerSessionListener() {
return mSpellCheckerSessionListenerImpl;
}
-
- /**
- * @return true if the spell checker supports sentence level spell checking APIs
- */
- public boolean isSentenceSpellCheckSupported() {
- return mSubtype.containsExtraValueKey(SUPPORT_SENTENCE_SPELL_CHECK);
- }
}
diff --git a/core/java/android/webkit/CallbackProxy.java b/core/java/android/webkit/CallbackProxy.java
index 79bd5d3..ab798e8 100644
--- a/core/java/android/webkit/CallbackProxy.java
+++ b/core/java/android/webkit/CallbackProxy.java
@@ -513,18 +513,18 @@
String databaseIdentifier =
(String) map.get("databaseIdentifier");
String url = (String) map.get("url");
- long currentQuota =
- ((Long) map.get("currentQuota")).longValue();
- long totalUsedQuota =
- ((Long) map.get("totalUsedQuota")).longValue();
- long estimatedSize =
- ((Long) map.get("estimatedSize")).longValue();
+ long quota =
+ ((Long) map.get("quota")).longValue();
+ long totalQuota =
+ ((Long) map.get("totalQuota")).longValue();
+ long estimatedDatabaseSize =
+ ((Long) map.get("estimatedDatabaseSize")).longValue();
WebStorage.QuotaUpdater quotaUpdater =
(WebStorage.QuotaUpdater) map.get("quotaUpdater");
mWebChromeClient.onExceededDatabaseQuota(url,
- databaseIdentifier, currentQuota, estimatedSize,
- totalUsedQuota, quotaUpdater);
+ databaseIdentifier, quota, estimatedDatabaseSize,
+ totalQuota, quotaUpdater);
}
break;
@@ -532,15 +532,15 @@
if (mWebChromeClient != null) {
HashMap<String, Object> map =
(HashMap<String, Object>) msg.obj;
- long spaceNeeded =
- ((Long) map.get("spaceNeeded")).longValue();
- long totalUsedQuota =
- ((Long) map.get("totalUsedQuota")).longValue();
+ long requiredStorage =
+ ((Long) map.get("requiredStorage")).longValue();
+ long quota =
+ ((Long) map.get("quota")).longValue();
WebStorage.QuotaUpdater quotaUpdater =
(WebStorage.QuotaUpdater) map.get("quotaUpdater");
- mWebChromeClient.onReachedMaxAppCacheSize(spaceNeeded,
- totalUsedQuota, quotaUpdater);
+ mWebChromeClient.onReachedMaxAppCacheSize(requiredStorage,
+ quota, quotaUpdater);
}
break;
@@ -1462,19 +1462,21 @@
* @param url The URL that caused the quota overflow.
* @param databaseIdentifier The identifier of the database that the
* transaction that caused the overflow was running on.
- * @param currentQuota The current quota the origin is allowed.
- * @param estimatedSize The estimated size of the database.
- * @param totalUsedQuota is the sum of all origins' quota.
+ * @param quota The current quota the origin is allowed.
+ * @param estimatedDatabaseSize The estimated size of the database.
+ * @param totalQuota is the sum of all origins' quota.
* @param quotaUpdater An instance of a class encapsulating a callback
* to WebViewCore to run when the decision to allow or deny more
* quota has been made.
*/
public void onExceededDatabaseQuota(
- String url, String databaseIdentifier, long currentQuota,
- long estimatedSize, long totalUsedQuota,
+ String url, String databaseIdentifier, long quota,
+ long estimatedDatabaseSize, long totalQuota,
WebStorage.QuotaUpdater quotaUpdater) {
if (mWebChromeClient == null) {
- quotaUpdater.updateQuota(currentQuota);
+ // Native-side logic prevents the quota being updated to a smaller
+ // value.
+ quotaUpdater.updateQuota(quota);
return;
}
@@ -1482,9 +1484,9 @@
HashMap<String, Object> map = new HashMap();
map.put("databaseIdentifier", databaseIdentifier);
map.put("url", url);
- map.put("currentQuota", currentQuota);
- map.put("estimatedSize", estimatedSize);
- map.put("totalUsedQuota", totalUsedQuota);
+ map.put("quota", quota);
+ map.put("estimatedDatabaseSize", estimatedDatabaseSize);
+ map.put("totalQuota", totalQuota);
map.put("quotaUpdater", quotaUpdater);
exceededQuota.obj = map;
sendMessage(exceededQuota);
@@ -1493,24 +1495,26 @@
/**
* Called by WebViewCore to inform the Java side that the appcache has
* exceeded its max size.
- * @param spaceNeeded is the amount of disk space that would be needed
- * in order for the last appcache operation to succeed.
- * @param totalUsedQuota is the sum of all origins' quota.
+ * @param requiredStorage is the amount of storage, in bytes, that would be
+ * needed in order for the last appcache operation to succeed.
+ * @param quota is the current quota (for all origins).
* @param quotaUpdater An instance of a class encapsulating a callback
* to WebViewCore to run when the decision to allow or deny a bigger
* app cache size has been made.
*/
- public void onReachedMaxAppCacheSize(long spaceNeeded,
- long totalUsedQuota, WebStorage.QuotaUpdater quotaUpdater) {
+ public void onReachedMaxAppCacheSize(long requiredStorage,
+ long quota, WebStorage.QuotaUpdater quotaUpdater) {
if (mWebChromeClient == null) {
- quotaUpdater.updateQuota(0);
+ // Native-side logic prevents the quota being updated to a smaller
+ // value.
+ quotaUpdater.updateQuota(quota);
return;
}
Message msg = obtainMessage(REACHED_APPCACHE_MAXSIZE);
HashMap<String, Object> map = new HashMap();
- map.put("spaceNeeded", spaceNeeded);
- map.put("totalUsedQuota", totalUsedQuota);
+ map.put("requiredStorage", requiredStorage);
+ map.put("quota", quota);
map.put("quotaUpdater", quotaUpdater);
msg.obj = map;
sendMessage(msg);
@@ -1707,7 +1711,7 @@
void onIsSupportedCallback(boolean isSupported) {
Message msg = obtainMessage(SEARCHBOX_IS_SUPPORTED_CALLBACK);
- msg.obj = new Boolean(isSupported);
+ msg.obj = Boolean.valueOf(isSupported);
sendMessage(msg);
}
diff --git a/core/java/android/webkit/CookieManager.java b/core/java/android/webkit/CookieManager.java
index 5f7ef41..2997c1a 100644
--- a/core/java/android/webkit/CookieManager.java
+++ b/core/java/android/webkit/CookieManager.java
@@ -26,7 +26,7 @@
* Manages the cookies used by an application's {@link WebView} instances.
* Cookies are manipulated according to RFC2109.
*/
-public final class CookieManager {
+public class CookieManager {
private static CookieManager sRef;
diff --git a/core/java/android/webkit/GeolocationPermissions.java b/core/java/android/webkit/GeolocationPermissions.java
index 1160d57..a916884 100755
--- a/core/java/android/webkit/GeolocationPermissions.java
+++ b/core/java/android/webkit/GeolocationPermissions.java
@@ -50,7 +50,7 @@
// Within WebKit, Geolocation permissions may be applied either temporarily
// (for the duration of the page) or permanently. This class deals only with
// permanent permissions.
-public final class GeolocationPermissions {
+public class GeolocationPermissions {
/**
* A callback interface used by the host application to set the Geolocation
* permission state for an origin.
@@ -252,7 +252,7 @@
}
if (WebViewCore.THREAD_NAME.equals(Thread.currentThread().getName())) {
boolean allowed = nativeGetAllowed(origin);
- callback.onReceiveValue(new Boolean(allowed));
+ callback.onReceiveValue(Boolean.valueOf(allowed));
} else {
Map values = new HashMap<String, Object>();
values.put(ORIGIN, origin);
diff --git a/core/java/android/webkit/JsResult.java b/core/java/android/webkit/JsResult.java
index 07b686f..e4e6851 100644
--- a/core/java/android/webkit/JsResult.java
+++ b/core/java/android/webkit/JsResult.java
@@ -22,8 +22,6 @@
* and provides a means for the client to indicate whether this action should proceed.
*/
public class JsResult {
- // This is a basic result of a confirm or prompt dialog.
- protected boolean mResult;
/**
* Callback interface, implemented by the WebViewProvider implementation to receive
* notifications when the JavaScript result represented by a JsResult instance has
@@ -32,11 +30,10 @@
public interface ResultReceiver {
public void onJsResultComplete(JsResult result);
}
- /**
- * This is the caller of the prompt and is the object that is waiting.
- * @hide
- */
- protected final ResultReceiver mReceiver;
+ // This is the caller of the prompt and is the object that is waiting.
+ private final ResultReceiver mReceiver;
+ // This is a basic result of a confirm or prompt dialog.
+ private boolean mResult;
/**
* Handle the result if the user cancelled the dialog.
@@ -69,7 +66,7 @@
}
/* Notify the caller that the JsResult has completed */
- protected final void wakeUp() {
+ private final void wakeUp() {
mReceiver.onJsResultComplete(this);
}
}
diff --git a/core/java/android/webkit/WebChromeClient.java b/core/java/android/webkit/WebChromeClient.java
index 5cb0d41..4e8790b 100644
--- a/core/java/android/webkit/WebChromeClient.java
+++ b/core/java/android/webkit/WebChromeClient.java
@@ -216,37 +216,54 @@
}
/**
- * Tell the client that the database quota for the origin has been exceeded.
- * @param url The URL that triggered the notification
- * @param databaseIdentifier The identifier of the database that caused the
- * quota overflow.
- * @param currentQuota The current quota for the origin.
- * @param estimatedSize The estimated size of the database.
- * @param totalUsedQuota is the sum of all origins' quota.
- * @param quotaUpdater A callback to inform the WebCore thread that a new
- * quota is available. This callback must always be executed at some
- * point to ensure that the sleeping WebCore thread is woken up.
+ * Tell the client that the quota has been exceeded for the Web SQL Database
+ * API for a particular origin and request a new quota. The client must
+ * respond by invoking the
+ * {@link WebStorage.QuotaUpdater#updateQuota(long) updateQuota(long)}
+ * method of the supplied {@link WebStorage.QuotaUpdater} instance. The
+ * minimum value that can be set for the new quota is the current quota. The
+ * default implementation responds with the current quota, so the quota will
+ * not be increased.
+ * @param url The URL of the page that triggered the notification
+ * @param databaseIdentifier The identifier of the database where the quota
+ * was exceeded.
+ * @param quota The quota for the origin, in bytes
+ * @param estimatedDatabaseSize The estimated size of the offending
+ * database, in bytes
+ * @param totalQuota The total quota for all origins, in bytes
+ * @param quotaUpdater An instance of {@link WebStorage.QuotaUpdater} which
+ * must be used to inform the WebView of the new quota.
*/
+ // Note that the callback must always be executed at some point to ensure
+ // that the sleeping WebCore thread is woken up.
public void onExceededDatabaseQuota(String url, String databaseIdentifier,
- long currentQuota, long estimatedSize, long totalUsedQuota,
- WebStorage.QuotaUpdater quotaUpdater) {
+ long quota, long estimatedDatabaseSize, long totalQuota,
+ WebStorage.QuotaUpdater quotaUpdater) {
// This default implementation passes the current quota back to WebCore.
// WebCore will interpret this that new quota was declined.
- quotaUpdater.updateQuota(currentQuota);
+ quotaUpdater.updateQuota(quota);
}
/**
- * Tell the client that the Application Cache has exceeded its max size.
- * @param spaceNeeded is the amount of disk space that would be needed
- * in order for the last appcache operation to succeed.
- * @param totalUsedQuota is the sum of all origins' quota.
- * @param quotaUpdater A callback to inform the WebCore thread that a new
- * app cache size is available. This callback must always be executed at
- * some point to ensure that the sleeping WebCore thread is woken up.
+ * Tell the client that the quota has been reached for the Application Cache
+ * API and request a new quota. The client must respond by invoking the
+ * {@link WebStorage.QuotaUpdater#updateQuota(long) updateQuota(long)}
+ * method of the supplied {@link WebStorage.QuotaUpdater} instance. The
+ * minimum value that can be set for the new quota is the current quota. The
+ * default implementation responds with the current quota, so the quota will
+ * not be increased.
+ * @param requiredStorage The amount of storage required by the Application
+ * Cache operation that triggered this notification,
+ * in bytes.
+ * @param quota The quota, in bytes
+ * @param quotaUpdater An instance of {@link WebStorage.QuotaUpdater} which
+ * must be used to inform the WebView of the new quota.
*/
- public void onReachedMaxAppCacheSize(long spaceNeeded, long totalUsedQuota,
+ // Note that the callback must always be executed at some point to ensure
+ // that the sleeping WebCore thread is woken up.
+ public void onReachedMaxAppCacheSize(long requiredStorage, long quota,
WebStorage.QuotaUpdater quotaUpdater) {
- quotaUpdater.updateQuota(0);
+ quotaUpdater.updateQuota(quota);
}
/**
diff --git a/core/java/android/webkit/WebCoreThreadWatchdog.java b/core/java/android/webkit/WebCoreThreadWatchdog.java
index 0541d5d..655db31 100644
--- a/core/java/android/webkit/WebCoreThreadWatchdog.java
+++ b/core/java/android/webkit/WebCoreThreadWatchdog.java
@@ -16,6 +16,7 @@
package android.webkit;
+import android.app.Activity;
import android.app.AlertDialog;
import android.content.Context;
import android.content.DialogInterface;
@@ -146,6 +147,7 @@
break;
case TIMED_OUT:
+ if ((mContext == null) || !(mContext instanceof Activity)) return;
new AlertDialog.Builder(mContext)
.setMessage(com.android.internal.R.string.webpage_unresponsive)
.setPositiveButton(com.android.internal.R.string.force_close,
diff --git a/core/java/android/webkit/WebIconDatabase.java b/core/java/android/webkit/WebIconDatabase.java
index 54dfab3..9299b71 100644
--- a/core/java/android/webkit/WebIconDatabase.java
+++ b/core/java/android/webkit/WebIconDatabase.java
@@ -35,7 +35,7 @@
* WebIconDatabase object is a single instance and all methods operate on that
* single object.
*/
-public final class WebIconDatabase {
+public class WebIconDatabase {
private static final String LOGTAG = "WebIconDatabase";
// Global instance of a WebIconDatabase
private static WebIconDatabase sIconDatabase;
diff --git a/core/java/android/webkit/WebSettings.java b/core/java/android/webkit/WebSettings.java
index cddd7ab..ba48da1 100644
--- a/core/java/android/webkit/WebSettings.java
+++ b/core/java/android/webkit/WebSettings.java
@@ -170,45 +170,66 @@
}
/**
- * Set whether the WebView supports zoom
+ * Sets whether the WebView should support zooming using its on-screen zoom
+ * controls and gestures. The particular zoom mechanisms that should be used
+ * can be set with {@link #setBuiltInZoomControls}. This setting does not
+ * affect zooming performed using the {@link WebView#zoomIn()} and
+ * {@link WebView#zoomOut()} methods.
+ * @param support Whether the WebView should support zoom.
*/
public void setSupportZoom(boolean support) {
throw new MustOverrideException();
}
/**
- * Returns whether the WebView supports zoom
+ * Returns true if the WebView supports zoom. The default is true.
+ * @return True if the WebView supports zoom.
*/
public boolean supportZoom() {
throw new MustOverrideException();
}
/**
- * Sets whether the zoom mechanism built into WebView is used.
+ * Sets whether the WebView should use its built-in zoom mechanisms. The
+ * built-in zoom mechanisms comprise on-screen zoom controls, which are
+ * displayed over the WebView's content, and the use of a pinch gesture to
+ * control zooming. Whether or not these on-screen controls are displayed
+ * can be set with {@link #setDisplayZoomControls}.
+ * <p>
+ * The built-in mechanisms are the only currently supported zoom
+ * mechanisms, so it is recommended that this setting is always enabled.
+ * @param enabled Whether the WebView should use its built-in zoom mechanisms.
*/
+ // This method was intended to select between the built-in zoom mechanisms
+ // and the separate zoom controls. The latter were obtained using
+ // {@link WebView#getZoomControls}, which is now hidden.
public void setBuiltInZoomControls(boolean enabled) {
throw new MustOverrideException();
}
/**
- * Returns true if the zoom mechanism built into WebView is being used.
+ * Returns true if the zoom mechanisms built into WebView are being used.
+ * The default is false.
+ * @return True if the zoom mechanisms built into WebView are being used.
*/
public boolean getBuiltInZoomControls() {
throw new MustOverrideException();
}
/**
- * Sets whether the on screen zoom buttons are used.
- * A combination of built in zoom controls enabled
- * and on screen zoom controls disabled allows for pinch to zoom
- * to work without the on screen controls
+ * Sets whether the WebView should display on-screen zoom controls when
+ * using the built-in zoom mechanisms. See {@link #setBuiltInZoomControls}.
+ * @param enabled Whether the WebView should display on-screen zoom controls.
*/
public void setDisplayZoomControls(boolean enabled) {
throw new MustOverrideException();
}
/**
- * Returns true if the on screen zoom buttons are being used.
+ * Returns true if the WebView displays on-screen zoom controls when using
+ * the built-in zoom mechanisms. The default is true.
+ * @return True if the WebView displays on-screen zoom controls when using
+ * the built-in zoom mechanisms.
*/
public boolean getDisplayZoomControls() {
throw new MustOverrideException();
diff --git a/core/java/android/webkit/WebStorage.java b/core/java/android/webkit/WebStorage.java
index 3745258..041791b 100644
--- a/core/java/android/webkit/WebStorage.java
+++ b/core/java/android/webkit/WebStorage.java
@@ -25,19 +25,34 @@
import java.util.Set;
/**
- * Functionality for manipulating the webstorage databases.
+ * This class is used to manage the JavaScript storage APIs provided by the
+ * {@link WebView}. It manages the Application Cache API, the Web SQL Database
+ * API and the HTML5 Web Storage API.
+ *
+ * The Web SQL Database API provides storage which is private to a given
+ * origin, where an origin comprises the host, scheme and port of a URI.
+ * Similarly, use of the Application Cache API can be attributed to an origin.
+ * This class provides access to the storage use and quotas for these APIs for
+ * a given origin. Origins are represented using {@link WebStorage.Origin}.
*/
-public final class WebStorage {
+public class WebStorage {
/**
- * Encapsulates a callback function to be executed when a new quota is made
- * available. We primarily want this to allow us to call back the sleeping
- * WebCore thread from outside the WebViewCore class (as the native call
- * is private). It is imperative that this the setDatabaseQuota method is
- * executed once a decision to either allow or deny new quota is made,
- * otherwise the WebCore thread will remain asleep.
+ * Encapsulates a callback function which is used to provide a new quota
+ * for a JavaScript storage API. See
+ * {@link WebChromeClient#onExceededDatabaseQuota} and
+ * {@link WebChromeClient#onReachedMaxAppCacheSize}.
*/
+ // We primarily want this to allow us to call back the sleeping WebCore
+ // thread from outside the WebViewCore class (as the native call is
+ // private). It is imperative that the setDatabaseQuota method is
+ // executed after a decision to either allow or deny new quota is made,
+ // otherwise the WebCore thread will remain asleep.
public interface QuotaUpdater {
+ /**
+ * Provide a new quota, specified in bytes.
+ * @param newQuota The new quota, in bytes
+ */
public void updateQuota(long newQuota);
};
@@ -70,7 +85,9 @@
private Handler mUIHandler = null;
/**
- * Class containing the HTML5 database quota and usage for an origin.
+ * This class encapsulates information about the amount of storage
+ * currently used by an origin for the JavaScript storage APIs.
+ * See {@link WebStorage} for details.
*/
public static class Origin {
private String mOrigin = null;
@@ -93,28 +110,32 @@
}
/**
- * An origin string is created using WebCore::SecurityOrigin::toString().
- * Note that WebCore::SecurityOrigin uses 0 (which is not printed) for
- * the port if the port is the default for the protocol. Eg
- * http://www.google.com and http://www.google.com:80 both record a port
- * of 0 and hence toString() == 'http://www.google.com' for both.
- * @return The origin string.
+ * Get the string representation of this origin.
+ * @return The string representation of this origin
*/
+ // An origin string is created using WebCore::SecurityOrigin::toString().
+ // Note that WebCore::SecurityOrigin uses 0 (which is not printed) for
+ // the port if the port is the default for the protocol. Eg
+ // http://www.google.com and http://www.google.com:80 both record a port
+ // of 0 and hence toString() == 'http://www.google.com' for both.
public String getOrigin() {
return mOrigin;
}
/**
- * Returns the quota for this origin's HTML5 database.
- * @return The quota in bytes.
+ * Get the quota for this origin, for the Web SQL Database API, in
+ * bytes. If this origin does not use the Web SQL Database API, this
+ * quota will be set to zero.
+ * @return The quota, in bytes.
*/
public long getQuota() {
return mQuota;
}
/**
- * Returns the usage for this origin's HTML5 database.
- * @return The usage in bytes.
+ * Get the total amount of storage currently being used by this origin,
+ * for all JavaScript storage APIs, in bytes.
+ * @return The total amount of storage, in bytes.
*/
public long getUsage() {
return mUsage;
@@ -122,8 +143,8 @@
}
/**
- * @hide
* Message handler, UI side
+ * @hide
*/
public void createUIHandler() {
if (mUIHandler == null) {
@@ -156,8 +177,8 @@
}
/**
+ * Message handler, WebCore side
* @hide
- * Message handler, webcore side
*/
public synchronized void createHandler() {
if (mHandler == null) {
@@ -231,19 +252,22 @@
/*
* When calling getOrigins(), getUsageForOrigin() and getQuotaForOrigin(),
- * we need to get the values from webcore, but we cannot block while doing so
- * as we used to do, as this could result in a full deadlock (other webcore
+ * we need to get the values from WebCore, but we cannot block while doing so
+ * as we used to do, as this could result in a full deadlock (other WebCore
* messages received while we are still blocked here, see http://b/2127737).
*
* We have to do everything asynchronously, by providing a callback function.
- * We post a message on the webcore thread (mHandler) that will get the result
- * from webcore, and we post it back on the UI thread (using mUIHandler).
+ * We post a message on the WebCore thread (mHandler) that will get the result
+ * from WebCore, and we post it back on the UI thread (using mUIHandler).
* We can then use the callback function to return the value.
*/
/**
- * Returns a list of origins having a database. The Map is of type
- * Map<String, Origin>.
+ * Get the origins currently using either the Application Cache or Web SQL
+ * Database APIs. This method operates asynchronously, with the result
+ * being provided via a {@link ValueCallback}. The origins are provided as
+ * a map, of type {@code Map<String, WebStorage.Origin>}, from the string
+ * representation of the origin to a {@link WebStorage.Origin} object.
*/
public void getOrigins(ValueCallback<Map> callback) {
if (callback != null) {
@@ -269,7 +293,11 @@
}
/**
- * Returns the use for a given origin
+ * Get the amount of storage currently being used by both the Application
+ * Cache and Web SQL Database APIs by the given origin. The amount is given
+ * in bytes and the origin is specified using its string representation.
+ * This method operates asynchronously, with the result being provided via
+ * a {@link ValueCallback}.
*/
public void getUsageForOrigin(String origin, ValueCallback<Long> callback) {
if (callback == null) {
@@ -292,7 +320,11 @@
}
/**
- * Returns the quota for a given origin
+ * Get the storage quota for the Web SQL Database API for the given origin.
+ * The quota is given in bytes and the origin is specified using its string
+ * representation. This method operates asynchronously, with the result
+ * being provided via a {@link ValueCallback}. Note that a quota is not
+ * enforced on a per-origin basis for the Application Cache API.
*/
public void getQuotaForOrigin(String origin, ValueCallback<Long> callback) {
if (callback == null) {
@@ -315,7 +347,10 @@
}
/**
- * Set the quota for a given origin
+ * Set the storage quota for the Web SQL Database API for the given origin.
+ * The quota is specified in bytes and the origin is specified using its string
+ * representation. Note that a quota is not enforced on a per-origin basis
+ * for the Application Cache API.
*/
public void setQuotaForOrigin(String origin, long quota) {
if (origin != null) {
@@ -329,7 +364,9 @@
}
/**
- * Delete a given origin
+ * Clear the storage currently being used by both the Application Cache and
+ * Web SQL Database APIs by the given origin. The origin is specified using
+ * its string representation.
*/
public void deleteOrigin(String origin) {
if (origin != null) {
@@ -343,7 +380,9 @@
}
/**
- * Delete all databases
+ * Clear all storage currently being used by the JavaScript storage APIs.
+ * This includes the Application Cache, Web SQL Database and the HTML5 Web
+ * Storage APIs.
*/
public void deleteAllData() {
if (WebViewCore.THREAD_NAME.equals(Thread.currentThread().getName())) {
@@ -381,8 +420,8 @@
}
/**
- * Get the global instance of WebStorage.
- * @return A single instance of WebStorage.
+ * Get the singleton instance of this class.
+ * @return The singleton {@link WebStorage} instance.
*/
public static WebStorage getInstance() {
if (sWebStorage == null) {
@@ -404,7 +443,7 @@
}
/**
- * Run on the webcore thread
+ * Run on the WebCore thread
* set the local values with the current ones
*/
private void syncValues() {
diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java
index 5498622..bd10cca 100644
--- a/core/java/android/webkit/WebView.java
+++ b/core/java/android/webkit/WebView.java
@@ -1530,17 +1530,15 @@
}
/**
- * Returns a view containing zoom controls i.e. +/- buttons. The caller is
- * in charge of installing this view to the view hierarchy. This view will
- * become visible when the user starts scrolling via touch and fade away if
- * the user does not interact with it.
+ * Gets the zoom controls for the WebView, as a separate View. The caller is
+ * responsible for inserting this View into the layout hierarchy.
* <p/>
- * API version 3 introduces a built-in zoom mechanism that is shown
- * automatically by the MapView. This is the preferred approach for
- * showing the zoom UI.
+ * API Level 3 introduced built-in zoom mechanisms for the WebView, as
+ * opposed to these separate zoom controls. The built-in mechanisms are
+ * preferred and can be enabled using
+ * {@link WebSettings#setBuiltInZoomControls}.
*
- * @deprecated The built-in zoom mechanism is preferred, see
- * {@link WebSettings#setBuiltInZoomControls(boolean)}.
+ * @deprecated The built-in zoom mechanisms are preferred.
* @hide since API version 16.
*/
@Deprecated
diff --git a/core/java/android/webkit/WebViewClassic.java b/core/java/android/webkit/WebViewClassic.java
index 504788e..893849b9 100644
--- a/core/java/android/webkit/WebViewClassic.java
+++ b/core/java/android/webkit/WebViewClassic.java
@@ -4677,6 +4677,9 @@
* Select the word at the indicated content coordinates.
*/
boolean selectText(int x, int y) {
+ if (mWebViewCore == null) {
+ return false;
+ }
mWebViewCore.sendMessage(EventHub.SELECT_WORD_AT, x, y);
return true;
}
diff --git a/core/java/android/webkit/WebViewCore.java b/core/java/android/webkit/WebViewCore.java
index 7652417..aea23c0 100644
--- a/core/java/android/webkit/WebViewCore.java
+++ b/core/java/android/webkit/WebViewCore.java
@@ -430,38 +430,38 @@
* Notify the browser that the origin has exceeded it's database quota.
* @param url The URL that caused the overflow.
* @param databaseIdentifier The identifier of the database.
- * @param currentQuota The current quota for the origin.
- * @param estimatedSize The estimated size of the database.
+ * @param quota The current quota for the origin.
+ * @param estimatedDatabaseSize The estimated size of the database.
*/
protected void exceededDatabaseQuota(String url,
String databaseIdentifier,
- long currentQuota,
- long estimatedSize) {
+ long quota,
+ long estimatedDatabaseSize) {
// Inform the callback proxy of the quota overflow. Send an object
// that encapsulates a call to the nativeSetDatabaseQuota method to
// awaken the sleeping webcore thread when a decision from the
// client to allow or deny quota is available.
mCallbackProxy.onExceededDatabaseQuota(url, databaseIdentifier,
- currentQuota, estimatedSize, getUsedQuota(),
+ quota, estimatedDatabaseSize, getUsedQuota(),
new WebStorage.QuotaUpdater() {
@Override
- public void updateQuota(long quota) {
- nativeSetNewStorageLimit(mNativeClass, quota);
+ public void updateQuota(long newQuota) {
+ nativeSetNewStorageLimit(mNativeClass, newQuota);
}
});
}
/**
* Notify the browser that the appcache has exceeded its max size.
- * @param spaceNeeded is the amount of disk space that would be needed
- * in order for the last appcache operation to succeed.
+ * @param requiredStorage is the amount of storage, in bytes, that would be
+ * needed in order for the last appcache operation to succeed.
*/
- protected void reachedMaxAppCacheSize(long spaceNeeded) {
- mCallbackProxy.onReachedMaxAppCacheSize(spaceNeeded, getUsedQuota(),
+ protected void reachedMaxAppCacheSize(long requiredStorage) {
+ mCallbackProxy.onReachedMaxAppCacheSize(requiredStorage, getUsedQuota(),
new WebStorage.QuotaUpdater() {
@Override
- public void updateQuota(long quota) {
- nativeSetNewStorageLimit(mNativeClass, quota);
+ public void updateQuota(long newQuota) {
+ nativeSetNewStorageLimit(mNativeClass, newQuota);
}
});
}
@@ -1772,6 +1772,9 @@
@Override
public boolean dispatchWebKitEvent(MotionEvent event, int eventType, int flags) {
+ if (mNativeClass == 0) {
+ return false;
+ }
switch (eventType) {
case WebViewInputDispatcher.EVENT_TYPE_CLICK:
return nativeMouseClick(mNativeClass);
diff --git a/core/java/android/widget/AdapterView.java b/core/java/android/widget/AdapterView.java
index 1a2231e..abfc577 100644
--- a/core/java/android/widget/AdapterView.java
+++ b/core/java/android/widget/AdapterView.java
@@ -650,7 +650,8 @@
mEmptyView = emptyView;
// If not explicitly specified this view is important for accessibility.
- if (emptyView.getImportantForAccessibility() == IMPORTANT_FOR_ACCESSIBILITY_AUTO) {
+ if (emptyView != null
+ && emptyView.getImportantForAccessibility() == IMPORTANT_FOR_ACCESSIBILITY_AUTO) {
emptyView.setImportantForAccessibility(IMPORTANT_FOR_ACCESSIBILITY_YES);
}
diff --git a/core/java/android/widget/GridLayout.java b/core/java/android/widget/GridLayout.java
index 60dd55c..1cb676f 100644
--- a/core/java/android/widget/GridLayout.java
+++ b/core/java/android/widget/GridLayout.java
@@ -20,6 +20,7 @@
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Color;
+import android.graphics.Insets;
import android.graphics.Paint;
import android.util.AttributeSet;
import android.util.Log;
@@ -559,9 +560,9 @@
int flags = (gravity & mask) >> shift;
switch (flags) {
case (AXIS_SPECIFIED | AXIS_PULL_BEFORE):
- return LEADING;
+ return horizontal ? LEFT : TOP;
case (AXIS_SPECIFIED | AXIS_PULL_AFTER):
- return TRAILING;
+ return horizontal ? RIGHT : BOTTOM;
case (AXIS_SPECIFIED | AXIS_PULL_BEFORE | AXIS_PULL_AFTER):
return FILL;
case AXIS_SPECIFIED:
@@ -1042,12 +1043,15 @@
int rightMargin = getMargin(c, true, false);
int bottomMargin = getMargin(c, false, false);
- // Alignment offsets: the location of the view relative to its alignment group.
- int alignmentOffsetX = boundsX.getOffset(c, hAlign, leftMargin + pWidth + rightMargin);
- int alignmentOffsetY = boundsY.getOffset(c, vAlign, topMargin + pHeight + bottomMargin);
+ int sumMarginsX = leftMargin + rightMargin;
+ int sumMarginsY = topMargin + bottomMargin;
- int width = hAlign.getSizeInCell(c, pWidth, cellWidth - leftMargin - rightMargin);
- int height = vAlign.getSizeInCell(c, pHeight, cellHeight - topMargin - bottomMargin);
+ // Alignment offsets: the location of the view relative to its alignment group.
+ int alignmentOffsetX = boundsX.getOffset(this, c, hAlign, pWidth + sumMarginsX, true);
+ int alignmentOffsetY = boundsY.getOffset(this, c, vAlign, pHeight + sumMarginsY, false);
+
+ int width = hAlign.getSizeInCell(c, pWidth, cellWidth - sumMarginsX);
+ int height = vAlign.getSizeInCell(c, pHeight, cellHeight - sumMarginsY);
int dx = x1 + gravityOffsetX + alignmentOffsetX;
@@ -1181,7 +1185,7 @@
View c = getChildAt(i);
LayoutParams lp = getLayoutParams(c);
Spec spec = horizontal ? lp.columnSpec : lp.rowSpec;
- groupBounds.getValue(i).include(c, spec, GridLayout.this, this);
+ groupBounds.getValue(i).include(GridLayout.this, c, spec, this);
}
}
@@ -2138,16 +2142,30 @@
return before + after;
}
- protected int getOffset(View c, Alignment alignment, int size) {
- return before - alignment.getAlignmentValue(c, size);
+ private int getAlignmentValue(GridLayout gl, View c, int size, Alignment a, boolean horiz) {
+ boolean useLayoutBounds = gl.getLayoutMode() == LAYOUT_BOUNDS;
+ if (!useLayoutBounds) {
+ return a.getAlignmentValue(c, size);
+ } else {
+ Insets insets = c.getLayoutInsets();
+ int leadingInset = horiz ? insets.left : insets.top; // RTL?
+ int trailingInset = horiz ? insets.right : insets.bottom; // RTL?
+ int totalInset = leadingInset + trailingInset;
+ return leadingInset + a.getAlignmentValue(c, size - totalInset);
+ }
}
- protected final void include(View c, Spec spec, GridLayout gridLayout, Axis axis) {
+ protected int getOffset(GridLayout gl, View c, Alignment a, int size, boolean horizontal) {
+ return before - getAlignmentValue(gl, c, size, a, horizontal);
+ }
+
+ protected final void include(GridLayout gl, View c, Spec spec, Axis axis) {
this.flexibility &= spec.getFlexibility();
- int size = gridLayout.getMeasurementIncludingMargin(c, axis.horizontal);
- Alignment alignment = gridLayout.getAlignment(spec.alignment, axis.horizontal);
+ boolean horizontal = axis.horizontal;
+ int size = gl.getMeasurementIncludingMargin(c, horizontal);
+ Alignment alignment = gl.getAlignment(spec.alignment, horizontal);
// todo test this works correctly when the returned value is UNDEFINED
- int before = alignment.getAlignmentValue(c, size);
+ int before = getAlignmentValue(gl, c, size, alignment, horizontal);
include(before, size - before);
}
@@ -2614,8 +2632,8 @@
}
@Override
- protected int getOffset(View c, Alignment alignment, int size) {
- return max(0, super.getOffset(c, alignment, size));
+ protected int getOffset(GridLayout gl, View c, Alignment a, int size, boolean hrz) {
+ return max(0, super.getOffset(gl, c, a, size, hrz));
}
};
}
diff --git a/core/java/android/widget/SpellChecker.java b/core/java/android/widget/SpellChecker.java
index c725b64..a13ee5a 100644
--- a/core/java/android/widget/SpellChecker.java
+++ b/core/java/android/widget/SpellChecker.java
@@ -24,6 +24,7 @@
import android.text.method.WordIterator;
import android.text.style.SpellCheckSpan;
import android.text.style.SuggestionSpan;
+import android.util.Log;
import android.view.textservice.SentenceSuggestionsInfo;
import android.view.textservice.SpellCheckerSession;
import android.view.textservice.SpellCheckerSession.SpellCheckerSessionListener;
@@ -43,6 +44,8 @@
* @hide
*/
public class SpellChecker implements SpellCheckerSessionListener {
+ private static final String TAG = SpellChecker.class.getSimpleName();
+ private static final boolean DBG = false;
// No more than this number of words will be parsed on each iteration to ensure a minimum
// lock of the UI thread
@@ -116,7 +119,7 @@
null /* Bundle not currently used by the textServicesManager */,
mCurrentLocale, this,
false /* means any available languages from current spell checker */);
- mIsSentenceSpellCheckSupported = mSpellCheckerSession.isSentenceSpellCheckSupported();
+ mIsSentenceSpellCheckSupported = true;
}
// Restore SpellCheckSpans in pool
@@ -266,6 +269,12 @@
editable.subSequence(start, end).toString();
spellCheckSpan.setSpellCheckInProgress(true);
textInfos[textInfosCount++] = new TextInfo(word, mCookie, mIds[i]);
+ if (DBG) {
+ Log.d(TAG, "create TextInfo: (" + i + "/" + mLength + ")" + word
+ + ", cookie = " + mCookie + ", seq = "
+ + mIds[i] + ", sel start = " + selectionStart + ", sel end = "
+ + selectionEnd + ", start = " + start + ", end = " + end);
+ }
}
}
@@ -507,7 +516,20 @@
if (regionEnd <= spellCheckStart) {
return;
}
- addSpellCheckSpan(editable, spellCheckStart, regionEnd);
+ final int selectionStart = Selection.getSelectionStart(editable);
+ final int selectionEnd = Selection.getSelectionEnd(editable);
+ if (DBG) {
+ Log.d(TAG, "addSpellCheckSpan: "
+ + editable.subSequence(spellCheckStart, regionEnd)
+ + ", regionEnd = " + regionEnd + ", spellCheckStart = "
+ + spellCheckStart + ", sel start = " + selectionStart + ", sel end ="
+ + selectionEnd);
+ }
+ // Do not check this word if the user is currently editing it
+ if (spellCheckStart >= 0 && regionEnd > spellCheckStart
+ && (selectionEnd < spellCheckStart || selectionStart > regionEnd)) {
+ addSpellCheckSpan(editable, spellCheckStart, regionEnd);
+ }
} else {
while (wordStart <= end) {
if (wordEnd >= start && wordEnd > wordStart) {
diff --git a/core/java/com/android/internal/app/ActionBarImpl.java b/core/java/com/android/internal/app/ActionBarImpl.java
index f1dffa1..1ba6d43 100644
--- a/core/java/com/android/internal/app/ActionBarImpl.java
+++ b/core/java/com/android/internal/app/ActionBarImpl.java
@@ -51,6 +51,7 @@
import android.view.ViewGroup;
import android.view.Window;
import android.view.accessibility.AccessibilityEvent;
+import android.view.animation.AnimationUtils;
import android.widget.SpinnerAdapter;
import java.lang.ref.WeakReference;
@@ -596,19 +597,23 @@
if (mCurWindowVisibility == View.VISIBLE && (mShowHideAnimationEnabled
|| alwaysAnimate)) {
mTopVisibilityView.setAlpha(0);
+ mTopVisibilityView.setTranslationY(-mTopVisibilityView.getHeight());
AnimatorSet anim = new AnimatorSet();
AnimatorSet.Builder b = anim.play(ObjectAnimator.ofFloat(mTopVisibilityView, "alpha", 1));
+ b.with(ObjectAnimator.ofFloat(mTopVisibilityView, "translationY", 0));
if (mContentView != null) {
b.with(ObjectAnimator.ofFloat(mContentView, "translationY",
-mTopVisibilityView.getHeight(), 0));
- mTopVisibilityView.setTranslationY(-mTopVisibilityView.getHeight());
- b.with(ObjectAnimator.ofFloat(mTopVisibilityView, "translationY", 0));
}
if (mSplitView != null && mContextDisplayMode == CONTEXT_DISPLAY_SPLIT) {
mSplitView.setAlpha(0);
+ mSplitView.setTranslationY(mSplitView.getHeight());
mSplitView.setVisibility(View.VISIBLE);
b.with(ObjectAnimator.ofFloat(mSplitView, "alpha", 1));
+ b.with(ObjectAnimator.ofFloat(mSplitView, "translationY", 0));
}
+ anim.setInterpolator(AnimationUtils.loadInterpolator(mContext,
+ com.android.internal.R.interpolator.decelerate_quad));
anim.addListener(mShowListener);
mCurrentShowAnim = anim;
anim.start();
@@ -638,16 +643,20 @@
mContainerView.setTransitioning(true);
AnimatorSet anim = new AnimatorSet();
AnimatorSet.Builder b = anim.play(ObjectAnimator.ofFloat(mTopVisibilityView, "alpha", 0));
+ b.with(ObjectAnimator.ofFloat(mTopVisibilityView, "translationY",
+ -mTopVisibilityView.getHeight()));
if (mContentView != null) {
b.with(ObjectAnimator.ofFloat(mContentView, "translationY",
0, -mTopVisibilityView.getHeight()));
- b.with(ObjectAnimator.ofFloat(mTopVisibilityView, "translationY",
- -mTopVisibilityView.getHeight()));
}
if (mSplitView != null && mSplitView.getVisibility() == View.VISIBLE) {
mSplitView.setAlpha(1);
b.with(ObjectAnimator.ofFloat(mSplitView, "alpha", 0));
+ b.with(ObjectAnimator.ofFloat(mSplitView, "translationY",
+ mSplitView.getHeight()));
}
+ anim.setInterpolator(AnimationUtils.loadInterpolator(mContext,
+ com.android.internal.R.interpolator.accelerate_quad));
anim.addListener(mHideListener);
mCurrentShowAnim = anim;
anim.start();
diff --git a/core/java/com/android/internal/util/ArrayUtils.java b/core/java/com/android/internal/util/ArrayUtils.java
index d1aa1ce..dbf6c8e 100644
--- a/core/java/com/android/internal/util/ArrayUtils.java
+++ b/core/java/com/android/internal/util/ArrayUtils.java
@@ -201,4 +201,40 @@
}
return array;
}
+
+ public static int[] appendInt(int[] cur, int val) {
+ if (cur == null) {
+ return new int[] { val };
+ }
+ final int N = cur.length;
+ for (int i = 0; i < N; i++) {
+ if (cur[i] == val) {
+ return cur;
+ }
+ }
+ int[] ret = new int[N + 1];
+ System.arraycopy(cur, 0, ret, 0, N);
+ ret[N] = val;
+ return ret;
+ }
+
+ public static int[] removeInt(int[] cur, int val) {
+ if (cur == null) {
+ return null;
+ }
+ final int N = cur.length;
+ for (int i = 0; i < N; i++) {
+ if (cur[i] == val) {
+ int[] ret = new int[N - 1];
+ if (i > 0) {
+ System.arraycopy(cur, 0, ret, 0, i);
+ }
+ if (i < (N - 1)) {
+ System.arraycopy(cur, i + 1, ret, i, N - i - 1);
+ }
+ return ret;
+ }
+ }
+ return cur;
+ }
}
diff --git a/core/java/com/android/internal/util/XmlUtils.java b/core/java/com/android/internal/util/XmlUtils.java
index e00a853..6a09fe07 100644
--- a/core/java/com/android/internal/util/XmlUtils.java
+++ b/core/java/com/android/internal/util/XmlUtils.java
@@ -888,4 +888,19 @@
;
}
}
+
+ public static boolean nextElementWithin(XmlPullParser parser, int outerDepth)
+ throws IOException, XmlPullParserException {
+ for (;;) {
+ int type = parser.next();
+ if (type == XmlPullParser.END_DOCUMENT
+ || (type == XmlPullParser.END_TAG && parser.getDepth() == outerDepth)) {
+ return false;
+ }
+ if (type == XmlPullParser.START_TAG
+ && parser.getDepth() == outerDepth + 1) {
+ return true;
+ }
+ }
+ }
}
diff --git a/core/java/com/android/internal/widget/SizeAdaptiveLayout.java b/core/java/com/android/internal/widget/SizeAdaptiveLayout.java
new file mode 100644
index 0000000..adfd3dc
--- /dev/null
+++ b/core/java/com/android/internal/widget/SizeAdaptiveLayout.java
@@ -0,0 +1,405 @@
+/*
+ * Copyright (C) 2012 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.widget;
+
+import com.android.internal.R;
+
+import android.animation.Animator;
+import android.animation.Animator.AnimatorListener;
+import android.animation.AnimatorSet;
+import android.animation.ObjectAnimator;
+import android.content.Context;
+import android.content.res.TypedArray;
+import android.graphics.Color;
+import android.graphics.drawable.ColorDrawable;
+import android.util.AttributeSet;
+import android.util.Log;
+import android.view.View;
+import android.view.ViewDebug;
+import android.view.ViewGroup;
+import android.widget.RemoteViews.RemoteView;
+
+/**
+ * A layout that switches between its children based on the requested layout height.
+ * Each child specifies its minimum and maximum valid height. Results are undefined
+ * if children specify overlapping ranges. A child may specify the maximum height
+ * as 'unbounded' to indicate that it is willing to be displayed arbitrarily tall.
+ *
+ * <p>
+ * See {@link SizeAdaptiveLayout.LayoutParams} for a full description of the
+ * layout parameters used by SizeAdaptiveLayout.
+ */
+@RemoteView
+public class SizeAdaptiveLayout extends ViewGroup {
+
+ private static final String TAG = "SizeAdaptiveLayout";
+ private static final boolean DEBUG = false;
+ private static final long CROSSFADE_TIME = 250;
+
+ // TypedArray indices
+ private static final int MIN_VALID_HEIGHT =
+ R.styleable.SizeAdaptiveLayout_Layout_layout_minHeight;
+ private static final int MAX_VALID_HEIGHT =
+ R.styleable.SizeAdaptiveLayout_Layout_layout_maxHeight;
+
+ // view state
+ private View mActiveChild;
+ private View mLastActive;
+
+ // animation state
+ private AnimatorSet mTransitionAnimation;
+ private AnimatorListener mAnimatorListener;
+ private ObjectAnimator mFadePanel;
+ private ObjectAnimator mFadeView;
+ private int mCanceledAnimationCount;
+ private View mEnteringView;
+ private View mLeavingView;
+ // View used to hide larger views under smaller ones to create a uniform crossfade
+ private View mModestyPanel;
+ private int mModestyPanelTop;
+
+ public SizeAdaptiveLayout(Context context) {
+ super(context);
+ initialize();
+ }
+
+ public SizeAdaptiveLayout(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ initialize();
+ }
+
+ public SizeAdaptiveLayout(Context context, AttributeSet attrs, int defStyle) {
+ super(context, attrs, defStyle);
+ initialize();
+ }
+
+ private void initialize() {
+ mModestyPanel = new View(getContext());
+ // If the SizeAdaptiveLayout has a solid background, use it as a transition hint.
+ if (getBackground() instanceof ColorDrawable) {
+ mModestyPanel.setBackgroundDrawable(getBackground());
+ } else {
+ mModestyPanel.setBackgroundColor(Color.BLACK);
+ }
+ SizeAdaptiveLayout.LayoutParams layout =
+ new SizeAdaptiveLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
+ ViewGroup.LayoutParams.MATCH_PARENT);
+ mModestyPanel.setLayoutParams(layout);
+ addView(mModestyPanel);
+ mFadePanel = ObjectAnimator.ofFloat(mModestyPanel, "alpha", 0f);
+ mFadeView = ObjectAnimator.ofFloat(null, "alpha", 0f);
+ mAnimatorListener = new BringToFrontOnEnd();
+ mTransitionAnimation = new AnimatorSet();
+ mTransitionAnimation.play(mFadeView).with(mFadePanel);
+ mTransitionAnimation.setDuration(CROSSFADE_TIME);
+ mTransitionAnimation.addListener(mAnimatorListener);
+ }
+
+ /**
+ * Visible for testing
+ * @hide
+ */
+ public Animator getTransitionAnimation() {
+ return mTransitionAnimation;
+ }
+
+ /**
+ * Visible for testing
+ * @hide
+ */
+ public View getModestyPanel() {
+ return mModestyPanel;
+ }
+
+ @Override
+ public void onAttachedToWindow() {
+ mLastActive = null;
+ // make sure all views start off invisible.
+ for (int i = 0; i < getChildCount(); i++) {
+ getChildAt(i).setVisibility(View.GONE);
+ }
+ }
+
+ @Override
+ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+ if (DEBUG) Log.d(TAG, this + " measure spec: " +
+ MeasureSpec.toString(heightMeasureSpec));
+ View model = selectActiveChild(heightMeasureSpec);
+ SizeAdaptiveLayout.LayoutParams lp =
+ (SizeAdaptiveLayout.LayoutParams) model.getLayoutParams();
+ if (DEBUG) Log.d(TAG, "active min: " + lp.minHeight + " max: " + lp.maxHeight);
+ measureChild(model, widthMeasureSpec, heightMeasureSpec);
+ int childHeight = model.getMeasuredHeight();
+ int childWidth = model.getMeasuredHeight();
+ int childState = combineMeasuredStates(0, model.getMeasuredState());
+ if (DEBUG) Log.d(TAG, "measured child at: " + childHeight);
+ int resolvedWidth = resolveSizeAndState(childWidth, widthMeasureSpec, childState);
+ int resolvedheight = resolveSizeAndState(childHeight, heightMeasureSpec, childState);
+ setMeasuredDimension(resolvedWidth, resolvedheight);
+ if (DEBUG) Log.d(TAG, "resolved to: " + resolvedheight);
+ }
+
+ //TODO extend to width and height
+ private View selectActiveChild(int heightMeasureSpec) {
+ final int heightMode = MeasureSpec.getMode(heightMeasureSpec);
+ final int heightSize = MeasureSpec.getSize(heightMeasureSpec);
+
+ View unboundedView = null;
+ View tallestView = null;
+ int tallestViewSize = 0;
+ View smallestView = null;
+ int smallestViewSize = Integer.MAX_VALUE;
+ for (int i = 0; i < getChildCount(); i++) {
+ View child = getChildAt(i);
+ if (child != mModestyPanel) {
+ SizeAdaptiveLayout.LayoutParams lp =
+ (SizeAdaptiveLayout.LayoutParams) child.getLayoutParams();
+ if (DEBUG) Log.d(TAG, "looking at " + i +
+ " with min: " + lp.minHeight +
+ " max: " + lp.maxHeight);
+ if (lp.maxHeight == SizeAdaptiveLayout.LayoutParams.UNBOUNDED &&
+ unboundedView == null) {
+ unboundedView = child;
+ }
+ if (lp.maxHeight > tallestViewSize) {
+ tallestViewSize = lp.maxHeight;
+ tallestView = child;
+ }
+ if (lp.minHeight < smallestViewSize) {
+ smallestViewSize = lp.minHeight;
+ smallestView = child;
+ }
+ if (heightMode != MeasureSpec.UNSPECIFIED &&
+ heightSize >= lp.minHeight && heightSize <= lp.maxHeight) {
+ if (DEBUG) Log.d(TAG, " found exact match, finishing early");
+ return child;
+ }
+ }
+ }
+ if (unboundedView != null) {
+ tallestView = unboundedView;
+ }
+ if (heightMode == MeasureSpec.UNSPECIFIED) {
+ return tallestView;
+ }
+ if (heightSize > tallestViewSize) {
+ return tallestView;
+ }
+ return smallestView;
+ }
+
+ @Override
+ protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
+ if (DEBUG) Log.d(TAG, this + " onlayout height: " + (bottom - top));
+ mLastActive = mActiveChild;
+ int measureSpec = View.MeasureSpec.makeMeasureSpec(bottom - top,
+ View.MeasureSpec.EXACTLY);
+ mActiveChild = selectActiveChild(measureSpec);
+ mActiveChild.setVisibility(View.VISIBLE);
+
+ if (mLastActive != mActiveChild && mLastActive != null) {
+ if (DEBUG) Log.d(TAG, this + " changed children from: " + mLastActive +
+ " to: " + mActiveChild);
+
+ mEnteringView = mActiveChild;
+ mLeavingView = mLastActive;
+
+ mEnteringView.setAlpha(1f);
+
+ mModestyPanel.setAlpha(1f);
+ mModestyPanel.bringToFront();
+ mModestyPanelTop = mLeavingView.getHeight();
+ mModestyPanel.setVisibility(View.VISIBLE);
+ // TODO: mModestyPanel background should be compatible with mLeavingView
+
+ mLeavingView.bringToFront();
+
+ if (mTransitionAnimation.isRunning()) {
+ mTransitionAnimation.cancel();
+ }
+ mFadeView.setTarget(mLeavingView);
+ mFadeView.setFloatValues(0f);
+ mFadePanel.setFloatValues(0f);
+ mTransitionAnimation.setupStartValues();
+ mTransitionAnimation.start();
+ }
+ final int childWidth = mActiveChild.getMeasuredWidth();
+ final int childHeight = mActiveChild.getMeasuredHeight();
+ // TODO investigate setting LAYER_TYPE_HARDWARE on mLastActive
+ mActiveChild.layout(0, 0, 0 + childWidth, 0 + childHeight);
+
+ if (DEBUG) Log.d(TAG, "got modesty offset of " + mModestyPanelTop);
+ mModestyPanel.layout(0, mModestyPanelTop, 0 + childWidth, mModestyPanelTop + childHeight);
+ }
+
+ @Override
+ public LayoutParams generateLayoutParams(AttributeSet attrs) {
+ if (DEBUG) Log.d(TAG, "generate layout from attrs");
+ return new SizeAdaptiveLayout.LayoutParams(getContext(), attrs);
+ }
+
+ @Override
+ protected LayoutParams generateLayoutParams(ViewGroup.LayoutParams p) {
+ if (DEBUG) Log.d(TAG, "generate default layout from viewgroup");
+ return new SizeAdaptiveLayout.LayoutParams(p);
+ }
+
+ @Override
+ protected LayoutParams generateDefaultLayoutParams() {
+ if (DEBUG) Log.d(TAG, "generate default layout from null");
+ return new SizeAdaptiveLayout.LayoutParams();
+ }
+
+ @Override
+ protected boolean checkLayoutParams(ViewGroup.LayoutParams p) {
+ return p instanceof SizeAdaptiveLayout.LayoutParams;
+ }
+
+ /**
+ * Per-child layout information associated with ViewSizeAdaptiveLayout.
+ *
+ * TODO extend to width and height
+ *
+ * @attr ref android.R.styleable#SizeAdaptiveLayout_Layout_layout_minHeight
+ * @attr ref android.R.styleable#SizeAdaptiveLayout_Layout_layout_maxHeight
+ */
+ public static class LayoutParams extends ViewGroup.LayoutParams {
+
+ /**
+ * Indicates the minimum valid height for the child.
+ */
+ @ViewDebug.ExportedProperty(category = "layout")
+ public int minHeight;
+
+ /**
+ * Indicates the maximum valid height for the child.
+ */
+ @ViewDebug.ExportedProperty(category = "layout")
+ public int maxHeight;
+
+ /**
+ * Constant value for maxHeight that indicates there is not maximum height.
+ */
+ public static final int UNBOUNDED = -1;
+
+ /**
+ * {@inheritDoc}
+ */
+ public LayoutParams(Context c, AttributeSet attrs) {
+ super(c, attrs);
+ if (DEBUG) {
+ Log.d(TAG, "construct layout from attrs");
+ for (int i = 0; i < attrs.getAttributeCount(); i++) {
+ Log.d(TAG, " " + attrs.getAttributeName(i) + " = " +
+ attrs.getAttributeValue(i));
+ }
+ }
+ TypedArray a =
+ c.obtainStyledAttributes(attrs,
+ R.styleable.SizeAdaptiveLayout_Layout);
+
+ minHeight = a.getDimensionPixelSize(MIN_VALID_HEIGHT, 0);
+ if (DEBUG) Log.d(TAG, "got minHeight of: " + minHeight);
+
+ try {
+ maxHeight = a.getLayoutDimension(MAX_VALID_HEIGHT, UNBOUNDED);
+ if (DEBUG) Log.d(TAG, "got maxHeight of: " + maxHeight);
+ } catch (Exception e) {
+ if (DEBUG) Log.d(TAG, "caught exception looking for maxValidHeight " + e);
+ }
+
+ a.recycle();
+ }
+
+ /**
+ * Creates a new set of layout parameters with the specified width, height
+ * and valid height bounds.
+ *
+ * @param width the width, either {@link #MATCH_PARENT},
+ * {@link #WRAP_CONTENT} or a fixed size in pixels
+ * @param height the height, either {@link #MATCH_PARENT},
+ * {@link #WRAP_CONTENT} or a fixed size in pixels
+ * @param minHeight the minimum height of this child
+ * @param maxHeight the maximum height of this child
+ * or {@link #UNBOUNDED} if the child can grow forever
+ */
+ public LayoutParams(int width, int height, int minHeight, int maxHeight) {
+ super(width, height);
+ this.minHeight = minHeight;
+ this.maxHeight = maxHeight;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public LayoutParams(int width, int height) {
+ this(width, height, UNBOUNDED, UNBOUNDED);
+ }
+
+ /**
+ * Constructs a new LayoutParams with default values as defined in {@link LayoutParams}.
+ */
+ public LayoutParams() {
+ this(MeasureSpec.UNSPECIFIED, MeasureSpec.UNSPECIFIED);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public LayoutParams(ViewGroup.LayoutParams p) {
+ super(p);
+ minHeight = UNBOUNDED;
+ maxHeight = UNBOUNDED;
+ }
+
+ public String debug(String output) {
+ return output + "SizeAdaptiveLayout.LayoutParams={" +
+ ", max=" + maxHeight +
+ ", max=" + minHeight + "}";
+ }
+ }
+
+ class BringToFrontOnEnd implements AnimatorListener {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ if (mCanceledAnimationCount == 0) {
+ mLeavingView.setVisibility(View.GONE);
+ mModestyPanel.setVisibility(View.GONE);
+ mEnteringView.bringToFront();
+ mEnteringView = null;
+ mLeavingView = null;
+ } else {
+ mCanceledAnimationCount--;
+ }
+ }
+
+ @Override
+ public void onAnimationCancel(Animator animation) {
+ mCanceledAnimationCount++;
+ }
+
+ @Override
+ public void onAnimationRepeat(Animator animation) {
+ if (DEBUG) Log.d(TAG, "fade animation repeated: should never happen.");
+ assert(false);
+ }
+
+ @Override
+ public void onAnimationStart(Animator animation) {
+ }
+ }
+}
diff --git a/core/jni/android/graphics/SurfaceTexture.cpp b/core/jni/android/graphics/SurfaceTexture.cpp
index 77ad11e..c48b974 100644
--- a/core/jni/android/graphics/SurfaceTexture.cpp
+++ b/core/jni/android/graphics/SurfaceTexture.cpp
@@ -220,7 +220,7 @@
if (err == INVALID_OPERATION) {
jniThrowException(env, IllegalStateException, "Unable to update texture contents (see "
"logcat for details)");
- } else {
+ } else if (err < 0) {
jniThrowRuntimeException(env, "Error during updateTexImage (see logcat for details)");
}
}
diff --git a/core/jni/android_hardware_SensorManager.cpp b/core/jni/android_hardware_SensorManager.cpp
index 202abf6..9abfb3a 100644
--- a/core/jni/android_hardware_SensorManager.cpp
+++ b/core/jni/android_hardware_SensorManager.cpp
@@ -179,6 +179,6 @@
int register_android_hardware_SensorManager(JNIEnv *env)
{
- return jniRegisterNativeMethods(env, "android/hardware/SensorManager",
+ return jniRegisterNativeMethods(env, "android/hardware/SystemSensorManager",
gMethods, NELEM(gMethods));
}
diff --git a/core/jni/android_net_TrafficStats.cpp b/core/jni/android_net_TrafficStats.cpp
index 0ab659b..325fe26 100644
--- a/core/jni/android_net_TrafficStats.cpp
+++ b/core/jni/android_net_TrafficStats.cpp
@@ -31,6 +31,9 @@
namespace android {
+static const uint64_t VALUE_UNKNOWN = -1;
+static const char* IFACE_STAT_ALL = "/proc/net/xt_qtaguid/iface_stat_all";
+
enum Tx_Rx {
TX,
RX
@@ -42,6 +45,21 @@
TCP_AND_UDP
};
+// NOTE: keep these in sync with TrafficStats.java
+enum IfaceStatType {
+ RX_BYTES = 0,
+ RX_PACKETS = 1,
+ TX_BYTES = 2,
+ TX_PACKETS = 3
+};
+
+struct IfaceStat {
+ uint64_t rxBytes;
+ uint64_t rxPackets;
+ uint64_t txBytes;
+ uint64_t txPackets;
+};
+
// Returns an ASCII decimal number read from the specified file, -1 on error.
static jlong readNumber(char const* filename) {
char buf[80];
@@ -63,130 +81,82 @@
return atoll(buf);
}
-static const char* mobile_iface_list[] = {
- "rmnet0",
- "rmnet1",
- "rmnet2",
- "rmnet3",
- "cdma_rmnet4",
- "ppp0",
- 0
-};
+static int parseIfaceStat(const char* iface, struct IfaceStat* stat) {
+ FILE *fp = fopen(IFACE_STAT_ALL, "r");
+ if (!fp) {
+ return errno;
+ }
-static jlong getAll(const char** iface_list, const char* what) {
+ char buffer[256];
+ char cur_iface[32];
+ int active;
+ uint64_t rxBytes, rxPackets, txBytes, txPackets, devRxBytes, devRxPackets, devTxBytes,
+ devTxPackets;
- char filename[80];
- int idx = 0;
- bool supported = false;
- jlong total = 0;
- while (iface_list[idx] != 0) {
-
- snprintf(filename, sizeof(filename), "/sys/class/net/%s/statistics/%s",
- iface_list[idx], what);
- jlong number = readNumber(filename);
- if (number >= 0) {
- supported = true;
- total += number;
+ while (fgets(buffer, 256, fp) != NULL) {
+ if (sscanf(buffer, "%31s %d %llu %llu %llu %llu %llu %llu %llu %llu", cur_iface, &active,
+ &rxBytes, &rxPackets, &txBytes, &txPackets, &devRxBytes, &devRxPackets,
+ &devTxBytes, &devTxPackets) != 10) {
+ continue;
}
- idx++;
- }
- if (supported) return total;
- return -1;
-}
+ if (!iface || !strcmp(iface, cur_iface)) {
+ stat->rxBytes += rxBytes;
+ stat->rxPackets += rxPackets;
+ stat->txBytes += txBytes;
+ stat->txPackets += txPackets;
-// Returns the sum of numbers from the specified path under /sys/class/net/*,
-// -1 if no such file exists.
-static jlong readTotal(char const* suffix) {
- char filename[PATH_MAX] = "/sys/class/net/";
- DIR *dir = opendir(filename);
- if (dir == NULL) {
- ALOGE("Can't list %s: %s", filename, strerror(errno));
- return -1;
- }
-
- int len = strlen(filename);
- jlong total = -1;
- while (struct dirent *entry = readdir(dir)) {
- // Skip ., .., and localhost interfaces.
- if (entry->d_name[0] != '.' && strncmp(entry->d_name, "lo", 2) != 0) {
- strlcpy(filename + len, entry->d_name, sizeof(filename) - len);
- strlcat(filename, suffix, sizeof(filename));
- jlong num = readNumber(filename);
- if (num >= 0) total = total < 0 ? num : total + num;
+ if (active) {
+ stat->rxBytes += devRxBytes;
+ stat->rxPackets += devRxPackets;
+ stat->txBytes += devTxBytes;
+ stat->txPackets += devTxPackets;
+ }
}
}
- closedir(dir);
- return total;
+ fclose(fp);
+ return 0;
}
-// Mobile stats get accessed a lot more often than total stats.
-// Note the individual files can come and go at runtime, so we check
-// each file every time (rather than caching which ones exist).
+static uint64_t getIfaceStatType(const char* iface, IfaceStatType type) {
+ struct IfaceStat stat;
+ memset(&stat, 0, sizeof(IfaceStat));
-static jlong getMobileTxPackets(JNIEnv* env, jobject clazz) {
- return getAll(mobile_iface_list, "tx_packets");
-}
-
-static jlong getMobileRxPackets(JNIEnv* env, jobject clazz) {
- return getAll(mobile_iface_list, "rx_packets");
-}
-
-static jlong getMobileTxBytes(JNIEnv* env, jobject clazz) {
- return getAll(mobile_iface_list, "tx_bytes");
-}
-
-static jlong getMobileRxBytes(JNIEnv* env, jobject clazz) {
- return getAll(mobile_iface_list, "rx_bytes");
-}
-
-static jlong getData(JNIEnv* env, const char* what, jstring javaInterface) {
- ScopedUtfChars interface(env, javaInterface);
- if (interface.c_str() == NULL) {
- return -1;
+ if (parseIfaceStat(iface, &stat)) {
+ return VALUE_UNKNOWN;
}
- char filename[80];
- snprintf(filename, sizeof(filename), "/sys/class/net/%s/statistics/%s", interface.c_str(), what);
- return readNumber(filename);
+ switch (type) {
+ case RX_BYTES:
+ return stat.rxBytes;
+ case RX_PACKETS:
+ return stat.rxPackets;
+ case TX_BYTES:
+ return stat.txBytes;
+ case TX_PACKETS:
+ return stat.txPackets;
+ default:
+ return VALUE_UNKNOWN;
+ }
}
-static jlong getTxPackets(JNIEnv* env, jobject clazz, jstring interface) {
- return getData(env, "tx_packets", interface);
+static jlong getTotalStat(JNIEnv* env, jclass clazz, jint type) {
+ return getIfaceStatType(NULL, (IfaceStatType) type);
}
-static jlong getRxPackets(JNIEnv* env, jobject clazz, jstring interface) {
- return getData(env, "rx_packets", interface);
+static jlong getIfaceStat(JNIEnv* env, jclass clazz, jstring iface, jint type) {
+ struct IfaceStat stat;
+ const char* ifaceChars = env->GetStringUTFChars(iface, NULL);
+ if (ifaceChars) {
+ uint64_t stat = getIfaceStatType(ifaceChars, (IfaceStatType) type);
+ env->ReleaseStringUTFChars(iface, ifaceChars);
+ return stat;
+ } else {
+ return VALUE_UNKNOWN;
+ }
}
-static jlong getTxBytes(JNIEnv* env, jobject clazz, jstring interface) {
- return getData(env, "tx_bytes", interface);
-}
-
-static jlong getRxBytes(JNIEnv* env, jobject clazz, jstring interface) {
- return getData(env, "rx_bytes", interface);
-}
-
-
-// Total stats are read less often, so we're willing to put up
-// with listing the directory and concatenating filenames.
-
-static jlong getTotalTxPackets(JNIEnv* env, jobject clazz) {
- return readTotal("/statistics/tx_packets");
-}
-
-static jlong getTotalRxPackets(JNIEnv* env, jobject clazz) {
- return readTotal("/statistics/rx_packets");
-}
-
-static jlong getTotalTxBytes(JNIEnv* env, jobject clazz) {
- return readTotal("/statistics/tx_bytes");
-}
-
-static jlong getTotalRxBytes(JNIEnv* env, jobject clazz) {
- return readTotal("/statistics/rx_bytes");
-}
// Per-UID stats require reading from a constructed filename.
@@ -323,18 +293,8 @@
}
static JNINativeMethod gMethods[] = {
- {"getMobileTxPackets", "()J", (void*) getMobileTxPackets},
- {"getMobileRxPackets", "()J", (void*) getMobileRxPackets},
- {"getMobileTxBytes", "()J", (void*) getMobileTxBytes},
- {"getMobileRxBytes", "()J", (void*) getMobileRxBytes},
- {"getTxPackets", "(Ljava/lang/String;)J", (void*) getTxPackets},
- {"getRxPackets", "(Ljava/lang/String;)J", (void*) getRxPackets},
- {"getTxBytes", "(Ljava/lang/String;)J", (void*) getTxBytes},
- {"getRxBytes", "(Ljava/lang/String;)J", (void*) getRxBytes},
- {"getTotalTxPackets", "()J", (void*) getTotalTxPackets},
- {"getTotalRxPackets", "()J", (void*) getTotalRxPackets},
- {"getTotalTxBytes", "()J", (void*) getTotalTxBytes},
- {"getTotalRxBytes", "()J", (void*) getTotalRxBytes},
+ {"nativeGetTotalStat", "(I)J", (void*) getTotalStat},
+ {"nativeGetIfaceStat", "(Ljava/lang/String;I)J", (void*) getIfaceStat},
/* Per-UID Stats */
{"getUidTxBytes", "(I)J", (void*) getUidTxBytes},
diff --git a/core/jni/android_view_Surface.cpp b/core/jni/android_view_Surface.cpp
index ce2cdee..31b914a 100644
--- a/core/jni/android_view_Surface.cpp
+++ b/core/jni/android_view_Surface.cpp
@@ -198,7 +198,7 @@
return surface;
}
-static void setSurface(JNIEnv* env, jobject clazz, const sp<Surface>& surface)
+void setSurface(JNIEnv* env, jobject clazz, const sp<Surface>& surface)
{
Surface* const p = (Surface*)env->GetIntField(clazz, so.surface);
if (surface.get()) {
diff --git a/core/res/res/anim/dock_bottom_enter.xml b/core/res/res/anim/dock_bottom_enter.xml
index 7a2e94b..74a021b 100644
--- a/core/res/res/anim/dock_bottom_enter.xml
+++ b/core/res/res/anim/dock_bottom_enter.xml
@@ -19,8 +19,6 @@
<!-- Animation for when a dock window at the bottom of the screen is entering. -->
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:interpolator="@android:interpolator/decelerate_quad">
- <translate android:fromYDelta="75%" android:toYDelta="0"
+ <translate android:fromYDelta="100%" android:toYDelta="0"
android:duration="@android:integer/config_mediumAnimTime"/>
- <alpha android:fromAlpha="0.0" android:toAlpha="1.0"
- android:duration="@android:integer/config_mediumAnimTime" />
</set>
diff --git a/core/res/res/anim/dock_bottom_exit.xml b/core/res/res/anim/dock_bottom_exit.xml
index c2fd15c..213b3d9 100644
--- a/core/res/res/anim/dock_bottom_exit.xml
+++ b/core/res/res/anim/dock_bottom_exit.xml
@@ -19,8 +19,6 @@
<!-- Animation for when a dock window at the bottom of the screen is exiting. -->
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:interpolator="@android:interpolator/accelerate_quad">
- <translate android:fromYDelta="0" android:toYDelta="75%"
+ <translate android:fromYDelta="0" android:toYDelta="100%"
android:startOffset="100" android:duration="@android:integer/config_mediumAnimTime"/>
- <alpha android:fromAlpha="1.0" android:toAlpha="0.0"
- android:startOffset="100" android:duration="@android:integer/config_mediumAnimTime" />
</set>
diff --git a/core/res/res/anim/dock_left_enter.xml b/core/res/res/anim/dock_left_enter.xml
index b057f67..4fce35a 100644
--- a/core/res/res/anim/dock_left_enter.xml
+++ b/core/res/res/anim/dock_left_enter.xml
@@ -19,8 +19,6 @@
<!-- Animation for when a dock window at the left of the screen is entering. -->
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:interpolator="@android:interpolator/decelerate_quad">
- <translate android:fromXDelta="-75%" android:toXDelta="0"
+ <translate android:fromXDelta="-100%" android:toXDelta="0"
android:duration="@android:integer/config_mediumAnimTime"/>
- <alpha android:fromAlpha="0.0" android:toAlpha="1.0"
- android:duration="@android:integer/config_mediumAnimTime" />
</set>
diff --git a/core/res/res/anim/dock_left_exit.xml b/core/res/res/anim/dock_left_exit.xml
index 576b1aa..bce203d 100644
--- a/core/res/res/anim/dock_left_exit.xml
+++ b/core/res/res/anim/dock_left_exit.xml
@@ -19,8 +19,6 @@
<!-- Animation for when a dock window at the right of the screen is exiting. -->
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:interpolator="@android:interpolator/accelerate_quad">
- <translate android:fromXDelta="0" android:toXDelta="-75%"
+ <translate android:fromXDelta="0" android:toXDelta="-100%"
android:startOffset="100" android:duration="@android:integer/config_mediumAnimTime"/>
- <alpha android:fromAlpha="1.0" android:toAlpha="0.0"
- android:startOffset="100" android:duration="@android:integer/config_mediumAnimTime" />
</set>
diff --git a/core/res/res/anim/dock_right_enter.xml b/core/res/res/anim/dock_right_enter.xml
index e1bd190..26b8ad6 100644
--- a/core/res/res/anim/dock_right_enter.xml
+++ b/core/res/res/anim/dock_right_enter.xml
@@ -19,8 +19,6 @@
<!-- Animation for when a dock window at the right of the screen is entering. -->
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:interpolator="@android:interpolator/decelerate_quad">
- <translate android:fromXDelta="75%" android:toXDelta="0"
+ <translate android:fromXDelta="100%" android:toXDelta="0"
android:duration="@android:integer/config_mediumAnimTime"/>
- <alpha android:fromAlpha="0.0" android:toAlpha="1.0"
- android:duration="@android:integer/config_mediumAnimTime" />
</set>
diff --git a/core/res/res/anim/dock_right_exit.xml b/core/res/res/anim/dock_right_exit.xml
index 6d778fa..6beda59 100644
--- a/core/res/res/anim/dock_right_exit.xml
+++ b/core/res/res/anim/dock_right_exit.xml
@@ -19,8 +19,6 @@
<!-- Animation for when a dock window at the right of the screen is exiting. -->
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:interpolator="@android:interpolator/accelerate_quad">
- <translate android:fromXDelta="0" android:toXDelta="75%"
+ <translate android:fromXDelta="0" android:toXDelta="100%"
android:startOffset="100" android:duration="@android:integer/config_mediumAnimTime"/>
- <alpha android:fromAlpha="1.0" android:toAlpha="0.0"
- android:startOffset="100" android:duration="@android:integer/config_mediumAnimTime" />
</set>
diff --git a/core/res/res/anim/dock_top_enter.xml b/core/res/res/anim/dock_top_enter.xml
index f2e4cae..594b479 100644
--- a/core/res/res/anim/dock_top_enter.xml
+++ b/core/res/res/anim/dock_top_enter.xml
@@ -19,8 +19,6 @@
<!-- Animation for when a dock window at the top of the screen is entering. -->
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:interpolator="@android:interpolator/decelerate_quad">
- <translate android:fromYDelta="-75%" android:toYDelta="0"
+ <translate android:fromYDelta="-100%" android:toYDelta="0"
android:duration="@android:integer/config_mediumAnimTime"/>
- <alpha android:fromAlpha="0.0" android:toAlpha="1.0"
- android:duration="@android:integer/config_mediumAnimTime" />
</set>
diff --git a/core/res/res/anim/dock_top_exit.xml b/core/res/res/anim/dock_top_exit.xml
index 7373695..b9691f6 100644
--- a/core/res/res/anim/dock_top_exit.xml
+++ b/core/res/res/anim/dock_top_exit.xml
@@ -19,8 +19,6 @@
<!-- Animation for when a dock window at the top of the screen is exiting. -->
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:interpolator="@android:interpolator/accelerate_quad">
- <translate android:fromYDelta="0" android:toYDelta="-75%"
+ <translate android:fromYDelta="0" android:toYDelta="-100%"
android:startOffset="100" android:duration="@android:integer/config_mediumAnimTime"/>
- <alpha android:fromAlpha="1.0" android:toAlpha="0.0"
- android:startOffset="100" android:duration="@android:integer/config_mediumAnimTime" />
</set>
diff --git a/core/res/res/layout/adaptive_notification_wrapper.xml b/core/res/res/layout/adaptive_notification_wrapper.xml
new file mode 100644
index 0000000..df9d720
--- /dev/null
+++ b/core/res/res/layout/adaptive_notification_wrapper.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 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.
+*/
+-->
+<TextView xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@android:id/text1"
+ android:textAppearance="?android:attr/dropDownHintAppearance"
+ android:singleLine="true"
+ android:layout_marginLeft="3dip"
+ android:layout_marginTop="3dip"
+ android:layout_marginRight="3dip"
+ android:layout_marginBottom="3dip"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content" />
diff --git a/core/res/res/layout/notification_template_base.xml b/core/res/res/layout/notification_template_base.xml
index b9710d6..74b3fa9 100644
--- a/core/res/res/layout/notification_template_base.xml
+++ b/core/res/res/layout/notification_template_base.xml
@@ -15,9 +15,13 @@
-->
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:internal="http://schemas.android.com/apk/prv/res/android"
+ android:background="@android:color/background_dark"
android:id="@+id/status_bar_latest_event_content"
android:layout_width="match_parent"
android:layout_height="wrap_content"
+ internal:layout_minHeight="64dp"
+ internal:layout_maxHeight="64dp"
>
<ImageView android:id="@+id/icon"
android:layout_width="@dimen/notification_large_icon_width"
diff --git a/core/res/res/layout/notification_template_big_picture.xml b/core/res/res/layout/notification_template_big_picture.xml
index 8be84bd..2150096 100644
--- a/core/res/res/layout/notification_template_big_picture.xml
+++ b/core/res/res/layout/notification_template_big_picture.xml
@@ -15,9 +15,13 @@
-->
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:internal="http://schemas.android.com/apk/prv/res/android"
+ android:background="@android:color/background_dark"
android:id="@+id/status_bar_latest_event_content"
android:layout_width="match_parent"
android:layout_height="match_parent"
+ internal:layout_minHeight="65dp"
+ internal:layout_maxHeight="unbounded"
>
<ImageView
android:id="@+id/big_picture"
@@ -30,4 +34,4 @@
android:layout_height="wrap_content"
android:layout_marginTop="192dp"
/>
-</FrameLayout>
\ No newline at end of file
+</FrameLayout>
diff --git a/core/res/res/layout/notification_template_big_text.xml b/core/res/res/layout/notification_template_big_text.xml
new file mode 100644
index 0000000..3a0bfc7
--- /dev/null
+++ b/core/res/res/layout/notification_template_big_text.xml
@@ -0,0 +1,147 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2012 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.
+-->
+<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:internal="http://schemas.android.com/apk/prv/res/android"
+ android:background="@android:color/background_dark"
+ android:id="@+id/status_bar_latest_event_content"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ internal:layout_minHeight="65dp"
+ internal:layout_maxHeight="unbounded"
+ >
+ <ImageView android:id="@+id/icon"
+ android:layout_width="@dimen/notification_large_icon_width"
+ android:layout_height="@dimen/notification_large_icon_height"
+ android:background="@android:drawable/notify_panel_notification_icon_bg_tile"
+ android:scaleType="center"
+ />
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_gravity="fill_vertical"
+ android:layout_marginLeft="@dimen/notification_large_icon_width"
+ android:minHeight="@dimen/notification_large_icon_height"
+ android:orientation="vertical"
+ android:paddingLeft="12dp"
+ android:paddingRight="12dp"
+ android:paddingTop="4dp"
+ android:paddingBottom="4dp"
+ android:gravity="center_vertical"
+ >
+ <LinearLayout
+ android:id="@+id/line1"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="horizontal"
+ >
+ <TextView android:id="@+id/title"
+ android:textAppearance="@style/TextAppearance.StatusBar.EventContent.Title"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:singleLine="true"
+ android:ellipsize="marquee"
+ android:fadingEdge="horizontal"
+ android:layout_weight="1"
+ />
+ <ViewStub android:id="@+id/time"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center"
+ android:layout_weight="0"
+ android:visibility="gone"
+ android:layout="@layout/notification_template_part_time"
+ />
+ <ViewStub android:id="@+id/chronometer"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center"
+ android:layout_weight="0"
+ android:visibility="gone"
+ android:layout="@layout/notification_template_part_chronometer"
+ />
+ </LinearLayout>
+ <TextView android:id="@+id/text2"
+ android:textAppearance="@style/TextAppearance.StatusBar.EventContent.Line2"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="-2dp"
+ android:layout_marginBottom="-2dp"
+ android:singleLine="true"
+ android:fadingEdge="horizontal"
+ android:ellipsize="marquee"
+ android:visibility="gone"
+ />
+ <TextView android:id="@+id/big_text"
+ android:textAppearance="@style/TextAppearance.StatusBar.EventContent"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:singleLine="false"
+ android:visibility="gone"
+ />
+ <LinearLayout
+ android:id="@+id/line3"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="horizontal"
+ >
+ <TextView android:id="@+id/text"
+ android:textAppearance="@style/TextAppearance.StatusBar.EventContent"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_weight="1"
+ android:layout_gravity="center"
+ android:singleLine="true"
+ android:ellipsize="marquee"
+ android:fadingEdge="horizontal"
+ />
+ <TextView android:id="@+id/info"
+ android:textAppearance="@style/TextAppearance.StatusBar.EventContent.Info"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center"
+ android:layout_weight="0"
+ android:singleLine="true"
+ android:gravity="center"
+ android:paddingLeft="8dp"
+ />
+ <ImageView android:id="@+id/right_icon"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center"
+ android:layout_weight="0"
+ android:scaleType="center"
+ android:paddingLeft="8dp"
+ android:visibility="gone"
+ android:drawableAlpha="180"
+ />
+ </LinearLayout>
+ <ProgressBar
+ android:id="@android:id/progress"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:visibility="gone"
+ style="?android:attr/progressBarStyleHorizontal"
+ />
+ <LinearLayout
+ android:id="@+id/actions"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:visibility="gone"
+ >
+ <!-- actions will be added here -->
+ </LinearLayout>
+ </LinearLayout>
+</FrameLayout>
diff --git a/core/res/res/layout/notification_template_inbox.xml b/core/res/res/layout/notification_template_inbox.xml
new file mode 100644
index 0000000..82342d4
--- /dev/null
+++ b/core/res/res/layout/notification_template_inbox.xml
@@ -0,0 +1,177 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2012 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.
+-->
+
+<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/status_bar_latest_event_content"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ >
+ <ImageView android:id="@+id/icon"
+ android:layout_width="@dimen/notification_large_icon_width"
+ android:layout_height="@dimen/notification_large_icon_height"
+ android:background="@android:drawable/notify_panel_notification_icon_bg_tile"
+ android:scaleType="center"
+ />
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_gravity="fill_vertical"
+ android:layout_marginLeft="@dimen/notification_large_icon_width"
+ android:minHeight="@dimen/notification_large_icon_height"
+ android:orientation="vertical"
+ android:paddingLeft="12dp"
+ android:paddingRight="12dp"
+ android:paddingTop="4dp"
+ android:paddingBottom="4dp"
+ android:gravity="center_vertical"
+ >
+ <LinearLayout
+ android:id="@+id/line1"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="horizontal"
+ >
+ <TextView android:id="@+id/title"
+ android:textAppearance="@style/TextAppearance.StatusBar.EventContent.Title"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:singleLine="true"
+ android:ellipsize="marquee"
+ android:fadingEdge="horizontal"
+ android:layout_weight="1"
+ />
+ <ViewStub android:id="@+id/time"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center"
+ android:layout_weight="0"
+ android:visibility="gone"
+ android:layout="@layout/notification_template_part_time"
+ />
+ <ViewStub android:id="@+id/chronometer"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center"
+ android:layout_weight="0"
+ android:visibility="gone"
+ android:layout="@layout/notification_template_part_chronometer"
+ />
+ </LinearLayout>
+ <TextView android:id="@+id/text2"
+ android:textAppearance="@style/TextAppearance.StatusBar.EventContent.Line2"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="-2dp"
+ android:layout_marginBottom="-2dp"
+ android:singleLine="true"
+ android:fadingEdge="horizontal"
+ android:ellipsize="marquee"
+ android:visibility="gone"
+ />
+ <TextView android:id="@+id/inbox_text0"
+ android:textAppearance="@style/TextAppearance.StatusBar.EventContent"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:singleLine="true"
+ android:ellipsize="end"
+ android:visibility="gone"
+ />
+ <TextView android:id="@+id/inbox_text1"
+ android:textAppearance="@style/TextAppearance.StatusBar.EventContent"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:singleLine="true"
+ android:ellipsize="end"
+ android:visibility="gone"
+ />
+ <TextView android:id="@+id/inbox_text2"
+ android:textAppearance="@style/TextAppearance.StatusBar.EventContent"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:singleLine="true"
+ android:ellipsize="end"
+ android:visibility="gone"
+ />
+ <TextView android:id="@+id/inbox_text3"
+ android:textAppearance="@style/TextAppearance.StatusBar.EventContent"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:singleLine="true"
+ android:ellipsize="end"
+ android:visibility="gone"
+ />
+ <TextView android:id="@+id/inbox_text4"
+ android:textAppearance="@style/TextAppearance.StatusBar.EventContent"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:singleLine="true"
+ android:ellipsize="end"
+ android:visibility="gone"
+ />
+ <LinearLayout
+ android:id="@+id/line3"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="horizontal"
+ >
+ <TextView android:id="@+id/text"
+ android:textAppearance="@style/TextAppearance.StatusBar.EventContent"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_weight="1"
+ android:layout_gravity="center"
+ android:singleLine="true"
+ android:ellipsize="marquee"
+ android:fadingEdge="horizontal"
+ />
+ <TextView android:id="@+id/info"
+ android:textAppearance="@style/TextAppearance.StatusBar.EventContent.Info"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center"
+ android:layout_weight="0"
+ android:singleLine="true"
+ android:gravity="center"
+ android:paddingLeft="8dp"
+ />
+ <ImageView android:id="@+id/right_icon"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center"
+ android:layout_weight="0"
+ android:scaleType="center"
+ android:paddingLeft="8dp"
+ android:visibility="gone"
+ android:drawableAlpha="180"
+ />
+ </LinearLayout>
+ <ProgressBar
+ android:id="@android:id/progress"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:visibility="gone"
+ style="?android:attr/progressBarStyleHorizontal"
+ />
+ <LinearLayout
+ android:id="@+id/actions"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:visibility="gone"
+ >
+ <!-- actions will be added here -->
+ </LinearLayout>
+ </LinearLayout>
+</FrameLayout>
diff --git a/core/res/res/values-af/strings.xml b/core/res/res/values-af/strings.xml
index 25fc3a0..d299436 100644
--- a/core/res/res/values-af/strings.xml
+++ b/core/res/res/values-af/strings.xml
@@ -1007,11 +1007,17 @@
<string name="wifi_p2p_enter_pin_message" msgid="5920929550367828970">"Voer die vereiste PIN in:"</string>
<string name="wifi_p2p_show_pin_message" msgid="8530563323880921094">"PIN:"</string>
<string name="select_character" msgid="3365550120617701745">"Voeg karakter in"</string>
- <string name="sms_control_default_app_name" msgid="3058577482636640465">"Onbekend program"</string>
<string name="sms_control_title" msgid="7296612781128917719">"Stuur SMS-boodskappe"</string>
- <string name="sms_control_message" msgid="4073755190243093924">"\'n Groot aantal SMS-boodskappe word gestuur. Raak OK om voort te gaan, of Kanselleer om op te hou stuur."</string>
- <string name="sms_control_yes" msgid="2532062172402615953">"OK"</string>
- <string name="sms_control_no" msgid="1715320703137199869">"Kanselleer"</string>
+ <string name="sms_control_message" msgid="3867899169651496433">"<b><xliff:g id="APP_NAME">%1$s</xliff:g></b> stuur \'n groot aantal SMS-boodskappe. Wil jy hierdie program toelaat om voort te gaan om boodskappe te stuur?"</string>
+ <string name="sms_control_yes" msgid="3663725993855816807">"Laat toe"</string>
+ <string name="sms_control_no" msgid="625438561395534982">"Weier"</string>
+ <string name="sms_short_code_confirm_title" msgid="1666863092640877318">"Stuur SMS na kortkode?"</string>
+ <string name="sms_premium_short_code_confirm_title" msgid="3811263856304367838">"Stuur \'n premium SMS?"</string>
+ <string name="sms_short_code_confirm_message" msgid="5616409294907295407">"<b><xliff:g id="APP_NAME">%1$s</xliff:g></b> wil graag \'n SMS stuur aan <b><xliff:g id="DEST_ADDRESS">%2$s</xliff:g></b>, wat lyk asof dit \'n SMS-kortkode is.<p>Die stuur van SMS\'e na sommige kortkodes kan veroorsaak dat jou selfoonrekening gedebiteer word vir premium dienste.<p>Wil jy hierdie program toelaat om die boodskap te stuur?"</string>
+ <string name="sms_premium_short_code_confirm_message" msgid="6214083016284738667">"<b><xliff:g id="APP_NAME">%1$s</xliff:g></b> wil graag \'n SMS stuur aan <b><xliff:g id="DEST_ADDRESS">%2$s</xliff:g></b>, wat \'n betaalde SMS-kortkode is.<p><b>As jy \'n boodskap na hierdie bestemming stuur, sal jou selfoonrekening gedebiteer word vir betaalde dienste.</b><p>Wil jy hierdie program toelaat om die boodskap te stuur?"</string>
+ <string name="sms_short_code_confirm_allow" msgid="8957573662645722940">"Stuur boodskap"</string>
+ <string name="sms_short_code_confirm_deny" msgid="6374609298084435887">"Moenie stuur nie"</string>
+ <string name="sms_short_code_confirm_report" msgid="2588793956061677070">"Gee kwaadwillige program aan"</string>
<string name="sim_removed_title" msgid="6227712319223226185">"SIM-kaart verwyder"</string>
<string name="sim_removed_message" msgid="2333164559970958645">"Die mobielnetwerk sal nie beskikbaar wees nie totdat jy weer begin met \'n geldige SIM-kaart."</string>
<string name="sim_done_button" msgid="827949989369963775">"Klaar"</string>
diff --git a/core/res/res/values-am/strings.xml b/core/res/res/values-am/strings.xml
index 0764f0e..b2714dd 100644
--- a/core/res/res/values-am/strings.xml
+++ b/core/res/res/values-am/strings.xml
@@ -286,10 +286,8 @@
<string name="permdesc_setOrientation" msgid="3046126619316671476">"በማንኛውም ጊዜ የማሳያውን መሽከርከር ለመለወጥ ለመተግበሪያው ይፈቅዳሉ፡፡ ለተለመዱ መተግበሪያዎች አያስፈልግም፡፡"</string>
<string name="permlab_setPointerSpeed" msgid="9175371613322562934">"የጠቋሚ ፍጥነት ለውጥ"</string>
<string name="permdesc_setPointerSpeed" msgid="6866563234274104233">"መዳፊት ወይም ዱካ መከተያ ጠቋሚ ፍጥነትን በማንኛውም ጊዜ ለመለወጥ ለመተግበሪያው ይፈቅዳሉ፡፡ ለመደበኛ መተግበሪያዎች መቼም ቢሆን አያስፈልግም፡፡"</string>
- <!-- no translation found for permlab_setKeyboardLayout (4778731703600909340) -->
- <skip />
- <!-- no translation found for permdesc_setKeyboardLayout (8480016771134175879) -->
- <skip />
+ <string name="permlab_setKeyboardLayout" msgid="4778731703600909340">"የቁልፍ ሰሌዳ አቀማመጥ ቀይር"</string>
+ <string name="permdesc_setKeyboardLayout" msgid="8480016771134175879">"መተግበሪያው የቁልፍ ሰሌዳ አቀማመጡን እንዲቀይር ይፈቅድለታል። ለመደበኛ መተግበሪያዎች መቼም ቢሆን ሊያስፈልግ አይገባም።"</string>
<string name="permlab_signalPersistentProcesses" msgid="4539002991947376659">"ወደ መተግበሪያዎችን የLinux ምልክቶች ላክ"</string>
<string name="permdesc_signalPersistentProcesses" msgid="4896992079182649141">"ለሁሉም ተከታታይ ሂደቶች ልከው የሚያቀርቧቸው ሲግናሎችን ለመጠየቅ ለመተግበሪያው ይፈቅዳሉ።"</string>
<string name="permlab_persistentActivity" msgid="8841113627955563938">"ትግበራ ሁልጊዜ አሂድ ላይ አድርግ"</string>
@@ -1009,11 +1007,17 @@
<string name="wifi_p2p_enter_pin_message" msgid="5920929550367828970">"የሚፈለገውን ፒን ተይብ፦"</string>
<string name="wifi_p2p_show_pin_message" msgid="8530563323880921094">"ፒን፦"</string>
<string name="select_character" msgid="3365550120617701745">"ቁምፊ አስገባ"</string>
- <string name="sms_control_default_app_name" msgid="3058577482636640465">"ያልታወቀ መተግበሪያ"</string>
<string name="sms_control_title" msgid="7296612781128917719">"የSMS መልዕክቶች መበላክ ላይ"</string>
- <string name="sms_control_message" msgid="4073755190243093924">"በጣም ብዙ የ SMS መልዕክቶቸ ተልከዋል።ለመቀጠል \"እሺ \" ፣ ወይም መላክ ለማቆም\"ተው \" ምረጥ።"</string>
- <string name="sms_control_yes" msgid="2532062172402615953">"እሺ"</string>
- <string name="sms_control_no" msgid="1715320703137199869">"ይቅር"</string>
+ <string name="sms_control_message" msgid="3867899169651496433">"<b><xliff:g id="APP_NAME">%1$s</xliff:g></b> ቁጥሩ ብዙ የሆኑ የኤስ.ኤም.ኤስ. መልዕቶችን እየላከ ነው። ይሄ መተግበሪያ መልዕክቶችን መላኩን እንዲቀጥል መፍቀድ ትፈልጋለህ?"</string>
+ <string name="sms_control_yes" msgid="3663725993855816807">"ፍቀድ"</string>
+ <string name="sms_control_no" msgid="625438561395534982">"ከልክል"</string>
+ <string name="sms_short_code_confirm_title" msgid="1666863092640877318">"ኤስ.ኤም.ኤስ. ለአጭር ኮድ ይላክ?"</string>
+ <string name="sms_premium_short_code_confirm_title" msgid="3811263856304367838">"ከፍ ያለ ኤስ.ኤም.ኤስ. ይላክ?"</string>
+ <string name="sms_short_code_confirm_message" msgid="5616409294907295407">"<b><xliff:g id="APP_NAME">%1$s</xliff:g></b> የጽሑፍ መልዕክት ለ<b><xliff:g id="DEST_ADDRESS">%2$s</xliff:g></b> መላክ ይፈልጋል፣ ይሄ ደግሞ የኤስ.ኤም.ኤስ. አጭር ኮድ ሆኖ ተገኝቷል።<p>የጽሑፍ መልዕክቶች ለሆኑ አጭር ኮዶች መላክ የተንቀሳቃሽ መለያህ ከፍ ላሉ አገልግሎቶች ሊያስከፍለው ይችላል።<p>ይሄ መተግበሪያ መልዕክቱ እንዲልክ መፍቀድ ትፈልጋለህ?"</string>
+ <string name="sms_premium_short_code_confirm_message" msgid="6214083016284738667">"<b><xliff:g id="APP_NAME">%1$s</xliff:g></b> የጽሑፍ መልዕክት ለ<b><xliff:g id="DEST_ADDRESS">%2$s</xliff:g></b> መላክ ይፈልጋል፣ ይሄ ደግሞ ከፍ ያለ የኤስ.ኤም.ኤስ. አጭር ኮድ ነው።<p><b>መልዕክት ወደዚህ ቦታ መላክ የተንቀሳቃሽ መለያህ ከፍ ላሉ አገልግሎቶች ያስከፍለዋል።</b><p>ይሄ መተግበሪያ መልዕክቱ እንዲልክ መፍቀድ ትፈልጋለህ?"</string>
+ <string name="sms_short_code_confirm_allow" msgid="8957573662645722940">"መልዕክት ላክ"</string>
+ <string name="sms_short_code_confirm_deny" msgid="6374609298084435887">"አትላክ"</string>
+ <string name="sms_short_code_confirm_report" msgid="2588793956061677070">"ተንኮል አዘል መተግበሪያ ሪፖርት አድርግ"</string>
<string name="sim_removed_title" msgid="6227712319223226185">"SIM ካርድ ተወግዷል"</string>
<string name="sim_removed_message" msgid="2333164559970958645">"በትክክል የገባ SIM ካርድ ድጋሚ እስኪያስጀምሩ የተንቀሳቃሽ ስልክ አውታረመረብ አይገኝም።"</string>
<string name="sim_done_button" msgid="827949989369963775">"ተከናውኗል"</string>
@@ -1063,10 +1067,8 @@
<string name="adb_active_notification_message" msgid="1016654627626476142">"USB ማረሚያ ላለማንቃት ዳስስ።"</string>
<string name="select_input_method" msgid="4653387336791222978">"የግቤት ስልት ምረጥ"</string>
<string name="configure_input_methods" msgid="9091652157722495116">"የግቤት ስልቶችን አዘጋጅ"</string>
- <!-- no translation found for use_physical_keyboard (6203112478095117625) -->
- <skip />
- <!-- no translation found for hardware (7517821086888990278) -->
- <skip />
+ <string name="use_physical_keyboard" msgid="6203112478095117625">"የሚዳሰስ የቁልፍ ሰሌዳ"</string>
+ <string name="hardware" msgid="7517821086888990278">"ሃርድዌር"</string>
<string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="candidates_style" msgid="4333913089637062257"><u>"ዕጩዎች"</u></string>
diff --git a/core/res/res/values-ar/strings.xml b/core/res/res/values-ar/strings.xml
index cc3cf93..9a1530f 100644
--- a/core/res/res/values-ar/strings.xml
+++ b/core/res/res/values-ar/strings.xml
@@ -286,10 +286,8 @@
<string name="permdesc_setOrientation" msgid="3046126619316671476">"للسماح للتطبيق بتغيير تدوير الشاشة في أي وقت. لن تكون هناك حاجة إليه مطلقًا مع التطبيقات العادية."</string>
<string name="permlab_setPointerSpeed" msgid="9175371613322562934">"تغيير سرعة المؤشر"</string>
<string name="permdesc_setPointerSpeed" msgid="6866563234274104233">"للسماح للتطبيق بتغيير سرعة مؤشر الماوس أو لوحة التتبع في أي وقت. لن تكون هناك حاجة إليه مطلقًا مع التطبيقات العادية."</string>
- <!-- no translation found for permlab_setKeyboardLayout (4778731703600909340) -->
- <skip />
- <!-- no translation found for permdesc_setKeyboardLayout (8480016771134175879) -->
- <skip />
+ <string name="permlab_setKeyboardLayout" msgid="4778731703600909340">"تغيير تنسيق لوحة مفاتيح"</string>
+ <string name="permdesc_setKeyboardLayout" msgid="8480016771134175879">"للسماح للتطبيق بتغيير تنسيق لوحة المفاتيح. لن تكون هناك حاجة إليه مطلقًا مع التطبيقات العادية."</string>
<string name="permlab_signalPersistentProcesses" msgid="4539002991947376659">"إرسال إشارات Linux للتطبيقات"</string>
<string name="permdesc_signalPersistentProcesses" msgid="4896992079182649141">"للسماح للتطبيق بطلب إرسال الإشارة المزوّدة لجميع العمليات المستمرة."</string>
<string name="permlab_persistentActivity" msgid="8841113627955563938">"تشغيل التطبيق دائمًا"</string>
@@ -1009,11 +1007,17 @@
<string name="wifi_p2p_enter_pin_message" msgid="5920929550367828970">"اكتب رقم التعريف الشخصي المطلوب:"</string>
<string name="wifi_p2p_show_pin_message" msgid="8530563323880921094">"رقم التعريف الشخصي:"</string>
<string name="select_character" msgid="3365550120617701745">"إدراج حرف"</string>
- <string name="sms_control_default_app_name" msgid="3058577482636640465">"تطبيق غير معروف"</string>
<string name="sms_control_title" msgid="7296612781128917719">"إرسال رسائل قصيرة SMS"</string>
- <string name="sms_control_message" msgid="4073755190243093924">"تم إرسال عدد كبير من الرسائل القصيرة SMS. المس \"موافق\" للمتابعة، أو \"إلغاء\" لإيقاف الإرسال."</string>
- <string name="sms_control_yes" msgid="2532062172402615953">"موافق"</string>
- <string name="sms_control_no" msgid="1715320703137199869">"إلغاء"</string>
+ <string name="sms_control_message" msgid="3867899169651496433">"<b><xliff:g id="APP_NAME">%1$s</xliff:g></b> يرسل عددًا كبيرًا من الرسائل القصيرة SMS. هل تريد السماح لهذا التطبيق بالاستمرار في إرسال الرسائل؟"</string>
+ <string name="sms_control_yes" msgid="3663725993855816807">"السماح"</string>
+ <string name="sms_control_no" msgid="625438561395534982">"رفض"</string>
+ <string name="sms_short_code_confirm_title" msgid="1666863092640877318">"إرسال رسالة SMS إلى رمز قصير؟"</string>
+ <string name="sms_premium_short_code_confirm_title" msgid="3811263856304367838">"هل تريد إرسال رسالة قصيرة SMS مميزة؟"</string>
+ <string name="sms_short_code_confirm_message" msgid="5616409294907295407">"<b><xliff:g id="APP_NAME">%1$s</xliff:g></b> يريد إرسال رسالة نصية إلى <b><xliff:g id="DEST_ADDRESS">%2$s</xliff:g></b>، والذي يُعد رمزًا قصيرًا لرسالة قصيرة SMS.<p>قد يؤدي إرسال رسائل نصية إلى بعض الرموز القصيرة إلى تحصيل رسوم من حساب جوالك للخدمات المميزة.<p>هل تريد السماح لهذا التطبيق بإرسال الرسالة؟"</string>
+ <string name="sms_premium_short_code_confirm_message" msgid="6214083016284738667">"<b><xliff:g id="APP_NAME">%1$s</xliff:g></b> يريد إرسال رسالة نصية إلى <b><xliff:g id="DEST_ADDRESS">%2$s</xliff:g></b>، والذي يُعد رمزًا قصيرًا لرسالة قصيرة SMS مميزة.<p><b>سيؤدي إرسال رسالة إلى هذه الوجهة إلى تحصيل رسوم من حساب جوالك للخدمات المميزة.</b><p>هل تريد السماح لهذا التطبيق بإرسال الرسالة؟"</string>
+ <string name="sms_short_code_confirm_allow" msgid="8957573662645722940">"إرسال رسالة"</string>
+ <string name="sms_short_code_confirm_deny" msgid="6374609298084435887">"عدم الإرسال"</string>
+ <string name="sms_short_code_confirm_report" msgid="2588793956061677070">"الإبلاغ عن تطبيق ضار"</string>
<string name="sim_removed_title" msgid="6227712319223226185">"تمت إزالة بطاقة SIM"</string>
<string name="sim_removed_message" msgid="2333164559970958645">"لن تكون شبكة الجوال متاحة حتى تتم إعادة التشغيل وإدخال بطاقة SIM صالحة."</string>
<string name="sim_done_button" msgid="827949989369963775">"تم"</string>
@@ -1063,10 +1067,8 @@
<string name="adb_active_notification_message" msgid="1016654627626476142">"المس لتعطيل تصحيح أخطاء USB."</string>
<string name="select_input_method" msgid="4653387336791222978">"اختيار أسلوب الإدخال"</string>
<string name="configure_input_methods" msgid="9091652157722495116">"إعداد أسلوب الإدخال"</string>
- <!-- no translation found for use_physical_keyboard (6203112478095117625) -->
- <skip />
- <!-- no translation found for hardware (7517821086888990278) -->
- <skip />
+ <string name="use_physical_keyboard" msgid="6203112478095117625">"لوحة مفاتيح فعلية"</string>
+ <string name="hardware" msgid="7517821086888990278">"أجهزة"</string>
<string name="fast_scroll_alphabet" msgid="5433275485499039199">" أ ب ت ث ج ح خ د ذ ر ز س ش ص ض ط ظ ع غ ف ق ك ل م ن ه و ي"</string>
<string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789 أ ب ت ث ج ح خ د ذ ر ز س ش ص ض ط ظ ع غ ف ق ك ل م ن ه و ي"</string>
<string name="candidates_style" msgid="4333913089637062257"><u>"العناصر المرشحة"</u></string>
diff --git a/core/res/res/values-be/strings.xml b/core/res/res/values-be/strings.xml
index 16cb445..9f11db1 100644
--- a/core/res/res/values-be/strings.xml
+++ b/core/res/res/values-be/strings.xml
@@ -1007,11 +1007,17 @@
<string name="wifi_p2p_enter_pin_message" msgid="5920929550367828970">"Увядзіце патрэбны PIN-код:"</string>
<string name="wifi_p2p_show_pin_message" msgid="8530563323880921094">"PIN-код"</string>
<string name="select_character" msgid="3365550120617701745">"Уставіць сімвал"</string>
- <string name="sms_control_default_app_name" msgid="3058577482636640465">"Невядомае прыкладанне"</string>
<string name="sms_control_title" msgid="7296612781128917719">"Адпраўка SMS"</string>
- <string name="sms_control_message" msgid="4073755190243093924">"Адпраўляецца вялікая колькасць SMS-паведамленняў. Націсніце \"OK\", каб працягнуць, ці \"Адмена\", каб спыніць адпраўку."</string>
- <string name="sms_control_yes" msgid="2532062172402615953">"ОК"</string>
- <string name="sms_control_no" msgid="1715320703137199869">"Адмяніць"</string>
+ <string name="sms_control_message" msgid="3867899169651496433">"Прыкладанне <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> дасылае вялікую колькасць SMS-паведамленняў. Дазволіць гэтаму прыкладанню працягваць адпраўляць паведамленні?"</string>
+ <string name="sms_control_yes" msgid="3663725993855816807">"Дазволіць"</string>
+ <string name="sms_control_no" msgid="625438561395534982">"Забараніць"</string>
+ <string name="sms_short_code_confirm_title" msgid="1666863092640877318">"Адправiць SMS на кароткі нумар?"</string>
+ <string name="sms_premium_short_code_confirm_title" msgid="3811263856304367838">"Адправiць платнае SMS?"</string>
+ <string name="sms_short_code_confirm_message" msgid="5616409294907295407">"Прыкладанне <b><xliff:g id="APP_NAME">%1$s</xliff:g></b&gt спрабуе адправiць тэкставае паведамленне на нумар <b><xliff:g id="DEST_ADDRESS">%2$s</xliff:g></b>, які, здаецца, з\'яўляецца кароткім нумарам для SMS.<p>Дасыланне тэкставых паведамленняў на кароткія нумары можа прывесці да спісання сродкаў з вашага мабільнага рахунку за платныя паслугі.</b><p>Жадаеце дазволіць гэтаму прыкладанню даслаць паведамленне?"</string>
+ <string name="sms_premium_short_code_confirm_message" msgid="6214083016284738667">"Прыкладанне <b><xliff:g id="APP_NAME">%1$s</xliff:g></b&g спрабуе адправiць тэкставае паведамленне на нумар <b><xliff:g id="DEST_ADDRESS">%2$s</xliff:g></b>, які з\'яўляецца платным кароткім нумарам для SMS.<p><b>Адпраўка паведамлення гэтаму атрымальніку прывядзе да спісання сродкаў з вашага мабільнага рахунку за платныя паслугі.</b><p>Жадаеце дазволіць гэтаму прыкладанню даслаць паведамленне?"</string>
+ <string name="sms_short_code_confirm_allow" msgid="8957573662645722940">"Адправiць паведамленне"</string>
+ <string name="sms_short_code_confirm_deny" msgid="6374609298084435887">"Не адпраўляць"</string>
+ <string name="sms_short_code_confirm_report" msgid="2588793956061677070">"Павед. аб шкодн. прыкладаннях"</string>
<string name="sim_removed_title" msgid="6227712319223226185">"SIM-карта выдаленая"</string>
<string name="sim_removed_message" msgid="2333164559970958645">"Мабільная сетка будзе недаступная да перазагрузкі з дзеючай SIM-картай."</string>
<string name="sim_done_button" msgid="827949989369963775">"Гатова"</string>
diff --git a/core/res/res/values-bg/strings.xml b/core/res/res/values-bg/strings.xml
index 83f5e41..4a1d3e6 100644
--- a/core/res/res/values-bg/strings.xml
+++ b/core/res/res/values-bg/strings.xml
@@ -286,10 +286,8 @@
<string name="permdesc_setOrientation" msgid="3046126619316671476">"Разрешава на приложението да променя ориентацията на екрана по всяко време. Нормалните приложения би трябвало никога да не се нуждаят от това."</string>
<string name="permlab_setPointerSpeed" msgid="9175371613322562934">"промяна на скоростта на курсор"</string>
<string name="permdesc_setPointerSpeed" msgid="6866563234274104233">"Разрешава на приложението да променя скоростта на курсора на мишката или на тракпада по всяко време. Нормалните приложения би трябвало никога да не се нуждаят от това."</string>
- <!-- no translation found for permlab_setKeyboardLayout (4778731703600909340) -->
- <skip />
- <!-- no translation found for permdesc_setKeyboardLayout (8480016771134175879) -->
- <skip />
+ <string name="permlab_setKeyboardLayout" msgid="4778731703600909340">"промяна на клавиат. подредба"</string>
+ <string name="permdesc_setKeyboardLayout" msgid="8480016771134175879">"Разрешава на приложението да променя клавиатурната подредба. Нормалните приложения би трябвало никога да не се нуждаят от това."</string>
<string name="permlab_signalPersistentProcesses" msgid="4539002991947376659">"изпращане на сигнали от Linux до приложенията"</string>
<string name="permdesc_signalPersistentProcesses" msgid="4896992079182649141">"Разрешава на приложението да подаде заявка предоставеният сигнал да се изпрати до всички постоянни процеси."</string>
<string name="permlab_persistentActivity" msgid="8841113627955563938">"задаване на постоянно изпълнение на приложението"</string>
@@ -1009,11 +1007,17 @@
<string name="wifi_p2p_enter_pin_message" msgid="5920929550367828970">"Въведете задължителния ПИН:"</string>
<string name="wifi_p2p_show_pin_message" msgid="8530563323880921094">"ПИН:"</string>
<string name="select_character" msgid="3365550120617701745">"Вмъкване на знак"</string>
- <string name="sms_control_default_app_name" msgid="3058577482636640465">"Неизвестно приложение"</string>
<string name="sms_control_title" msgid="7296612781128917719">"Изпращане на SMS съобщения"</string>
- <string name="sms_control_message" msgid="4073755190243093924">"Изпращат се голям брой SMS съобщения. Докоснете „OK“, за да продължите, или „Отказ“, за да спрете изпращането."</string>
- <string name="sms_control_yes" msgid="2532062172402615953">"OK"</string>
- <string name="sms_control_no" msgid="1715320703137199869">"Отказ"</string>
+ <string name="sms_control_message" msgid="3867899169651496433">"<b><xliff:g id="APP_NAME">%1$s</xliff:g></b> изпраща голям брой SMS съобщения. Искате ли да разрешите на това приложение да продължи да го прави?"</string>
+ <string name="sms_control_yes" msgid="3663725993855816807">"Разрешаване"</string>
+ <string name="sms_control_no" msgid="625438561395534982">"Отказване"</string>
+ <string name="sms_short_code_confirm_title" msgid="1666863092640877318">"Да се изпрати ли SMS до кратък код?"</string>
+ <string name="sms_premium_short_code_confirm_title" msgid="3811263856304367838">"Да се изпрати ли импулсен SMS?"</string>
+ <string name="sms_short_code_confirm_message" msgid="5616409294907295407">"<b><xliff:g id="APP_NAME">%1$s</xliff:g></b> иска да изпрати текстово съобщение до <b><xliff:g id="DEST_ADDRESS">%2$s</xliff:g></b>, което изглежда е кратък код на SMS.<p>Изпращането на съобщения до някои такива кодове може да доведе до таксуване на мобилната ви сметка за услуги, които се плащат допълнително.<p>Искате ли да разрешите на това приложение да изпрати съобщението?"</string>
+ <string name="sms_premium_short_code_confirm_message" msgid="6214083016284738667">"<b><xliff:g id="APP_NAME">%1$s</xliff:g></b> иска да изпрати текстово съобщение до <b><xliff:g id="DEST_ADDRESS">%2$s</xliff:g></b>, което е кратък код за импулсен SMS.<p><b>Изпращането до тази точка ще доведе до таксуване на мобилната ви сметка за услуги, които се плащат допълнително.</b><p>Искате ли да разрешите на това приложение да изпрати съобщението?"</string>
+ <string name="sms_short_code_confirm_allow" msgid="8957573662645722940">"Изпращане на съобщението"</string>
+ <string name="sms_short_code_confirm_deny" msgid="6374609298084435887">"Да не се изпраща"</string>
+ <string name="sms_short_code_confirm_report" msgid="2588793956061677070">"Сигнал за злонам. приложение"</string>
<string name="sim_removed_title" msgid="6227712319223226185">"SIM картата е премахната"</string>
<string name="sim_removed_message" msgid="2333164559970958645">"Няма да имате достъп до мобилната мрежа, докато не рестартирате с поставена валидна SIM карта."</string>
<string name="sim_done_button" msgid="827949989369963775">"Готово"</string>
@@ -1063,10 +1067,8 @@
<string name="adb_active_notification_message" msgid="1016654627626476142">"Докоснете, за да деактивирате отстраняването на грешки през USB."</string>
<string name="select_input_method" msgid="4653387336791222978">"Избор на метод на въвеждане"</string>
<string name="configure_input_methods" msgid="9091652157722495116">"Методи на въвеждане: Настройка"</string>
- <!-- no translation found for use_physical_keyboard (6203112478095117625) -->
- <skip />
- <!-- no translation found for hardware (7517821086888990278) -->
- <skip />
+ <string name="use_physical_keyboard" msgid="6203112478095117625">"Физическа клавиатура"</string>
+ <string name="hardware" msgid="7517821086888990278">"Хардуер"</string>
<string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="candidates_style" msgid="4333913089637062257"><u>"кандидати"</u></string>
diff --git a/core/res/res/values-ca/strings.xml b/core/res/res/values-ca/strings.xml
index c72c2dd..e266a85 100644
--- a/core/res/res/values-ca/strings.xml
+++ b/core/res/res/values-ca/strings.xml
@@ -286,10 +286,8 @@
<string name="permdesc_setOrientation" msgid="3046126619316671476">"Permet que l\'aplicació canviï el gir de la pantalla en qualsevol moment. No s\'hauria de necessitar mai per a les aplicacions normals."</string>
<string name="permlab_setPointerSpeed" msgid="9175371613322562934">"canvi de velocitat del punter"</string>
<string name="permdesc_setPointerSpeed" msgid="6866563234274104233">"Permet que l\'aplicació canviï la velocitat del punter del ratolí o del ratolí tàctil en qualsevol moment. No s\'hauria de necessitar mai per a les aplicacions normals."</string>
- <!-- no translation found for permlab_setKeyboardLayout (4778731703600909340) -->
- <skip />
- <!-- no translation found for permdesc_setKeyboardLayout (8480016771134175879) -->
- <skip />
+ <string name="permlab_setKeyboardLayout" msgid="4778731703600909340">"canvia la disposició del teclat"</string>
+ <string name="permdesc_setKeyboardLayout" msgid="8480016771134175879">"Permet que l\'aplicació canviï la disposició del teclat. En principi mai no serà necessari per a les aplicacions normals."</string>
<string name="permlab_signalPersistentProcesses" msgid="4539002991947376659">"envia senyals Linux a les aplicacions"</string>
<string name="permdesc_signalPersistentProcesses" msgid="4896992079182649141">"Permet que l\'aplicació sol·liciti que el senyal subministrat s\'enviï a tots els processos persistents."</string>
<string name="permlab_persistentActivity" msgid="8841113627955563938">"fes que l\'aplicació s\'executi sempre"</string>
@@ -1009,11 +1007,17 @@
<string name="wifi_p2p_enter_pin_message" msgid="5920929550367828970">"Introdueix el PIN sol·licitat:"</string>
<string name="wifi_p2p_show_pin_message" msgid="8530563323880921094">"PIN:"</string>
<string name="select_character" msgid="3365550120617701745">"Insereix un caràcter"</string>
- <string name="sms_control_default_app_name" msgid="3058577482636640465">"Aplicació desconeguda"</string>
<string name="sms_control_title" msgid="7296612781128917719">"S\'estan enviant missatges SMS"</string>
- <string name="sms_control_message" msgid="4073755190243093924">"S\'estan enviant molts missatges SMS. Toca D\'acord per continuar o Cancel·la per aturar l\'enviament."</string>
- <string name="sms_control_yes" msgid="2532062172402615953">"D\'acord"</string>
- <string name="sms_control_no" msgid="1715320703137199869">"Cancel·la"</string>
+ <string name="sms_control_message" msgid="3867899169651496433">"<b><xliff:g id="APP_NAME">%1$s</xliff:g></b> està enviant molts missatges SMS. Vols permetre que aquesta aplicació continuï enviant missatges?"</string>
+ <string name="sms_control_yes" msgid="3663725993855816807">"Permet"</string>
+ <string name="sms_control_no" msgid="625438561395534982">"Denega"</string>
+ <string name="sms_short_code_confirm_title" msgid="1666863092640877318">"Vols enviar SMS a codi curt?"</string>
+ <string name="sms_premium_short_code_confirm_title" msgid="3811263856304367838">"Vols enviar el SMS prèmium?"</string>
+ <string name="sms_short_code_confirm_message" msgid="5616409294907295407">"<b><xliff:g id="APP_NAME">%1$s</xliff:g></b> vol enviar un missatge de text a <b><xliff:g id="DEST_ADDRESS">%2$s</xliff:g></b>, que sembla que és un codi SMS curt.<p>Si envies missatges de text a codis curts, pot ser que es carreguin serveis prèmium al teu compte mòbil.<p>Vols permetre que aquesta aplicació enviï el missatge?"</string>
+ <string name="sms_premium_short_code_confirm_message" msgid="6214083016284738667">"<b><xliff:g id="APP_NAME">%1$s</xliff:g></b> vol enviar un missatge de text a <b><xliff:g id="DEST_ADDRESS">%2$s</xliff:g></b>, que és un codi curt SMS prèmium.<p><b>Si envies un missatge a aquesta destinació, es carregaran els serveis prèmium al teu compte mòbil.</b><p>Vols permetre que aquesta aplicació enviï el missatge?"</string>
+ <string name="sms_short_code_confirm_allow" msgid="8957573662645722940">"Envia el missatge"</string>
+ <string name="sms_short_code_confirm_deny" msgid="6374609298084435887">"No enviïs"</string>
+ <string name="sms_short_code_confirm_report" msgid="2588793956061677070">"Informa d\'una aplic. maliciosa"</string>
<string name="sim_removed_title" msgid="6227712319223226185">"Extracció de la targeta SIM"</string>
<string name="sim_removed_message" msgid="2333164559970958645">"La xarxa de telefonia mòbil no estarà disponible fins que no reiniciïs amb una targeta SIM vàlida inserida."</string>
<string name="sim_done_button" msgid="827949989369963775">"Fet"</string>
@@ -1063,10 +1067,8 @@
<string name="adb_active_notification_message" msgid="1016654627626476142">"Toca-ho per desactivar la depuració USB."</string>
<string name="select_input_method" msgid="4653387336791222978">"Selecció de mètodes d\'introducció"</string>
<string name="configure_input_methods" msgid="9091652157722495116">"Configura els mètodes d\'entrada"</string>
- <!-- no translation found for use_physical_keyboard (6203112478095117625) -->
- <skip />
- <!-- no translation found for hardware (7517821086888990278) -->
- <skip />
+ <string name="use_physical_keyboard" msgid="6203112478095117625">"Teclat físic"</string>
+ <string name="hardware" msgid="7517821086888990278">"Maquinari"</string>
<string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="candidates_style" msgid="4333913089637062257"><u>"candidats"</u></string>
diff --git a/core/res/res/values-cs/strings.xml b/core/res/res/values-cs/strings.xml
index 52d10a2..eead99e 100644
--- a/core/res/res/values-cs/strings.xml
+++ b/core/res/res/values-cs/strings.xml
@@ -286,10 +286,8 @@
<string name="permdesc_setOrientation" msgid="3046126619316671476">"Umožňuje aplikaci kdykoli změnit otočení obrazovky. Běžné aplikace by toto oprávnění neměly nikdy požadovat."</string>
<string name="permlab_setPointerSpeed" msgid="9175371613322562934">"změna rychlosti kurzoru"</string>
<string name="permdesc_setPointerSpeed" msgid="6866563234274104233">"Umožňuje aplikaci kdykoli změnit rychlost ukazatele myši nebo touchpadu. Běžné aplikace by toto oprávnění neměly nikdy požadovat."</string>
- <!-- no translation found for permlab_setKeyboardLayout (4778731703600909340) -->
- <skip />
- <!-- no translation found for permdesc_setKeyboardLayout (8480016771134175879) -->
- <skip />
+ <string name="permlab_setKeyboardLayout" msgid="4778731703600909340">"změnit rozložení klávesnice"</string>
+ <string name="permdesc_setKeyboardLayout" msgid="8480016771134175879">"Umožňuje aplikaci změnit rozložení klávesnice. Běžné aplikace by toto oprávnění neměly nikdy požadovat."</string>
<string name="permlab_signalPersistentProcesses" msgid="4539002991947376659">"odeslání signálů systému Linux aplikacím"</string>
<string name="permdesc_signalPersistentProcesses" msgid="4896992079182649141">"Umožňuje aplikaci vyžádat zaslání poskytnutého signálu všem trvalým procesům."</string>
<string name="permlab_persistentActivity" msgid="8841113627955563938">"trvalé spuštění aplikace"</string>
@@ -1009,11 +1007,17 @@
<string name="wifi_p2p_enter_pin_message" msgid="5920929550367828970">"Zadejte požadovaný kód PIN:"</string>
<string name="wifi_p2p_show_pin_message" msgid="8530563323880921094">"PIN:"</string>
<string name="select_character" msgid="3365550120617701745">"Vkládání znaků"</string>
- <string name="sms_control_default_app_name" msgid="3058577482636640465">"Neznámá aplikace"</string>
<string name="sms_control_title" msgid="7296612781128917719">"Odesílání zpráv SMS"</string>
- <string name="sms_control_message" msgid="4073755190243093924">"Odesíláte velký počet zpráv SMS. Dotkněte se možnosti OK, chcete-li pokračovat, nebo možnosti Zrušit, chcete-li odesílání ukončit."</string>
- <string name="sms_control_yes" msgid="2532062172402615953">"OK"</string>
- <string name="sms_control_no" msgid="1715320703137199869">"Zrušit"</string>
+ <string name="sms_control_message" msgid="3867899169651496433">"Aplikace <b><xliff:g id="APP_NAME">%1$s</xliff:g></b>odesílá velký počet SMS zpráv. Chcete aplikaci povolit, aby zprávy odesílala i nadále?"</string>
+ <string name="sms_control_yes" msgid="3663725993855816807">"Povolit"</string>
+ <string name="sms_control_no" msgid="625438561395534982">"Odmítnout"</string>
+ <string name="sms_short_code_confirm_title" msgid="1666863092640877318">"Odeslat SMS na prémiové číslo?"</string>
+ <string name="sms_premium_short_code_confirm_title" msgid="3811263856304367838">"Odeslat zprávu Premium SMS?"</string>
+ <string name="sms_short_code_confirm_message" msgid="5616409294907295407">"Aplikace<b><xliff:g id="APP_NAME">%1$s</xliff:g></b> chce odeslat zprávu na číslo <b><xliff:g id="DEST_ADDRESS">%2$s</xliff:g></b>, což je zřejmě číslo služby Premium SMS.<p>Za odesílání zpráv na určitá prémiová čísla mohou být na mobilní účet naúčtovány poplatky za prémiové služby.<p>Chcete aplikaci povolit odeslání zprávy?"</string>
+ <string name="sms_premium_short_code_confirm_message" msgid="6214083016284738667">"Aplikace <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> chce poslat zprávu na číslo <b><xliff:g id="DEST_ADDRESS">%2$s</xliff:g></b>, což je číslo služby Premium SMS.<p><b>Pokud zprávu odešlete na toto číslo, budou vám na mobilní účet naúčtovány poplatky za prémiové služby.</b><p>Chcete aplikaci povolit odeslání zprávy?"</string>
+ <string name="sms_short_code_confirm_allow" msgid="8957573662645722940">"Odeslat zprávu"</string>
+ <string name="sms_short_code_confirm_deny" msgid="6374609298084435887">"Neodesílat"</string>
+ <string name="sms_short_code_confirm_report" msgid="2588793956061677070">"Nahlásit škodlivou aplikaci"</string>
<string name="sim_removed_title" msgid="6227712319223226185">"Karta SIM odebrána"</string>
<string name="sim_removed_message" msgid="2333164559970958645">"Mobilní síť bude dostupná až poté, co vložíte platnou kartu SIM a restartujete zařízení."</string>
<string name="sim_done_button" msgid="827949989369963775">"Hotovo"</string>
@@ -1063,10 +1067,8 @@
<string name="adb_active_notification_message" msgid="1016654627626476142">"Dotykem zakážete ladění USB."</string>
<string name="select_input_method" msgid="4653387336791222978">"Vybrat metodu vstupu"</string>
<string name="configure_input_methods" msgid="9091652157722495116">"Nastavit metody vstupu"</string>
- <!-- no translation found for use_physical_keyboard (6203112478095117625) -->
- <skip />
- <!-- no translation found for hardware (7517821086888990278) -->
- <skip />
+ <string name="use_physical_keyboard" msgid="6203112478095117625">"Fyzická klávesnice"</string>
+ <string name="hardware" msgid="7517821086888990278">"Hardware"</string>
<string name="fast_scroll_alphabet" msgid="5433275485499039199">" AÁBCČDĎEÉĚFGHCHIÍJKLMNŇOÓPQRŘSŠTŤUÚVWXYÝZŽ"</string>
<string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789AÁBCČDĎEÉĚFGHCHIÍJKLMNŇOÓPQRŘSŠTŤUÚVWXYÝZŽ"</string>
<string name="candidates_style" msgid="4333913089637062257"><u>"kandidáti"</u></string>
diff --git a/core/res/res/values-da/strings.xml b/core/res/res/values-da/strings.xml
index b0a487b..f641927 100644
--- a/core/res/res/values-da/strings.xml
+++ b/core/res/res/values-da/strings.xml
@@ -1007,11 +1007,17 @@
<string name="wifi_p2p_enter_pin_message" msgid="5920929550367828970">"Skriv den påkrævede pinkode:"</string>
<string name="wifi_p2p_show_pin_message" msgid="8530563323880921094">"Pinkode:"</string>
<string name="select_character" msgid="3365550120617701745">"Indsæt tegn"</string>
- <string name="sms_control_default_app_name" msgid="3058577482636640465">"Ukendt app"</string>
<string name="sms_control_title" msgid="7296612781128917719">"Sender sms-beskeder"</string>
- <string name="sms_control_message" msgid="4073755190243093924">"Der sendes et stort antal sms-beskeder. Vælg \"OK\" for at fortsætte eller \"Annuller\" for at stoppe afsendelsen."</string>
- <string name="sms_control_yes" msgid="2532062172402615953">"OK"</string>
- <string name="sms_control_no" msgid="1715320703137199869">"Annuller"</string>
+ <string name="sms_control_message" msgid="3867899169651496433">"<b><xliff:g id="APP_NAME">%1$s</xliff:g></b> sender et stort antal sms-beskeder. Vil du tillade, at denne app fortsat sender beskeder?"</string>
+ <string name="sms_control_yes" msgid="3663725993855816807">"Tillad"</string>
+ <string name="sms_control_no" msgid="625438561395534982">"Afvis"</string>
+ <string name="sms_short_code_confirm_title" msgid="1666863092640877318">"Send sms til shortcode?"</string>
+ <string name="sms_premium_short_code_confirm_title" msgid="3811263856304367838">"Vil du sende en premium-sms?"</string>
+ <string name="sms_short_code_confirm_message" msgid="5616409294907295407">"<b><xliff:g id="APP_NAME">%1$s</xliff:g></b> vil du sende en sms til <b><xliff:g id="DEST_ADDRESS">%2$s</xliff:g></b>, som ser ud til at være en premium-sms-shortcode.&.<p>Hvis du sender en sms til nogle shortcodes, kan det medføre, at din mobilkonto bliver debiteret for premium-tjenester.<p>Vil du tillade, at denne app sender beskeden?"</string>
+ <string name="sms_premium_short_code_confirm_message" msgid="6214083016284738667">"<b><xliff:g id="APP_NAME">%1$s</xliff:g></b> vil du sende en sms til <b><xliff:g id="DEST_ADDRESS">%2$s</xliff:g></b>, som er en premium-sms-shortcode.<p><b>Hvis du sender en besked til denne destination, bliver din mobilkonto debiteret for premium-tjenester.</b><p>Vil du tillade, at denne app sender beskeden?"</string>
+ <string name="sms_short_code_confirm_allow" msgid="8957573662645722940">"Send besked"</string>
+ <string name="sms_short_code_confirm_deny" msgid="6374609298084435887">"Send ikke"</string>
+ <string name="sms_short_code_confirm_report" msgid="2588793956061677070">"Rapportér ondsindet app"</string>
<string name="sim_removed_title" msgid="6227712319223226185">"SIM-kort blev fjernet"</string>
<string name="sim_removed_message" msgid="2333164559970958645">"Det mobile netværk er utilgængeligt, indtil du genstarter med et gyldigt SIM-kort."</string>
<string name="sim_done_button" msgid="827949989369963775">"Udfør"</string>
diff --git a/core/res/res/values-de/strings.xml b/core/res/res/values-de/strings.xml
index 27b88f4..072005d 100644
--- a/core/res/res/values-de/strings.xml
+++ b/core/res/res/values-de/strings.xml
@@ -286,10 +286,8 @@
<string name="permdesc_setOrientation" msgid="3046126619316671476">"Ermöglicht der App, die Bildschirmdrehung jederzeit zu ändern. Sollte nie für normale Apps benötigt werden."</string>
<string name="permlab_setPointerSpeed" msgid="9175371613322562934">"Zeigergeschwindigkeit ändern"</string>
<string name="permdesc_setPointerSpeed" msgid="6866563234274104233">"Ermöglicht der App, jederzeit die Geschwindigkeit des Maus- bzw. Touchpad-Zeigers zu ändern. Sollte nie für normale Apps benötigt werden."</string>
- <!-- no translation found for permlab_setKeyboardLayout (4778731703600909340) -->
- <skip />
- <!-- no translation found for permdesc_setKeyboardLayout (8480016771134175879) -->
- <skip />
+ <string name="permlab_setKeyboardLayout" msgid="4778731703600909340">"Tastaturlayout ändern"</string>
+ <string name="permdesc_setKeyboardLayout" msgid="8480016771134175879">"Ermöglicht der App, das Tastaturlayout zu ändern. Sollte für normale Apps nie benötigt werden."</string>
<string name="permlab_signalPersistentProcesses" msgid="4539002991947376659">"Linux-Signale an Apps senden"</string>
<string name="permdesc_signalPersistentProcesses" msgid="4896992079182649141">"Ermöglicht der App, das Senden des gelieferten Signals an alle andauernden Prozesse zu fordern"</string>
<string name="permlab_persistentActivity" msgid="8841113627955563938">"App permanent ausführen"</string>
@@ -931,7 +929,7 @@
<string name="chooseUsbActivity" msgid="6894748416073583509">"App für USB-Gerät auswählen"</string>
<string name="noApplications" msgid="2991814273936504689">"Diese Aktion kann von keiner App ausgeführt werden."</string>
<string name="aerr_title" msgid="1905800560317137752"></string>
- <string name="aerr_application" msgid="932628488013092776">"Leider wurde <xliff:g id="APPLICATION">%1$s</xliff:g> beendet."</string>
+ <string name="aerr_application" msgid="932628488013092776">"Leider wurde \"<xliff:g id="APPLICATION">%1$s</xliff:g>\" beendet."</string>
<string name="aerr_process" msgid="4507058997035697579">"Leider wurde der Prozess <xliff:g id="PROCESS">%1$s</xliff:g> beendet."</string>
<string name="anr_title" msgid="4351948481459135709"></string>
<string name="anr_activity_application" msgid="1904477189057199066">"<xliff:g id="APPLICATION">%2$s</xliff:g> reagiert nicht."\n\n"Möchten Sie die App schließen?"</string>
@@ -1009,11 +1007,17 @@
<string name="wifi_p2p_enter_pin_message" msgid="5920929550367828970">"Geben Sie die erforderliche PIN ein:"</string>
<string name="wifi_p2p_show_pin_message" msgid="8530563323880921094">"PIN:"</string>
<string name="select_character" msgid="3365550120617701745">"Zeichen einfügen"</string>
- <string name="sms_control_default_app_name" msgid="3058577482636640465">"Unbekannte App"</string>
<string name="sms_control_title" msgid="7296612781128917719">"Kurznachrichten werden gesendet"</string>
- <string name="sms_control_message" msgid="4073755190243093924">"Es wird eine große Anzahl an SMS versendet. Tippen Sie zum Fortfahren auf \"OK\" oder tippen Sie auf \"Abbrechen\", um den Sendevorgang zu beenden."</string>
- <string name="sms_control_yes" msgid="2532062172402615953">"OK"</string>
- <string name="sms_control_no" msgid="1715320703137199869">"Abbrechen"</string>
+ <string name="sms_control_message" msgid="3867899169651496433">"<b><xliff:g id="APP_NAME">%1$s</xliff:g></b> sendet eine große Anzahl SMS. Möchten Sie zulassen, dass die App weiterhin Nachrichten sendet?"</string>
+ <string name="sms_control_yes" msgid="3663725993855816807">"Zulassen"</string>
+ <string name="sms_control_no" msgid="625438561395534982">"Nicht zulassen"</string>
+ <string name="sms_short_code_confirm_title" msgid="1666863092640877318">"SMS an Kurzwahl senden?"</string>
+ <string name="sms_premium_short_code_confirm_title" msgid="3811263856304367838">"Premium-SMS senden?"</string>
+ <string name="sms_short_code_confirm_message" msgid="5616409294907295407">"<b><xliff:g id="APP_NAME">%1$s</xliff:g></b> versucht, eine SMS an <b><xliff:g id="DEST_ADDRESS">%2$s</xliff:g></b> zu senden. Dabei scheint es sich um eine SMS-Kurzwahl zu handeln.<p>Wenn Sie SMS an eine Kurzwahl senden, werden Ihnen für Ihr Mobilfunkkonto möglicherweise Premiumdienste in Rechnung gestellt.<p>Möchten Sie zulassen, dass die App die Nachricht sendet?"</string>
+ <string name="sms_premium_short_code_confirm_message" msgid="6214083016284738667">"<b><xliff:g id="APP_NAME">%1$s</xliff:g></b> versucht, eine SMS an die Premium-SMS-Kurzwahl <b><xliff:g id="DEST_ADDRESS">%2$s</xliff:g></b> zu senden.<p><b>Wenn Sie eine Nachricht an diese Zieladresse senden, werden Ihnen für Ihr Mobilfunkkonto Premiumdienste in Rechnung gestellt.</b><p>Möchten Sie zulassen, dass die App die Nachricht sendet?"</string>
+ <string name="sms_short_code_confirm_allow" msgid="8957573662645722940">"Nachricht senden"</string>
+ <string name="sms_short_code_confirm_deny" msgid="6374609298084435887">"Nicht senden"</string>
+ <string name="sms_short_code_confirm_report" msgid="2588793956061677070">"Schädliche App melden"</string>
<string name="sim_removed_title" msgid="6227712319223226185">"SIM-Karte entfernt"</string>
<string name="sim_removed_message" msgid="2333164559970958645">"Das Mobilfunknetz ist erst wieder verfügbar, wenn Sie einen Neustart mit einer gültigen SIM-Karte durchführen."</string>
<string name="sim_done_button" msgid="827949989369963775">"Fertig"</string>
@@ -1063,10 +1067,8 @@
<string name="adb_active_notification_message" msgid="1016654627626476142">"Zum Deaktivieren von USB-Debugging tippen"</string>
<string name="select_input_method" msgid="4653387336791222978">"Eingabemethode wählen"</string>
<string name="configure_input_methods" msgid="9091652157722495116">"Eingabemethoden einrichten"</string>
- <!-- no translation found for use_physical_keyboard (6203112478095117625) -->
- <skip />
- <!-- no translation found for hardware (7517821086888990278) -->
- <skip />
+ <string name="use_physical_keyboard" msgid="6203112478095117625">"Physische Tastatur"</string>
+ <string name="hardware" msgid="7517821086888990278">"Hardware"</string>
<string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="candidates_style" msgid="4333913089637062257"><u>"Kandidaten"</u></string>
diff --git a/core/res/res/values-el/strings.xml b/core/res/res/values-el/strings.xml
index 0a5dd69..b668965 100644
--- a/core/res/res/values-el/strings.xml
+++ b/core/res/res/values-el/strings.xml
@@ -286,10 +286,8 @@
<string name="permdesc_setOrientation" msgid="3046126619316671476">"Επιτρέπει στην εφαρμογή την αλλαγή της περιστροφής της οθόνης ανά πάσα στιγμή. Δεν απαιτείται για συνήθεις εφαρμογές."</string>
<string name="permlab_setPointerSpeed" msgid="9175371613322562934">"αλλαγή ταχύτητας δείκτη"</string>
<string name="permdesc_setPointerSpeed" msgid="6866563234274104233">"Επιτρέπει στην εφαρμογή την αλλαγή της ταχύτητας του δείκτη του ποντικιού ή της επιφάνειας αφής ανά πάσα στιγμή. Δεν πρέπει να χρησιμοποιείται από συνήθεις εφαρμογές."</string>
- <!-- no translation found for permlab_setKeyboardLayout (4778731703600909340) -->
- <skip />
- <!-- no translation found for permdesc_setKeyboardLayout (8480016771134175879) -->
- <skip />
+ <string name="permlab_setKeyboardLayout" msgid="4778731703600909340">"αλλαγή διάταξης πληκτρολογίου"</string>
+ <string name="permdesc_setKeyboardLayout" msgid="8480016771134175879">"Επιτρέπει στην εφαρμογή την αλλαγή της διάταξης πληκτρολογίου. Δεν απαιτείται για συνήθεις εφαρμογές."</string>
<string name="permlab_signalPersistentProcesses" msgid="4539002991947376659">"αποστολή σημάτων Linux σε εφαρμογές"</string>
<string name="permdesc_signalPersistentProcesses" msgid="4896992079182649141">"Επιτρέπει στην εφαρμογή την αποστολή αιτήματος για την αποστολή του παρεχόμενου σήματος σε όλες τις υπάρχουσες διαδικασίες."</string>
<string name="permlab_persistentActivity" msgid="8841113627955563938">"να εκτελείται συνεχώς η εφαρμογή"</string>
@@ -1009,11 +1007,17 @@
<string name="wifi_p2p_enter_pin_message" msgid="5920929550367828970">"Πληκτρολογήστε τον απαιτούμενο κωδικό PIN:"</string>
<string name="wifi_p2p_show_pin_message" msgid="8530563323880921094">"PIN:"</string>
<string name="select_character" msgid="3365550120617701745">"Εισαγωγή χαρακτήρα"</string>
- <string name="sms_control_default_app_name" msgid="3058577482636640465">"Άγνωστη εφαρμογή"</string>
<string name="sms_control_title" msgid="7296612781128917719">"Αποστολή μηνυμάτων SMS"</string>
- <string name="sms_control_message" msgid="4073755190243093924">"Αποστέλλεται μεγάλος αριθμός μηνυμάτων SMS. Αγγίξτε το στοιχείο \"OK\" για συνέχεια, ή το στοιχείο \"Ακύρωση\" για διακοπή της αποστολής."</string>
- <string name="sms_control_yes" msgid="2532062172402615953">"OK"</string>
- <string name="sms_control_no" msgid="1715320703137199869">"Ακύρωση"</string>
+ <string name="sms_control_message" msgid="3867899169651496433">"Η εφαρμογή <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> στέλνει έναν μεγάλο αριθμό μηνυμάτων SMS. Θέλετε να επιτρέψετε σε αυτήν την εφαρμογή να συνεχίσει να στέλνει μηνύματα;"</string>
+ <string name="sms_control_yes" msgid="3663725993855816807">"Αποδοχή"</string>
+ <string name="sms_control_no" msgid="625438561395534982">"Άρνηση"</string>
+ <string name="sms_short_code_confirm_title" msgid="1666863092640877318">"Να αποσταλεί SMS στον κωδικό;"</string>
+ <string name="sms_premium_short_code_confirm_title" msgid="3811263856304367838">"Να σταλεί SMS ειδικής χρέωσης;"</string>
+ <string name="sms_short_code_confirm_message" msgid="5616409294907295407">"Η εφαρμογή <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> ζητά την έγκρισή σας για την αποστολή μηνύματος κειμένου στον αριθμό <b><xliff:g id="DEST_ADDRESS">%2$s</xliff:g></b>, ο οποίος φαίνεται ότι είναι κωδικός για την αποστολή SMS με ειδική χρέωση.<p>Η αποστολή μηνύματος σε αυτόν τον αριθμό θα χρεωθεί στον λογαριασμό του κινητού σας ως παροχή υπηρεσιών.<p>Θέλετε να επιτρέψετε σε αυτήν την εφαρμογή να στείλει το μήνυμα;"</string>
+ <string name="sms_premium_short_code_confirm_message" msgid="6214083016284738667">"Η εφαρμογή <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> θέλει να στείλει ένα μήνυμα κειμένου στον αριθμό <b><xliff:g id="DEST_ADDRESS">%2$s</xliff:g></b>, ο οποίος είναι ένας κωδικός αποστολής SMS με ειδική χρέωση.<p><b>Η αποστολή μηνύματος σε αυτόν τον αριθμό θα χρεωθεί στον λογαριασμό του κινητού σας ως παροχή υπηρεσιών.</b><p>Θέλετε να επιτρέψετε σε αυτήν την εφαρμογή να στείλει το μήνυμα;"</string>
+ <string name="sms_short_code_confirm_allow" msgid="8957573662645722940">"Αποστολή μηνύματος"</string>
+ <string name="sms_short_code_confirm_deny" msgid="6374609298084435887">"Να μην αποσταλεί"</string>
+ <string name="sms_short_code_confirm_report" msgid="2588793956061677070">"Αναφορά κακόβουλης εφαρμογής"</string>
<string name="sim_removed_title" msgid="6227712319223226185">"Η κάρτα SIM αφαιρέθηκε"</string>
<string name="sim_removed_message" msgid="2333164559970958645">"Το δίκτυο κινητής τηλεφωνίας δεν θα είναι διαθέσιμο μέχρι να κάνετε επανεκκίνηση αφού τοποθετήσετε μια έγκυρη κάρτα SIM."</string>
<string name="sim_done_button" msgid="827949989369963775">"Τέλος"</string>
@@ -1063,10 +1067,8 @@
<string name="adb_active_notification_message" msgid="1016654627626476142">"Αγγίξτε για απενεργοποίηση του εντοπισμού σφαλμάτων USB."</string>
<string name="select_input_method" msgid="4653387336791222978">"Επιλογή μεθόδου εισόδου"</string>
<string name="configure_input_methods" msgid="9091652157722495116">"Ρύθμιση μεθόδων εισαγωγής"</string>
- <!-- no translation found for use_physical_keyboard (6203112478095117625) -->
- <skip />
- <!-- no translation found for hardware (7517821086888990278) -->
- <skip />
+ <string name="use_physical_keyboard" msgid="6203112478095117625">"Φυσικό πληκτρολόγιο"</string>
+ <string name="hardware" msgid="7517821086888990278">"Υλικό"</string>
<string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="candidates_style" msgid="4333913089637062257"><u>"υποψήφιοι"</u></string>
diff --git a/core/res/res/values-en-rGB/strings.xml b/core/res/res/values-en-rGB/strings.xml
index fe5a173..208e96a 100644
--- a/core/res/res/values-en-rGB/strings.xml
+++ b/core/res/res/values-en-rGB/strings.xml
@@ -1007,11 +1007,17 @@
<string name="wifi_p2p_enter_pin_message" msgid="5920929550367828970">"Type the required PIN:"</string>
<string name="wifi_p2p_show_pin_message" msgid="8530563323880921094">"PIN:"</string>
<string name="select_character" msgid="3365550120617701745">"Insert character"</string>
- <string name="sms_control_default_app_name" msgid="3058577482636640465">"Unknown app"</string>
<string name="sms_control_title" msgid="7296612781128917719">"Sending SMS messages"</string>
- <string name="sms_control_message" msgid="4073755190243093924">"A large number of SMS messages are being sent. Touch OK to continue or Cancel to stop sending."</string>
- <string name="sms_control_yes" msgid="2532062172402615953">"OK"</string>
- <string name="sms_control_no" msgid="1715320703137199869">"Cancel"</string>
+ <string name="sms_control_message" msgid="3867899169651496433">"<b><xliff:g id="APP_NAME">%1$s</xliff:g></b> is sending a large number of SMS messages. Do you want to allow this app to continue sending messages?"</string>
+ <string name="sms_control_yes" msgid="3663725993855816807">"Allow"</string>
+ <string name="sms_control_no" msgid="625438561395534982">"Deny"</string>
+ <string name="sms_short_code_confirm_title" msgid="1666863092640877318">"Send SMS to short code?"</string>
+ <string name="sms_premium_short_code_confirm_title" msgid="3811263856304367838">"Send premium SMS?"</string>
+ <string name="sms_short_code_confirm_message" msgid="5616409294907295407">"<b><xliff:g id="APP_NAME">%1$s</xliff:g></b> would like to send a text message to <b><xliff:g id="DEST_ADDRESS">%2$s</xliff:g></b>, which appears to be an SMS short code.<p>Sending text messages to some short codes may cause your mobile account to be billed for premium services.<p>do you want to allow this app to send the message?"</string>
+ <string name="sms_premium_short_code_confirm_message" msgid="6214083016284738667">"<b><xliff:g id="APP_NAME">%1$s</xliff:g></b> would like to send a text message to <b><xliff:g id="DEST_ADDRESS">%2$s</xliff:g></b>, which is a premium SMS short code.<p><b>Sending a message to this destination will cause your mobile account to be billed for premium services.</b><p>Do you want to allow this app to send the message?"</string>
+ <string name="sms_short_code_confirm_allow" msgid="8957573662645722940">"Send message"</string>
+ <string name="sms_short_code_confirm_deny" msgid="6374609298084435887">"Don\'t send"</string>
+ <string name="sms_short_code_confirm_report" msgid="2588793956061677070">"Report malicious app"</string>
<string name="sim_removed_title" msgid="6227712319223226185">"SIM card removed"</string>
<string name="sim_removed_message" msgid="2333164559970958645">"The mobile network will be unavailable until you restart with a valid SIM card inserted."</string>
<string name="sim_done_button" msgid="827949989369963775">"Done"</string>
diff --git a/core/res/res/values-es-rUS/strings.xml b/core/res/res/values-es-rUS/strings.xml
index ade6cfb..d464095 100644
--- a/core/res/res/values-es-rUS/strings.xml
+++ b/core/res/res/values-es-rUS/strings.xml
@@ -286,10 +286,8 @@
<string name="permdesc_setOrientation" msgid="3046126619316671476">"Permite que la aplicación cambie la rotación de la pantalla en cualquier momento. Las aplicaciones normales no deberían necesitar este permiso."</string>
<string name="permlab_setPointerSpeed" msgid="9175371613322562934">"cambiar velocidad del puntero"</string>
<string name="permdesc_setPointerSpeed" msgid="6866563234274104233">"Permite que la aplicación cambie la velocidad del puntero del mouse o el trackpad en cualquier momento. Las aplicaciones normales no deben utilizar este permiso."</string>
- <!-- no translation found for permlab_setKeyboardLayout (4778731703600909340) -->
- <skip />
- <!-- no translation found for permdesc_setKeyboardLayout (8480016771134175879) -->
- <skip />
+ <string name="permlab_setKeyboardLayout" msgid="4778731703600909340">"cambiar el diseño del teclado"</string>
+ <string name="permdesc_setKeyboardLayout" msgid="8480016771134175879">"Permite que la aplicación cambie el diseño del teclado. Las aplicaciones normales no deberían necesitar este permiso."</string>
<string name="permlab_signalPersistentProcesses" msgid="4539002991947376659">"enviar señales de Linux a las aplicaciones"</string>
<string name="permdesc_signalPersistentProcesses" msgid="4896992079182649141">"Permite que la aplicación solicite que la señal suministrada se envíe a todos los procesos persistentes."</string>
<string name="permlab_persistentActivity" msgid="8841113627955563938">"hacer que la aplicación se ejecute siempre"</string>
@@ -1009,11 +1007,17 @@
<string name="wifi_p2p_enter_pin_message" msgid="5920929550367828970">"Escribe el PIN solicitado:"</string>
<string name="wifi_p2p_show_pin_message" msgid="8530563323880921094">"PIN:"</string>
<string name="select_character" msgid="3365550120617701745">"Insertar caracteres"</string>
- <string name="sms_control_default_app_name" msgid="3058577482636640465">"Aplicación desconocida"</string>
<string name="sms_control_title" msgid="7296612781128917719">"Enviando mensajes SMS"</string>
- <string name="sms_control_message" msgid="4073755190243093924">"Se está enviando una gran cantidad de mensajes SMS. Toca \"Aceptar\" para continuar o \"Cancelar\" para detener el envío."</string>
- <string name="sms_control_yes" msgid="2532062172402615953">"Aceptar"</string>
- <string name="sms_control_no" msgid="1715320703137199869">"Cancelar"</string>
+ <string name="sms_control_message" msgid="3867899169651496433">"<b><xliff:g id="APP_NAME">%1$s</xliff:g></b> está enviando una gran cantidad de mensajes SMS. ¿Quieres permitir que está aplicación siga enviando mensajes?"</string>
+ <string name="sms_control_yes" msgid="3663725993855816807">"Permitir"</string>
+ <string name="sms_control_no" msgid="625438561395534982">"Rechazar"</string>
+ <string name="sms_short_code_confirm_title" msgid="1666863092640877318">"¿Enviar SMS premium?"</string>
+ <string name="sms_premium_short_code_confirm_title" msgid="3811263856304367838">"¿Enviar SMS premium?"</string>
+ <string name="sms_short_code_confirm_message" msgid="5616409294907295407">"<b><xliff:g id="APP_NAME">%1$s</xliff:g></b> quiere enviar un mensaje de texto a <b><xliff:g id="DEST_ADDRESS">%2$s</xliff:g></b>, y parece que se trata de un SMS premium.<p>Al enviar mensajes de texto a estos números, es posible que se facturen servicios premium en tu cuenta móvil.<p>¿Quieres permitir que esta aplicación envíe el mensaje?"</string>
+ <string name="sms_premium_short_code_confirm_message" msgid="6214083016284738667">"<b><xliff:g id="APP_NAME">%1$s</xliff:g></b> quiere enviar un mensaje de texto a <b><xliff:g id="DEST_ADDRESS">%2$s</xliff:g></b>, y se trata de un SMS premium.<p><b>Al enviar un mensaje a este destino, se podrán facturar servicios premium en tu cuenta móvil.</b><p>¿Quieres permitir que esta aplicación envíe el mensaje?"</string>
+ <string name="sms_short_code_confirm_allow" msgid="8957573662645722940">"Enviar mensaje"</string>
+ <string name="sms_short_code_confirm_deny" msgid="6374609298084435887">"No enviar"</string>
+ <string name="sms_short_code_confirm_report" msgid="2588793956061677070">"Notificar aplicación malintencionada"</string>
<string name="sim_removed_title" msgid="6227712319223226185">"Tarjeta SIM eliminada"</string>
<string name="sim_removed_message" msgid="2333164559970958645">"La red para celulares no estará disponible hasta que reinicies, luego de insertar una tarjeta SIM válida."</string>
<string name="sim_done_button" msgid="827949989369963775">"Finalizado"</string>
@@ -1063,10 +1067,8 @@
<string name="adb_active_notification_message" msgid="1016654627626476142">"Toca para desactivar la depuración de USB."</string>
<string name="select_input_method" msgid="4653387336791222978">"Selecciona el método de introducción"</string>
<string name="configure_input_methods" msgid="9091652157722495116">"Configurar métodos de introducción"</string>
- <!-- no translation found for use_physical_keyboard (6203112478095117625) -->
- <skip />
- <!-- no translation found for hardware (7517821086888990278) -->
- <skip />
+ <string name="use_physical_keyboard" msgid="6203112478095117625">"Teclado físico"</string>
+ <string name="hardware" msgid="7517821086888990278">"Hardware"</string>
<string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="candidates_style" msgid="4333913089637062257"><u>"candidatos"</u></string>
diff --git a/core/res/res/values-es/strings.xml b/core/res/res/values-es/strings.xml
index 8f50660..9bf23ffd 100644
--- a/core/res/res/values-es/strings.xml
+++ b/core/res/res/values-es/strings.xml
@@ -286,10 +286,8 @@
<string name="permdesc_setOrientation" msgid="3046126619316671476">"Permite que la aplicación cambie la rotación de la pantalla en cualquier momento. Las aplicaciones normales no deberían necesitar este permiso."</string>
<string name="permlab_setPointerSpeed" msgid="9175371613322562934">"cambiar velocidad del puntero"</string>
<string name="permdesc_setPointerSpeed" msgid="6866563234274104233">"Permite que la aplicación modifique la velocidad del puntero del ratón o del trackpad en cualquier momento. Las aplicaciones normales no deberían necesitar este permiso."</string>
- <!-- no translation found for permlab_setKeyboardLayout (4778731703600909340) -->
- <skip />
- <!-- no translation found for permdesc_setKeyboardLayout (8480016771134175879) -->
- <skip />
+ <string name="permlab_setKeyboardLayout" msgid="4778731703600909340">"cambiar el diseño del teclado"</string>
+ <string name="permdesc_setKeyboardLayout" msgid="8480016771134175879">"Permite que la aplicación cambie el diseño del teclado. Las aplicaciones normales no deberían necesitar este permiso."</string>
<string name="permlab_signalPersistentProcesses" msgid="4539002991947376659">"enviar señales Linux a aplicaciones"</string>
<string name="permdesc_signalPersistentProcesses" msgid="4896992079182649141">"Permite que la aplicación solicite que la señal suministrada se envíe a todos los procesos persistentes."</string>
<string name="permlab_persistentActivity" msgid="8841113627955563938">"hacer que la aplicación se ejecute siempre"</string>
@@ -1009,11 +1007,17 @@
<string name="wifi_p2p_enter_pin_message" msgid="5920929550367828970">"Escribe el PIN solicitado:"</string>
<string name="wifi_p2p_show_pin_message" msgid="8530563323880921094">"PIN:"</string>
<string name="select_character" msgid="3365550120617701745">"Insertar carácter"</string>
- <string name="sms_control_default_app_name" msgid="3058577482636640465">"Aplicación desconocida"</string>
<string name="sms_control_title" msgid="7296612781128917719">"Enviando mensajes SMS..."</string>
- <string name="sms_control_message" msgid="4073755190243093924">"Se va a enviar un número elevado de mensajes SMS. Selecciona Aceptar para continuar o Cancelar para detener el envío."</string>
- <string name="sms_control_yes" msgid="2532062172402615953">"Aceptar"</string>
- <string name="sms_control_no" msgid="1715320703137199869">"Cancelar"</string>
+ <string name="sms_control_message" msgid="3867899169651496433">"<b><xliff:g id="APP_NAME">%1$s</xliff:g></b> está enviando un gran número de mensajes SMS. ¿Quieres permitir que está aplicación siga enviando mensajes?"</string>
+ <string name="sms_control_yes" msgid="3663725993855816807">"Permitir"</string>
+ <string name="sms_control_no" msgid="625438561395534982">"Denegar"</string>
+ <string name="sms_short_code_confirm_title" msgid="1666863092640877318">"¿Enviar SMS premium?"</string>
+ <string name="sms_premium_short_code_confirm_title" msgid="3811263856304367838">"¿Enviar SMS premium?"</string>
+ <string name="sms_short_code_confirm_message" msgid="5616409294907295407">"<b><xliff:g id="APP_NAME">%1$s</xliff:g></b> quiere enviar un mensaje de texto a <b><xliff:g id="DEST_ADDRESS">%2$s</xliff:g></b> y parece que se trata de un SMS premium.<p>Al enviar mensajes de texto a estos números, es posible que se facturen servicios premium en tu cuenta móvil.<p>¿Quieres permitir que esta aplicación envíe el mensaje?"</string>
+ <string name="sms_premium_short_code_confirm_message" msgid="6214083016284738667">"<b><xliff:g id="APP_NAME">%1$s</xliff:g></b> quiere enviar un mensaje de texto a <b><xliff:g id="DEST_ADDRESS">%2$s</xliff:g></b> y se trata de un SMS premium.<p><b>Al enviar un mensaje a este destino, se podrán facturar servicios premium en tu cuenta móvil.</b><p>¿Quieres permitir que esta aplicación envíe el mensaje?"</string>
+ <string name="sms_short_code_confirm_allow" msgid="8957573662645722940">"Enviar mensaje"</string>
+ <string name="sms_short_code_confirm_deny" msgid="6374609298084435887">"No enviar"</string>
+ <string name="sms_short_code_confirm_report" msgid="2588793956061677070">"Notificar aplicación malintencionada"</string>
<string name="sim_removed_title" msgid="6227712319223226185">"Tarjeta SIM eliminada"</string>
<string name="sim_removed_message" msgid="2333164559970958645">"La red móvil no estará disponible hasta que reinicies el dispositivo con una tarjeta SIM válida."</string>
<string name="sim_done_button" msgid="827949989369963775">"Listo"</string>
@@ -1063,10 +1067,8 @@
<string name="adb_active_notification_message" msgid="1016654627626476142">"Tocar para inhabilitar la depuración USB"</string>
<string name="select_input_method" msgid="4653387336791222978">"Seleccionar método de introducción"</string>
<string name="configure_input_methods" msgid="9091652157722495116">"Ajustar métodos de introducción"</string>
- <!-- no translation found for use_physical_keyboard (6203112478095117625) -->
- <skip />
- <!-- no translation found for hardware (7517821086888990278) -->
- <skip />
+ <string name="use_physical_keyboard" msgid="6203112478095117625">"Teclado físico"</string>
+ <string name="hardware" msgid="7517821086888990278">"Hardware"</string>
<string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="candidates_style" msgid="4333913089637062257"><u>"candidatos"</u></string>
diff --git a/core/res/res/values-et/strings.xml b/core/res/res/values-et/strings.xml
index 25f3752..c4e0c41 100644
--- a/core/res/res/values-et/strings.xml
+++ b/core/res/res/values-et/strings.xml
@@ -1007,11 +1007,17 @@
<string name="wifi_p2p_enter_pin_message" msgid="5920929550367828970">"Sisestage nõutav PIN-kood:"</string>
<string name="wifi_p2p_show_pin_message" msgid="8530563323880921094">"PIN-kood:"</string>
<string name="select_character" msgid="3365550120617701745">"Sisesta tähemärk"</string>
- <string name="sms_control_default_app_name" msgid="3058577482636640465">"Tundmatu rakendus"</string>
<string name="sms_control_title" msgid="7296612781128917719">"SMS-sõnumite saatmine"</string>
- <string name="sms_control_message" msgid="4073755190243093924">"Saadetakse suur hulk SMS-sõnumid. Saatmise jätkamiseks valige OK, lõpetamiseks Tühista."</string>
- <string name="sms_control_yes" msgid="2532062172402615953">"OK"</string>
- <string name="sms_control_no" msgid="1715320703137199869">"Tühista"</string>
+ <string name="sms_control_message" msgid="3867899169651496433">"<b><xliff:g id="APP_NAME">%1$s</xliff:g></b> saadab suurel hulgal SMS-sõnumeid. Kas tahate lubada sellel rakendusel ka edaspidi sõnumeid saata?"</string>
+ <string name="sms_control_yes" msgid="3663725993855816807">"Luba"</string>
+ <string name="sms_control_no" msgid="625438561395534982">"Keela"</string>
+ <string name="sms_short_code_confirm_title" msgid="1666863092640877318">"Kas saata SMS lühinumbrile?"</string>
+ <string name="sms_premium_short_code_confirm_title" msgid="3811263856304367838">"Kas saata tasuline SMS?"</string>
+ <string name="sms_short_code_confirm_message" msgid="5616409294907295407">"<b><xliff:g id="APP_NAME">%1$s</xliff:g></b> tahab saata tekstsõnumi adressaadile <b><xliff:g id="DEST_ADDRESS">%2$s</xliff:g></b>, mis paistab olevat SMS-i lühinumber.<p>Mõnele lühinumbrile saadetud sõnumi eest võidakse teie mobiilikontole esitada arve tasuliste teenuste eest.<p>Kas lubate rakendusel selle sõnumi saata?"</string>
+ <string name="sms_premium_short_code_confirm_message" msgid="6214083016284738667">"<b><xliff:g id="APP_NAME">%1$s</xliff:g></b> tahab saata tekstisõnumi adressaadile <b><xliff:g id="DEST_ADDRESS">%2$s</xliff:g></b>, mis on tasulise SMS-i lühinumber.<p><b>Kui saadate sõnumi sellele adressaadile, esitatakse teie mobiilikontole arve tasuliste teenuste eest.</b><p>Kas lubate rakendusel sõnumi saata?"</string>
+ <string name="sms_short_code_confirm_allow" msgid="8957573662645722940">"Saada sõnum"</string>
+ <string name="sms_short_code_confirm_deny" msgid="6374609298084435887">"Ära saada"</string>
+ <string name="sms_short_code_confirm_report" msgid="2588793956061677070">"Teata pahatahtlikust rakend."</string>
<string name="sim_removed_title" msgid="6227712319223226185">"SIM-kaart eemaldatud"</string>
<string name="sim_removed_message" msgid="2333164559970958645">"Mobiilsidevõrk ei ole saadaval, kuni sisestate kehtiva SIM-kaardi ja taaskäivitate seadme."</string>
<string name="sim_done_button" msgid="827949989369963775">"Valmis"</string>
diff --git a/core/res/res/values-fa/strings.xml b/core/res/res/values-fa/strings.xml
index d60c59d..6a4c8cb 100644
--- a/core/res/res/values-fa/strings.xml
+++ b/core/res/res/values-fa/strings.xml
@@ -286,10 +286,8 @@
<string name="permdesc_setOrientation" msgid="3046126619316671476">"به برنامه اجازه میدهد تا چرخش صفحه را هر وقت بخواهد تغییر دهد. برای برنامههای عادی نیاز نیست."</string>
<string name="permlab_setPointerSpeed" msgid="9175371613322562934">"تغییر سرعت اشاره گر"</string>
<string name="permdesc_setPointerSpeed" msgid="6866563234274104233">"به برنامه اجازه میدهد تا سرعت ماوس و پد کنترل را هر وقت خواست تغییر دهد. برای برنامههای عادی نیاز نیست."</string>
- <!-- no translation found for permlab_setKeyboardLayout (4778731703600909340) -->
- <skip />
- <!-- no translation found for permdesc_setKeyboardLayout (8480016771134175879) -->
- <skip />
+ <string name="permlab_setKeyboardLayout" msgid="4778731703600909340">"تغییر چیدمان صفحه کلید"</string>
+ <string name="permdesc_setKeyboardLayout" msgid="8480016771134175879">"به برنامه اجازه میدهد تا چیدمان صفحه کلید را تغییر دهد. این کار هیچگاه برای برنامههای عادی نیاز نیست."</string>
<string name="permlab_signalPersistentProcesses" msgid="4539002991947376659">"ارسال سیگنالهای Linux به برنامهها"</string>
<string name="permdesc_signalPersistentProcesses" msgid="4896992079182649141">"به برنامه اجازه میدهد تا درخواست کند سیگنال ارائه شده به همه مراحل دائم ارسال شود."</string>
<string name="permlab_persistentActivity" msgid="8841113627955563938">"همیشه برنامه اجرا شود"</string>
@@ -1009,11 +1007,17 @@
<string name="wifi_p2p_enter_pin_message" msgid="5920929550367828970">"پین لازم را تایپ کنید:"</string>
<string name="wifi_p2p_show_pin_message" msgid="8530563323880921094">"پین:"</string>
<string name="select_character" msgid="3365550120617701745">"درج نویسه"</string>
- <string name="sms_control_default_app_name" msgid="3058577482636640465">"برنامه ناشناخته"</string>
<string name="sms_control_title" msgid="7296612781128917719">"ارسال پیامک ها"</string>
- <string name="sms_control_message" msgid="4073755190243093924">"تعداد زیادی پیام کوتاه ارسال شده است. برای ادامه، \"تأیید\" را لمس کرده و برای توقف ارسال، \"لغو\" را لمس کنید."</string>
- <string name="sms_control_yes" msgid="2532062172402615953">"تأیید"</string>
- <string name="sms_control_no" msgid="1715320703137199869">"لغو"</string>
+ <string name="sms_control_message" msgid="3867899169651496433">"<b><xliff:g id="APP_NAME">%1$s</xliff:g></b> در حال ارسال تعداد زیادی پیامک است. آیا اجازه میدهید این برنامه همچنان پیامک ارسال کند؟"</string>
+ <string name="sms_control_yes" msgid="3663725993855816807">"اجازه دادن"</string>
+ <string name="sms_control_no" msgid="625438561395534982">"ردکردن"</string>
+ <string name="sms_short_code_confirm_title" msgid="1666863092640877318">"پیامک به کد کوتاه ارسال شود؟"</string>
+ <string name="sms_premium_short_code_confirm_title" msgid="3811263856304367838">"پیامک ممتاز ارسال شود؟"</string>
+ <string name="sms_short_code_confirm_message" msgid="5616409294907295407">"<b><xliff:g id="APP_NAME">%1$s</xliff:g></b> میخواهد یک پیام نوشتاری را به <b><xliff:g id="DEST_ADDRESS">%2$s</xliff:g></b>, ارسال کند که به نظر میرسد یک کد کوتاه پیامک است.<p>ارسال پیامهای نوشتاری به برخی از کدهای کوتاه ممکن است باعث شود برای حساب تلفن همراه شما بابت استفاده از سرویسهای ممتاز صورتحساب ارسال شود.<p>آیا به این برنامه اجازه میدهید پیام ارسال کند؟"</string>
+ <string name="sms_premium_short_code_confirm_message" msgid="6214083016284738667">"<b><xliff:g id="APP_NAME">%1$s</xliff:g></b> میخواهد یک پیام نوشتاری را به <b><xliff:g id="DEST_ADDRESS">%2$s</xliff:g></b>, ارسال کند که یک کد کوتاه پیامک ممتاز است.<p><b>ارسال پیام به این مقصد ممکن است باعث شود برای حساب تلفن همراه شما بابت استفاده از سرویسهای ممتاز صورتحساب ارسال شود.</b><p>آیا به این برنامه اجازه میدهید پیامک ارسال کند؟"</string>
+ <string name="sms_short_code_confirm_allow" msgid="8957573662645722940">"ارسال پیام"</string>
+ <string name="sms_short_code_confirm_deny" msgid="6374609298084435887">"ارسال نشود"</string>
+ <string name="sms_short_code_confirm_report" msgid="2588793956061677070">"گزارش برنامه مخرب"</string>
<string name="sim_removed_title" msgid="6227712319223226185">"سیم کارت برداشته شد"</string>
<string name="sim_removed_message" msgid="2333164559970958645">"تا وقتی که با یک سیمکارت معتبر راهاندازی مجدد نکنید شبکه تلفن همراه غیر قابل دسترس خواهد بود."</string>
<string name="sim_done_button" msgid="827949989369963775">"انجام شد"</string>
@@ -1063,10 +1067,8 @@
<string name="adb_active_notification_message" msgid="1016654627626476142">"غیرفعال کردن اشکال زدایی USB را لمس کنید."</string>
<string name="select_input_method" msgid="4653387336791222978">"انتخاب روش ورودی"</string>
<string name="configure_input_methods" msgid="9091652157722495116">"تنظیم روشهای ورودی"</string>
- <!-- no translation found for use_physical_keyboard (6203112478095117625) -->
- <skip />
- <!-- no translation found for hardware (7517821086888990278) -->
- <skip />
+ <string name="use_physical_keyboard" msgid="6203112478095117625">"صفحه کلید فیزیکی"</string>
+ <string name="hardware" msgid="7517821086888990278">"سختافزار"</string>
<string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="candidates_style" msgid="4333913089637062257"><u>"داوطلبین"</u></string>
diff --git a/core/res/res/values-fi/strings.xml b/core/res/res/values-fi/strings.xml
index 211fab2..4451192 100644
--- a/core/res/res/values-fi/strings.xml
+++ b/core/res/res/values-fi/strings.xml
@@ -286,10 +286,8 @@
<string name="permdesc_setOrientation" msgid="3046126619316671476">"Antaa sovelluksen muuttaa näytön kiertoa milloin tahansa. Ei tavallisten sovellusten käyttöön."</string>
<string name="permlab_setPointerSpeed" msgid="9175371613322562934">"muuta osoittimen nopeutta"</string>
<string name="permdesc_setPointerSpeed" msgid="6866563234274104233">"Antaa sovelluksen muuttaa hiiren tai kosketuslevyn osoittimen nopeutta milloin tahansa. Ei tavallisten sovellusten käyttöön."</string>
- <!-- no translation found for permlab_setKeyboardLayout (4778731703600909340) -->
- <skip />
- <!-- no translation found for permdesc_setKeyboardLayout (8480016771134175879) -->
- <skip />
+ <string name="permlab_setKeyboardLayout" msgid="4778731703600909340">"vaihda näppäimistön asettelua"</string>
+ <string name="permdesc_setKeyboardLayout" msgid="8480016771134175879">"Antaa sovelluksen muuttaa näppäimistön asettelua. Ei tavallisten sovellusten käyttöön."</string>
<string name="permlab_signalPersistentProcesses" msgid="4539002991947376659">"Linux-signaalien lähettäminen sovelluksille"</string>
<string name="permdesc_signalPersistentProcesses" msgid="4896992079182649141">"Antaa sovelluksen pyytää, että tarjottu signaali lähetetään kaikille käynnissä oleville prosesseille."</string>
<string name="permlab_persistentActivity" msgid="8841113627955563938">"sovelluksen asettaminen aina käynnissä olevaksi"</string>
@@ -1009,11 +1007,17 @@
<string name="wifi_p2p_enter_pin_message" msgid="5920929550367828970">"Kirjoita pyydetty PIN-koodi:"</string>
<string name="wifi_p2p_show_pin_message" msgid="8530563323880921094">"PIN-koodi:"</string>
<string name="select_character" msgid="3365550120617701745">"Lisää merkki"</string>
- <string name="sms_control_default_app_name" msgid="3058577482636640465">"Tuntematon sovellus"</string>
<string name="sms_control_title" msgid="7296612781128917719">"Tekstiviestien lähettäminen"</string>
- <string name="sms_control_message" msgid="4073755190243093924">"Olet lähettämässä suurta määrää tekstiviestejä. Jatka koskettamalla OK tai peruuta lähetys valitsemalla Peruuta."</string>
- <string name="sms_control_yes" msgid="2532062172402615953">"OK"</string>
- <string name="sms_control_no" msgid="1715320703137199869">"Peruuta"</string>
+ <string name="sms_control_message" msgid="3867899169651496433">"<b><xliff:g id="APP_NAME">%1$s</xliff:g></b> lähettää suuria määriä tekstiviestejä. Annetaanko tämän sovelluksen jatkaa tekstiviestien lähettämistä?"</string>
+ <string name="sms_control_yes" msgid="3663725993855816807">"Salli"</string>
+ <string name="sms_control_no" msgid="625438561395534982">"Kiellä"</string>
+ <string name="sms_short_code_confirm_title" msgid="1666863092640877318">"Lähetetäänkö viesti?"</string>
+ <string name="sms_premium_short_code_confirm_title" msgid="3811263856304367838">"Lähetä maksullinen viesti?"</string>
+ <string name="sms_short_code_confirm_message" msgid="5616409294907295407">"<b><xliff:g id="APP_NAME">%1$s</xliff:g></b> haluaa lähettää tekstiviestin kohteeseen <b><xliff:g id="DEST_ADDRESS">%2$s</xliff:g></b>, joka voi olla maksullinen numero.<p><b>Jos lähetät viestin tähän kohteeseen, sinua saatetaan veloittaa maksullisten palveluiden käytöstä.</b><p>Annetaanko sovelluksen lähettää viesti?"</string>
+ <string name="sms_premium_short_code_confirm_message" msgid="6214083016284738667">"<b><xliff:g id="APP_NAME">%1$s</xliff:g></b> haluaa lähettää tekstiviestin kohteeseen <b><xliff:g id="DEST_ADDRESS">%2$s</xliff:g></b>, joka on maksullinen numero.<p><b>Jos lähetät viestin tähän kohteeseen, sinua veloitetaan maksullisten palveluiden käytöstä.</b><p>Annetaanko sovelluksen lähettää viesti?"</string>
+ <string name="sms_short_code_confirm_allow" msgid="8957573662645722940">"Lähetä viesti"</string>
+ <string name="sms_short_code_confirm_deny" msgid="6374609298084435887">"Älä lähetä"</string>
+ <string name="sms_short_code_confirm_report" msgid="2588793956061677070">"Ilmoita haittasovelluksesta"</string>
<string name="sim_removed_title" msgid="6227712319223226185">"SIM-kortti poistettu"</string>
<string name="sim_removed_message" msgid="2333164559970958645">"Mobiiliverkko ei ole käytettävissä, ennen kuin käynnistät uudelleen kelvollisella laitteeseen kytketyllä SIM-kortilla."</string>
<string name="sim_done_button" msgid="827949989369963775">"Valmis"</string>
@@ -1063,10 +1067,8 @@
<string name="adb_active_notification_message" msgid="1016654627626476142">"Poista USB-vianetsintä käytöstä koskettamalla tätä."</string>
<string name="select_input_method" msgid="4653387336791222978">"Valitse syöttötapa"</string>
<string name="configure_input_methods" msgid="9091652157722495116">"Määritä syöttötavat"</string>
- <!-- no translation found for use_physical_keyboard (6203112478095117625) -->
- <skip />
- <!-- no translation found for hardware (7517821086888990278) -->
- <skip />
+ <string name="use_physical_keyboard" msgid="6203112478095117625">"Fyysinen näppäimistö"</string>
+ <string name="hardware" msgid="7517821086888990278">"Laitteisto"</string>
<string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZÅÄÖ"</string>
<string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="candidates_style" msgid="4333913089637062257"><u>"kandidaatit"</u></string>
diff --git a/core/res/res/values-fr/strings.xml b/core/res/res/values-fr/strings.xml
index 787bdda..2d5dbb1 100644
--- a/core/res/res/values-fr/strings.xml
+++ b/core/res/res/values-fr/strings.xml
@@ -1007,11 +1007,17 @@
<string name="wifi_p2p_enter_pin_message" msgid="5920929550367828970">"Saisissez le code PIN requis :"</string>
<string name="wifi_p2p_show_pin_message" msgid="8530563323880921094">"Code PIN :"</string>
<string name="select_character" msgid="3365550120617701745">"Insérer un caractère"</string>
- <string name="sms_control_default_app_name" msgid="3058577482636640465">"Application inconnue"</string>
<string name="sms_control_title" msgid="7296612781128917719">"Envoi de messages SMS"</string>
- <string name="sms_control_message" msgid="4073755190243093924">"Vous êtes sur le point d\'envoyer un grand nombre de SMS. Appuyez sur \"OK\" pour continuer ou sur \"Annuler\" pour interrompre l\'envoi."</string>
- <string name="sms_control_yes" msgid="2532062172402615953">"OK"</string>
- <string name="sms_control_no" msgid="1715320703137199869">"Annuler"</string>
+ <string name="sms_control_message" msgid="3867899169651496433">"<b><xliff:g id="APP_NAME">%1$s</xliff:g></b> envoie un grand nombre de SMS. Autorisez-vous cette application à poursuivre l\'envoi des messages ?"</string>
+ <string name="sms_control_yes" msgid="3663725993855816807">"Autoriser"</string>
+ <string name="sms_control_no" msgid="625438561395534982">"Refuser"</string>
+ <string name="sms_short_code_confirm_title" msgid="1666863092640877318">"Envoyer SMS au numéro abrégé ?"</string>
+ <string name="sms_premium_short_code_confirm_title" msgid="3811263856304367838">"Envoyer un SMS premium ?"</string>
+ <string name="sms_short_code_confirm_message" msgid="5616409294907295407">"<b><xliff:g id="APP_NAME">%1$s</xliff:g></b> essaie d\'envoyer un SMS à <b><xliff:g id="DEST_ADDRESS">%2$s</xliff:g></b>. Il s\'agit apparemment d\'un numéro abrégé.<p>L\'envoi de SMS à de tels numéros peut entraîner la facturation de services premium sur votre compte mobile.<p>Autorisez-vous cette application à envoyer ce message ?"</string>
+ <string name="sms_premium_short_code_confirm_message" msgid="6214083016284738667">"<b><xliff:g id="APP_NAME">%1$s</xliff:g></b> essaie d\'envoyer un SMS à <b><xliff:g id="DEST_ADDRESS">%2$s</xliff:g></b>. Il s\'agit apparemment d\'un numéro abrégé de type premium.<p><b>L\'envoi de SMS à ce destinataire entraînera la facturation de services premium sur votre compte mobile.</b><p>Autorisez-vous cette application à envoyer le message ?"</string>
+ <string name="sms_short_code_confirm_allow" msgid="8957573662645722940">"Envoyer le message"</string>
+ <string name="sms_short_code_confirm_deny" msgid="6374609298084435887">"Ne pas envoyer"</string>
+ <string name="sms_short_code_confirm_report" msgid="2588793956061677070">"Signaler appli malveillante"</string>
<string name="sim_removed_title" msgid="6227712319223226185">"Carte SIM retirée"</string>
<string name="sim_removed_message" msgid="2333164559970958645">"Le réseau mobile ne sera pas disponible avant le redémarrage avec une carte SIM valide insérée."</string>
<string name="sim_done_button" msgid="827949989369963775">"OK"</string>
diff --git a/core/res/res/values-hi/strings.xml b/core/res/res/values-hi/strings.xml
index 1a95f32..6eeb942 100644
--- a/core/res/res/values-hi/strings.xml
+++ b/core/res/res/values-hi/strings.xml
@@ -286,10 +286,8 @@
<string name="permdesc_setOrientation" msgid="3046126619316671476">"एप्लिकेशन को किसी भी समय स्क्रीन का रोटेशन बदलने देता है. सामान्य एप्लिकेशन के लिए कभी भी आवश्यक नहीं होना चाहिए."</string>
<string name="permlab_setPointerSpeed" msgid="9175371613322562934">"सूचक गति बदलें"</string>
<string name="permdesc_setPointerSpeed" msgid="6866563234274104233">"एप्लिकेशन को माउस या ट्रैकपैड सूचक गति को किसी भी समय बदलने देता है. सामान्य एप्लिकेशन के लिए कभी भी आवश्यक नहीं होना चाहिए."</string>
- <!-- no translation found for permlab_setKeyboardLayout (4778731703600909340) -->
- <skip />
- <!-- no translation found for permdesc_setKeyboardLayout (8480016771134175879) -->
- <skip />
+ <string name="permlab_setKeyboardLayout" msgid="4778731703600909340">"कीबोर्ड लेआउट बदलें"</string>
+ <string name="permdesc_setKeyboardLayout" msgid="8480016771134175879">"एप्लिकेशन को कीबोर्ड लेआउट बदलने देता है. सामान्य एप्लिकेशन के लिए कभी आवश्यक नहीं है."</string>
<string name="permlab_signalPersistentProcesses" msgid="4539002991947376659">"एप्लिकेशन को Linux सिग्नल भेजें"</string>
<string name="permdesc_signalPersistentProcesses" msgid="4896992079182649141">"एप्लिकेशन को यह अनुरोध करने देता है कि दिया गया सिग्नल सभी जारी प्रक्रियाओं को भेजा जाए."</string>
<string name="permlab_persistentActivity" msgid="8841113627955563938">"एप्लिकेशन को हमेशा चलने वाला बनाएं"</string>
@@ -1009,11 +1007,17 @@
<string name="wifi_p2p_enter_pin_message" msgid="5920929550367828970">"आवश्यक पिन लिखें:"</string>
<string name="wifi_p2p_show_pin_message" msgid="8530563323880921094">"पिन:"</string>
<string name="select_character" msgid="3365550120617701745">"वर्ण सम्मिलित करें"</string>
- <string name="sms_control_default_app_name" msgid="3058577482636640465">"अज्ञात एप्लिकेशन"</string>
<string name="sms_control_title" msgid="7296612781128917719">"SMS संदेश भेज रहा है"</string>
- <string name="sms_control_message" msgid="4073755190243093924">"बड़ी संख्या में SMS संदेश भेजे जा रहे हैं. जारी रखने के लिए ठीक स्पर्श करें, या भेजना बंद करने के लिए रद्द करें स्पर्श करें."</string>
- <string name="sms_control_yes" msgid="2532062172402615953">"ठीक"</string>
- <string name="sms_control_no" msgid="1715320703137199869">"रद्द करें"</string>
+ <string name="sms_control_message" msgid="3867899169651496433">"<b><xliff:g id="APP_NAME">%1$s</xliff:g></b> बड़ी संख्या में SMS संदेश भेज रहा है. क्या आप इस एप्लिकेशन को संदेश भेजना जारी रखने देना चाहते हैं?"</string>
+ <string name="sms_control_yes" msgid="3663725993855816807">"अनुमति दें"</string>
+ <string name="sms_control_no" msgid="625438561395534982">"अस्वीकार करें"</string>
+ <string name="sms_short_code_confirm_title" msgid="1666863092640877318">"शॉर्ट कोड पर SMS भेजें?"</string>
+ <string name="sms_premium_short_code_confirm_title" msgid="3811263856304367838">"प्रीमियम SMS भेजें?"</string>
+ <string name="sms_short_code_confirm_message" msgid="5616409294907295407">"<b><xliff:g id="APP_NAME">%1$s</xliff:g></b>, <b><xliff:g id="DEST_ADDRESS">%2$s</xliff:g></b> को एक पाठ संदेश भेजना चाहता है, जो एक SMS शॉर्ट कोड लगता है.<p>कुछ शॉर्ट कोड को पाठ संदेश भेजने से आपके मोबाइल खाते पर प्रीमियम सेवाओं का शुल्क लिया जा सकता है.<p>क्या आप इस एप्लिकेशन को यह संदेश भेजने देना चाहते हैं?"</string>
+ <string name="sms_premium_short_code_confirm_message" msgid="6214083016284738667">"<b><xliff:g id="APP_NAME">%1$s</xliff:g></b>, <b><xliff:g id="DEST_ADDRESS">%2$s</xliff:g></b> को एक पाठ संदेश भेजना चाहता है, जो एक प्रीमियम SMS शॉर्ट कोड है.<p><b>इस गंतव्य पर कोई संदेश भेजने से आपके मोबाइल खाते पर प्रीमियम सेवाओं का शुल्क लिया जाएगा.</b><p>क्या आप इस एप्लिकेशन को संदेश भेजने देना चाहते हैं?"</string>
+ <string name="sms_short_code_confirm_allow" msgid="8957573662645722940">"संदेश भेजें"</string>
+ <string name="sms_short_code_confirm_deny" msgid="6374609298084435887">"न भेजें"</string>
+ <string name="sms_short_code_confirm_report" msgid="2588793956061677070">"दुर्भावनापूर्ण एप्लि. की रिपोर्ट करें"</string>
<string name="sim_removed_title" msgid="6227712319223226185">"सिमकार्ड निकाला गया"</string>
<string name="sim_removed_message" msgid="2333164559970958645">"मान्य सिम कार्ड डालकर पुन: प्रारंभ करने तक मोबाइल नेटवर्क अनुपलब्ध रहेगा."</string>
<string name="sim_done_button" msgid="827949989369963775">"पूर्ण"</string>
@@ -1063,10 +1067,8 @@
<string name="adb_active_notification_message" msgid="1016654627626476142">"USB डीबग करना अक्षम करने के लिए स्पर्श करें."</string>
<string name="select_input_method" msgid="4653387336791222978">"इनपुट पद्धति चुनें"</string>
<string name="configure_input_methods" msgid="9091652157722495116">"इनपुट पद्धतियां सेट करें"</string>
- <!-- no translation found for use_physical_keyboard (6203112478095117625) -->
- <skip />
- <!-- no translation found for hardware (7517821086888990278) -->
- <skip />
+ <string name="use_physical_keyboard" msgid="6203112478095117625">"भौतिक कीबोर्ड"</string>
+ <string name="hardware" msgid="7517821086888990278">"हार्डवेयर"</string>
<string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="candidates_style" msgid="4333913089637062257"><u>"उम्मीदवार"</u></string>
diff --git a/core/res/res/values-hr/strings.xml b/core/res/res/values-hr/strings.xml
index 0591e04..0409168 100644
--- a/core/res/res/values-hr/strings.xml
+++ b/core/res/res/values-hr/strings.xml
@@ -286,10 +286,8 @@
<string name="permdesc_setOrientation" msgid="3046126619316671476">"Omogućuje aplikaciji promjenu rotacije zaslona u bilo kojem trenutku. Ne bi smjelo biti potrebno za normalne aplikacije."</string>
<string name="permlab_setPointerSpeed" msgid="9175371613322562934">"promjena brzine pokazivača"</string>
<string name="permdesc_setPointerSpeed" msgid="6866563234274104233">"Omogućuje aplikaciji promjenu brzine miša ili dodirne pločice. Ne bi smjelo biti potrebno za normalne aplikacije."</string>
- <!-- no translation found for permlab_setKeyboardLayout (4778731703600909340) -->
- <skip />
- <!-- no translation found for permdesc_setKeyboardLayout (8480016771134175879) -->
- <skip />
+ <string name="permlab_setKeyboardLayout" msgid="4778731703600909340">"promjena rasporeda tipkovnice"</string>
+ <string name="permdesc_setKeyboardLayout" msgid="8480016771134175879">"Omogućuje da aplikacija promijeni raspored tipkovnice. Nikada ne bi trebalo biti potrebno za uobičajene aplikacije."</string>
<string name="permlab_signalPersistentProcesses" msgid="4539002991947376659">"slanje Linux signala aplikacijama"</string>
<string name="permdesc_signalPersistentProcesses" msgid="4896992079182649141">"Aplikaciji omogućuje zahtijevanje da isporučeni signal bude poslan na sve trajne procese."</string>
<string name="permlab_persistentActivity" msgid="8841113627955563938">"trajni rad aplikacije"</string>
@@ -1009,11 +1007,17 @@
<string name="wifi_p2p_enter_pin_message" msgid="5920929550367828970">"Upišite potreban PIN:"</string>
<string name="wifi_p2p_show_pin_message" msgid="8530563323880921094">"PIN:"</string>
<string name="select_character" msgid="3365550120617701745">"Umetni znak"</string>
- <string name="sms_control_default_app_name" msgid="3058577482636640465">"Nepoznata aplikacija"</string>
<string name="sms_control_title" msgid="7296612781128917719">"Slanje SMS poruka"</string>
- <string name="sms_control_message" msgid="4073755190243093924">"Šalje se velika količina SMS poruka. Dodirnite \"U redu\" za nastavak ili \"Odustani\" za prekid slanja."</string>
- <string name="sms_control_yes" msgid="2532062172402615953">"U redu"</string>
- <string name="sms_control_no" msgid="1715320703137199869">"Odustani"</string>
+ <string name="sms_control_message" msgid="3867899169651496433">"Aplikacija <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> šalje veliki broj SMS poruka. Želite li dopustiti ovoj aplikaciji da nastavi slati poruke?"</string>
+ <string name="sms_control_yes" msgid="3663725993855816807">"Dopusti"</string>
+ <string name="sms_control_no" msgid="625438561395534982">"Odbij"</string>
+ <string name="sms_short_code_confirm_title" msgid="1666863092640877318">"Poslati SMS na skraćeni broj?"</string>
+ <string name="sms_premium_short_code_confirm_title" msgid="3811263856304367838">"Poslati premium SMS?"</string>
+ <string name="sms_short_code_confirm_message" msgid="5616409294907295407">"Aplikacija <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> želi poslati tekstnu poruku na <b><xliff:g id="DEST_ADDRESS">%2$s</xliff:g></b>, a čini se da je to skraćeni SMS broj.<p>Slanje tekstnih poruka na neke skraćene interne brojeve može dovesti do naplate premium usluga na vašem računu mobilnog uređaja.<p>Želite li dopustiti aplikaciji da pošalje poruku?"</string>
+ <string name="sms_premium_short_code_confirm_message" msgid="6214083016284738667">"Aplikacija <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> želi poslati tekstnu poruku na <b><xliff:g id="DEST_ADDRESS">%2$s</xliff:g></b>, a to je skraćeni premium SMS broj.<p><b>Slanje poruke na taj broj dovest će do naplate premium usluga na vašem računu mobilnog uređaja.</b><p>Želite li dopustiti toj aplikaciji da pošalje poruku?"</string>
+ <string name="sms_short_code_confirm_allow" msgid="8957573662645722940">"Pošalji poruku"</string>
+ <string name="sms_short_code_confirm_deny" msgid="6374609298084435887">"Ne šalji"</string>
+ <string name="sms_short_code_confirm_report" msgid="2588793956061677070">"Prijavi zlonamjerne aplikacije"</string>
<string name="sim_removed_title" msgid="6227712319223226185">"SIM kartica uklonjena"</string>
<string name="sim_removed_message" msgid="2333164559970958645">"Mobilna mreža bit će nedostupna do ponovnog pokretanja s umetnutom važećom SIM karticom."</string>
<string name="sim_done_button" msgid="827949989369963775">"Gotovo"</string>
@@ -1063,10 +1067,8 @@
<string name="adb_active_notification_message" msgid="1016654627626476142">"Dodirnite da biste onemogućili rješavanje programske pogreške na USB-u."</string>
<string name="select_input_method" msgid="4653387336791222978">"Odabir načina unosa"</string>
<string name="configure_input_methods" msgid="9091652157722495116">"Postavljanje načina unosa"</string>
- <!-- no translation found for use_physical_keyboard (6203112478095117625) -->
- <skip />
- <!-- no translation found for hardware (7517821086888990278) -->
- <skip />
+ <string name="use_physical_keyboard" msgid="6203112478095117625">"Fizička tipkovnica"</string>
+ <string name="hardware" msgid="7517821086888990278">"Hardver"</string>
<string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="candidates_style" msgid="4333913089637062257"><u>"kandidati"</u></string>
diff --git a/core/res/res/values-hu/strings.xml b/core/res/res/values-hu/strings.xml
index 4043aef..e57c157 100644
--- a/core/res/res/values-hu/strings.xml
+++ b/core/res/res/values-hu/strings.xml
@@ -286,10 +286,8 @@
<string name="permdesc_setOrientation" msgid="3046126619316671476">"Lehetővé teszi az alkalmazás számára a képernyő elforgatásának bármikori módosítását. A normál alkalmazásoknak erre soha nincs szüksége."</string>
<string name="permlab_setPointerSpeed" msgid="9175371613322562934">"mutató sebességének módosítása"</string>
<string name="permdesc_setPointerSpeed" msgid="6866563234274104233">"Lehetővé teszi az alkalmazás számára, hogy bármikor módosítsa az egér vagy az érintőpad mutatójának sebességét. Normál alkalmazásoknak soha nem lehet rá szükségük."</string>
- <!-- no translation found for permlab_setKeyboardLayout (4778731703600909340) -->
- <skip />
- <!-- no translation found for permdesc_setKeyboardLayout (8480016771134175879) -->
- <skip />
+ <string name="permlab_setKeyboardLayout" msgid="4778731703600909340">"billentyűkiosztás módosítása"</string>
+ <string name="permdesc_setKeyboardLayout" msgid="8480016771134175879">"Lehetővé teszi az alkalmazás számára, hogy módosítsa a billentyűzetkiosztást. Normál alkalmazásoknak alapesetben nem lehet szükségük rá."</string>
<string name="permlab_signalPersistentProcesses" msgid="4539002991947376659">"Linux-jelek küldése az alkalmazásoknak"</string>
<string name="permdesc_signalPersistentProcesses" msgid="4896992079182649141">"Lehetővé teszi az alkalmazás számára, hogy a megadott jelet elküldje az összes állandó folyamatnak."</string>
<string name="permlab_persistentActivity" msgid="8841113627955563938">"az alkalmazás állandó futtatása"</string>
@@ -1009,11 +1007,17 @@
<string name="wifi_p2p_enter_pin_message" msgid="5920929550367828970">"Adja meg a szükséges PIN kódot:"</string>
<string name="wifi_p2p_show_pin_message" msgid="8530563323880921094">"PIN kód:"</string>
<string name="select_character" msgid="3365550120617701745">"Karakter beszúrása"</string>
- <string name="sms_control_default_app_name" msgid="3058577482636640465">"Ismeretlen alkalmazás"</string>
<string name="sms_control_title" msgid="7296612781128917719">"SMS-ek küldése"</string>
- <string name="sms_control_message" msgid="4073755190243093924">"Nagy számú SMS-t kíván elküldeni. A folytatáshoz érintse meg az \"OK\", a küldés leállításához a \"Mégse\" lehetőséget."</string>
- <string name="sms_control_yes" msgid="2532062172402615953">"OK"</string>
- <string name="sms_control_no" msgid="1715320703137199869">"Mégse"</string>
+ <string name="sms_control_message" msgid="3867899169651496433">"<b><xliff:g id="APP_NAME">%1$s</xliff:g></ b> nagyszámú SMS üzenetet küld. Engedélyezi, hogy ez az alkalmazás továbbra is üzeneteket küldjön?"</string>
+ <string name="sms_control_yes" msgid="3663725993855816807">"Engedélyezés"</string>
+ <string name="sms_control_no" msgid="625438561395534982">"Elutasítás"</string>
+ <string name="sms_short_code_confirm_title" msgid="1666863092640877318">"SMS küldése a rövid kódra?"</string>
+ <string name="sms_premium_short_code_confirm_title" msgid="3811263856304367838">"Elküldi a prémium SMS-t?"</string>
+ <string name="sms_short_code_confirm_message" msgid="5616409294907295407">"A(z) <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> szöveges üzenetet szeretne küldeni a(z) <b><xliff:g id="DEST_ADDRESS">%2$s</xliff:g></b> címre, ami egy SMS rövid kódja.<p>Az egyes rövid kódokra küldött üzenetek miatt mobilszámláján prémiumszolgáltatások lesznek kiszámlázva.</b><p>Engedélyezi, hogy az alkalmazás elküldje az üzenetet?"</string>
+ <string name="sms_premium_short_code_confirm_message" msgid="6214083016284738667">"A(z) <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> szöveges üzenetet szeretne küldeni a(z) <b><xliff:g id="DEST_ADDRESS">%2$s</xliff:g></b> címre, ami egy prémium SMS rövid kódja.<p>Az ide küldött üzenet miatt mobilszámláján prémiumszolgáltatások lesznek kiszámlázva.</b><p>Engedélyezi, hogy az alkalmazás elküldje az üzenetet?"</string>
+ <string name="sms_short_code_confirm_allow" msgid="8957573662645722940">"Üzenet küldése"</string>
+ <string name="sms_short_code_confirm_deny" msgid="6374609298084435887">"Nincs küldés"</string>
+ <string name="sms_short_code_confirm_report" msgid="2588793956061677070">"Rosszindulatú alk. bejelentése"</string>
<string name="sim_removed_title" msgid="6227712319223226185">"SIM-kártya eltávolítva"</string>
<string name="sim_removed_message" msgid="2333164559970958645">"A mobilhálózat nem lesz elérhető, amíg újra nem indítja egy érvényes SIM kártya behelyezése után."</string>
<string name="sim_done_button" msgid="827949989369963775">"Kész"</string>
@@ -1063,10 +1067,8 @@
<string name="adb_active_notification_message" msgid="1016654627626476142">"Érintse meg az USB hibakeresés kikapcsolásához."</string>
<string name="select_input_method" msgid="4653387336791222978">"Beviteli mód kiválasztása"</string>
<string name="configure_input_methods" msgid="9091652157722495116">"Beviteli módok beállítása"</string>
- <!-- no translation found for use_physical_keyboard (6203112478095117625) -->
- <skip />
- <!-- no translation found for hardware (7517821086888990278) -->
- <skip />
+ <string name="use_physical_keyboard" msgid="6203112478095117625">"Fizikai billentyűzet"</string>
+ <string name="hardware" msgid="7517821086888990278">"Hardver"</string>
<string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="candidates_style" msgid="4333913089637062257"><u>"jelöltek"</u></string>
diff --git a/core/res/res/values-in/strings.xml b/core/res/res/values-in/strings.xml
index 7a52979..03c7f79 100644
--- a/core/res/res/values-in/strings.xml
+++ b/core/res/res/values-in/strings.xml
@@ -286,10 +286,8 @@
<string name="permdesc_setOrientation" msgid="3046126619316671476">"Mengizinkan apl mengubah rotasi layar kapan saja. Tidak pernah dibutuhkan oleh apl normal."</string>
<string name="permlab_setPointerSpeed" msgid="9175371613322562934">"ubah kecepatan penunjuk"</string>
<string name="permdesc_setPointerSpeed" msgid="6866563234274104233">"Mengizinkan apl mengubah kecepatan mouse atau pointer trackpad kapan saja. Tidak pernah diperlukan oleh apl normal."</string>
- <!-- no translation found for permlab_setKeyboardLayout (4778731703600909340) -->
- <skip />
- <!-- no translation found for permdesc_setKeyboardLayout (8480016771134175879) -->
- <skip />
+ <string name="permlab_setKeyboardLayout" msgid="4778731703600909340">"Ubah tata letak keyboard"</string>
+ <string name="permdesc_setKeyboardLayout" msgid="8480016771134175879">"Memungkinkan aplikasi untuk mengubah tata letak keyboard. Tidak pernah dibutuhkan oleh aplikasi normal."</string>
<string name="permlab_signalPersistentProcesses" msgid="4539002991947376659">"mengirim sinyal Linux ke apl"</string>
<string name="permdesc_signalPersistentProcesses" msgid="4896992079182649141">"Mengizinkan apl meminta agar sinyal yang disediakan dikirim ke semua proses yang ada."</string>
<string name="permlab_persistentActivity" msgid="8841113627955563938">"membuat apl selalu berjalan"</string>
@@ -1009,11 +1007,17 @@
<string name="wifi_p2p_enter_pin_message" msgid="5920929550367828970">"Ketik PIN yang diminta:"</string>
<string name="wifi_p2p_show_pin_message" msgid="8530563323880921094">"PIN:"</string>
<string name="select_character" msgid="3365550120617701745">"Sisipkan huruf"</string>
- <string name="sms_control_default_app_name" msgid="3058577482636640465">"Apl tak dikenal"</string>
<string name="sms_control_title" msgid="7296612781128917719">"Mengirim pesan SMS"</string>
- <string name="sms_control_message" msgid="4073755190243093924">"Pesan SMS dalam jumlah besar sedang dikirimkan. Sentuh Oke untuk melanjutkan, atau Batal untuk menghentikan pengiriman."</string>
- <string name="sms_control_yes" msgid="2532062172402615953">"Oke"</string>
- <string name="sms_control_no" msgid="1715320703137199869">"Batal"</string>
+ <string name="sms_control_message" msgid="3867899169651496433">"<b><xliff:g id="APP_NAME">%1$s</xliff:g></b> sedang mengirim pesan SMS dalam jumlah besar. Izinkan aplikasi ini untuk melanjutkan pengiriman pesan?"</string>
+ <string name="sms_control_yes" msgid="3663725993855816807">"Izinkan"</string>
+ <string name="sms_control_no" msgid="625438561395534982">"Tolak"</string>
+ <string name="sms_short_code_confirm_title" msgid="1666863092640877318">"Kirim SMS ke kode singkat?"</string>
+ <string name="sms_premium_short_code_confirm_title" msgid="3811263856304367838">"Kirim SMS premium?"</string>
+ <string name="sms_short_code_confirm_message" msgid="5616409294907295407">"<b><xliff:g id="APP_NAME">%1$s</xliff:g></b> akan mengirim pesan teks ke <b><xliff:g id="DEST_ADDRESS">%2$s</xliff:g></b>, yang akan muncul sebagai kode singkat SMS.<p>Mengirim pesan teks ke beberapa kode singkat menyebabkan Anda dikenakan biaya layanan premium pada akun seluler Anda.<p>Izinkan aplikasi ini mengirim pesan?"</string>
+ <string name="sms_premium_short_code_confirm_message" msgid="6214083016284738667">"<b><xliff:g id="APP_NAME">%1$s</xliff:g></b> akan mengirim pesan teks ke <b><xliff:g id="DEST_ADDRESS">%2$s</xliff:g></b>, yang merupakan kode singkat SMS premium.<p><b>Mengirim pesan ke tujuan ini menyebabkan Anda dikenakan biaya layanan premium pada akun seluler Anda.</b><p>Izinkan aplikasi ini mengirim pesan?"</string>
+ <string name="sms_short_code_confirm_allow" msgid="8957573662645722940">"Kirim pesan"</string>
+ <string name="sms_short_code_confirm_deny" msgid="6374609298084435887">"Jangan kirim"</string>
+ <string name="sms_short_code_confirm_report" msgid="2588793956061677070">"Laporkan aplikasi berbahaya"</string>
<string name="sim_removed_title" msgid="6227712319223226185">"Kartu SIM dihapus"</string>
<string name="sim_removed_message" msgid="2333164559970958645">"Jaringan seluler tidak akan tersedia sampai Anda memulai lagi dengan memasukkan kartu SIM yang valid."</string>
<string name="sim_done_button" msgid="827949989369963775">"Selesai"</string>
@@ -1063,10 +1067,8 @@
<string name="adb_active_notification_message" msgid="1016654627626476142">"Sentuh untuk menonaktifkan debugging USB."</string>
<string name="select_input_method" msgid="4653387336791222978">"Pilih metode masukan"</string>
<string name="configure_input_methods" msgid="9091652157722495116">"Menyiapkan metode masukan"</string>
- <!-- no translation found for use_physical_keyboard (6203112478095117625) -->
- <skip />
- <!-- no translation found for hardware (7517821086888990278) -->
- <skip />
+ <string name="use_physical_keyboard" msgid="6203112478095117625">"Keyboard fisik"</string>
+ <string name="hardware" msgid="7517821086888990278">"Perangkat Keras"</string>
<string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="candidates_style" msgid="4333913089637062257"><u>"calon"</u></string>
diff --git a/core/res/res/values-it/strings.xml b/core/res/res/values-it/strings.xml
index 9073bf1..7ec07d2 100644
--- a/core/res/res/values-it/strings.xml
+++ b/core/res/res/values-it/strings.xml
@@ -1007,11 +1007,17 @@
<string name="wifi_p2p_enter_pin_message" msgid="5920929550367828970">"Inserisci il PIN richiesto:"</string>
<string name="wifi_p2p_show_pin_message" msgid="8530563323880921094">"PIN:"</string>
<string name="select_character" msgid="3365550120617701745">"Inserisci carattere"</string>
- <string name="sms_control_default_app_name" msgid="3058577482636640465">"Applicazione sconosciuta"</string>
<string name="sms_control_title" msgid="7296612781128917719">"Invio SMS"</string>
- <string name="sms_control_message" msgid="4073755190243093924">"È in corso l\'invio di numerosi SMS. Tocca \"OK\" per continuare oppure \"Annulla\" per interrompere l\'invio."</string>
- <string name="sms_control_yes" msgid="2532062172402615953">"OK"</string>
- <string name="sms_control_no" msgid="1715320703137199869">"Annulla"</string>
+ <string name="sms_control_message" msgid="3867899169651496433">"<b><xliff:g id="APP_NAME">%1$s</xliff:g></b> sta inviando molti SMS. Vuoi consentire all\'applicazione di continuare a inviare messaggi?"</string>
+ <string name="sms_control_yes" msgid="3663725993855816807">"Consenti"</string>
+ <string name="sms_control_no" msgid="625438561395534982">"Nega"</string>
+ <string name="sms_short_code_confirm_title" msgid="1666863092640877318">"Inviare SMS a codice breve?"</string>
+ <string name="sms_premium_short_code_confirm_title" msgid="3811263856304367838">"Inviare SMS premium?"</string>
+ <string name="sms_short_code_confirm_message" msgid="5616409294907295407">"<b><xliff:g id="APP_NAME">%1$s</xliff:g></b> vorrebbe inviare un messaggio di testo a <b><xliff:g id="DEST_ADDRESS">%2$s</xliff:g></b>, che sembra essere un codice breve SMS.<p>L\'invio di messaggi di testo ad alcuni codici brevi potrebbe comportare l\'addebito di servizi premium sul tuo account per cellulari.<p>Vuoi consentire a questa applicazione di inviare il messaggio?"</string>
+ <string name="sms_premium_short_code_confirm_message" msgid="6214083016284738667">"<b><xliff:g id="APP_NAME">%1$s</xliff:g></b> vorrebbe inviare un messaggio di testo a <b><xliff:g id="DEST_ADDRESS">%2$s</xliff:g></b>, che è un codice breve SMS premium.<p><b>L\'invio di un messaggio a questa destinazione comporterà l\'addebito di servizi premium sul tuo account per cellulari.</b><p>Vuoi consentire a questa applicazione di inviare il messaggio?"</string>
+ <string name="sms_short_code_confirm_allow" msgid="8957573662645722940">"Invia messaggio"</string>
+ <string name="sms_short_code_confirm_deny" msgid="6374609298084435887">"Non inviare"</string>
+ <string name="sms_short_code_confirm_report" msgid="2588793956061677070">"Segnala applicazione dannosa"</string>
<string name="sim_removed_title" msgid="6227712319223226185">"Scheda SIM rimossa"</string>
<string name="sim_removed_message" msgid="2333164559970958645">"La rete mobile non sarà disponibile finché non eseguirai il riavvio con una scheda SIM valida inserita."</string>
<string name="sim_done_button" msgid="827949989369963775">"Fine"</string>
diff --git a/core/res/res/values-iw/strings.xml b/core/res/res/values-iw/strings.xml
index 714f203..68f5e7e 100644
--- a/core/res/res/values-iw/strings.xml
+++ b/core/res/res/values-iw/strings.xml
@@ -286,10 +286,8 @@
<string name="permdesc_setOrientation" msgid="3046126619316671476">"מאפשר ליישום לשנות את הסיבוב של המסך בכל עת. הרשאה זו לעולם אינה נחוצה ליישומים רגילים."</string>
<string name="permlab_setPointerSpeed" msgid="9175371613322562934">"שינוי מהירות המצביע"</string>
<string name="permdesc_setPointerSpeed" msgid="6866563234274104233">"מאפשר ליישום לשנות את המהירות של מצביע העכבר או לוח המגע בכל עת. יישומים רגילים לא אמורים לעולם להזדקק להרשאה זו."</string>
- <!-- no translation found for permlab_setKeyboardLayout (4778731703600909340) -->
- <skip />
- <!-- no translation found for permdesc_setKeyboardLayout (8480016771134175879) -->
- <skip />
+ <string name="permlab_setKeyboardLayout" msgid="4778731703600909340">"שנה את פריסת המקלדת"</string>
+ <string name="permdesc_setKeyboardLayout" msgid="8480016771134175879">"מאפשר ליישום לשנות את פריסת המקלדת. הרשאה זו לעולם אינה אמורה להיות נחוצה עבור יישומים רגילים."</string>
<string name="permlab_signalPersistentProcesses" msgid="4539002991947376659">"שליחת אותות Linux ליישומים"</string>
<string name="permdesc_signalPersistentProcesses" msgid="4896992079182649141">"מאפשר ליישום לבקש שהאות שנקלט יישלח לכל התהליכים המתמשכים."</string>
<string name="permlab_persistentActivity" msgid="8841113627955563938">"הגדרת היישום לפעול תמיד"</string>
@@ -1009,11 +1007,17 @@
<string name="wifi_p2p_enter_pin_message" msgid="5920929550367828970">"הקלד את קוד ה-PIN הנדרש."</string>
<string name="wifi_p2p_show_pin_message" msgid="8530563323880921094">"PIN:"</string>
<string name="select_character" msgid="3365550120617701745">"הוסף תו"</string>
- <string name="sms_control_default_app_name" msgid="3058577482636640465">"יישום לא ידוע"</string>
<string name="sms_control_title" msgid="7296612781128917719">"שולח הודעות SMS"</string>
- <string name="sms_control_message" msgid="4073755190243093924">"מתבצעת כעת שליחה של מספר גדול של הודעות SMS. גע באפשרות \'אישור\' כדי להמשיך, או \'ביטול\' כדי לעצור את השליחה."</string>
- <string name="sms_control_yes" msgid="2532062172402615953">"אישור"</string>
- <string name="sms_control_no" msgid="1715320703137199869">"ביטול"</string>
+ <string name="sms_control_message" msgid="3867899169651496433">"<b> <xliff:g id="APP_NAME">%1$s</xliff:g> </ b> שולח מספר רב של הודעות SMS. האם ברצונך לאפשר ליישום זה להמשיך לשלוח הודעות?"</string>
+ <string name="sms_control_yes" msgid="3663725993855816807">"אפשר"</string>
+ <string name="sms_control_no" msgid="625438561395534982">"דחה"</string>
+ <string name="sms_short_code_confirm_title" msgid="1666863092640877318">"לשלוח SMS לקוד קצר?"</string>
+ <string name="sms_premium_short_code_confirm_title" msgid="3811263856304367838">"לשלוח SMS פרימיום?"</string>
+ <string name="sms_short_code_confirm_message" msgid="5616409294907295407">"<b> <xliff:g id="APP_NAME">%1$s</xliff:g> </ b> רוצה לשלוח הודעת טקסט אל <b> <xliff:g id="DEST_ADDRESS">%2$s</xliff:g> </ b>, שנראה כמו קוד SMS קצר. <p> שליחת הודעות טקסט לקודים קצרים מסוימים עשויה לגרום לחיוב חשבון הנייד שלך בשירותי פרימיום. <p> האם ברצונך לאפשר ליישום זה לשלוח את ההודעה?"</string>
+ <string name="sms_premium_short_code_confirm_message" msgid="6214083016284738667">"<b> <xliff:g id="APP_NAME">%1$s</xliff:g> </ b> רוצה לשלוח הודעת טקסט ל-<b> <xliff:g id="DEST_ADDRESS">%2$s</xliff:g> </ b>, שהוא קוד פרימיום קצר של SMS. <b> <p> שליחת הודעה ליעד זה תגרום לחיוב חשבון הנייד שלך בשירותי פרימיום. </ b> <p> האם ברצונך לאפשר ליישום זה לשלוח את ההודעה?"</string>
+ <string name="sms_short_code_confirm_allow" msgid="8957573662645722940">"שלח הודעה"</string>
+ <string name="sms_short_code_confirm_deny" msgid="6374609298084435887">"אל תשלח"</string>
+ <string name="sms_short_code_confirm_report" msgid="2588793956061677070">"דווח על יישום זדוני"</string>
<string name="sim_removed_title" msgid="6227712319223226185">"כרטיס ה-SIM הוסר"</string>
<string name="sim_removed_message" msgid="2333164559970958645">"הרשת הסלולרית לא תהיה זמינה עד שתפעיל מחדש לאחר הכנסת כרטיס SIM חוקי."</string>
<string name="sim_done_button" msgid="827949989369963775">"סיום"</string>
@@ -1063,10 +1067,8 @@
<string name="adb_active_notification_message" msgid="1016654627626476142">"גע כדי להשבית את ניקוי הבאגים בהתקן ה-USB."</string>
<string name="select_input_method" msgid="4653387336791222978">"בחר שיטת הזנה"</string>
<string name="configure_input_methods" msgid="9091652157722495116">"הגדר שיטות קלט"</string>
- <!-- no translation found for use_physical_keyboard (6203112478095117625) -->
- <skip />
- <!-- no translation found for hardware (7517821086888990278) -->
- <skip />
+ <string name="use_physical_keyboard" msgid="6203112478095117625">"מקלדת פיזית"</string>
+ <string name="hardware" msgid="7517821086888990278">"חומרה"</string>
<string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="candidates_style" msgid="4333913089637062257"><u>"מועמדים"</u></string>
diff --git a/core/res/res/values-ja/strings.xml b/core/res/res/values-ja/strings.xml
index a5db38b..aa4864c 100644
--- a/core/res/res/values-ja/strings.xml
+++ b/core/res/res/values-ja/strings.xml
@@ -286,10 +286,8 @@
<string name="permdesc_setOrientation" msgid="3046126619316671476">"いつでも画面の向きを変更することをアプリに許可します。通常のアプリでは不要です。"</string>
<string name="permlab_setPointerSpeed" msgid="9175371613322562934">"ポインタの速度の変更"</string>
<string name="permdesc_setPointerSpeed" msgid="6866563234274104233">"マウスまたはトラックパッドのポインタの速度をいつでも変更することをアプリに許可します。通常のアプリでは不要です。"</string>
- <!-- no translation found for permlab_setKeyboardLayout (4778731703600909340) -->
- <skip />
- <!-- no translation found for permdesc_setKeyboardLayout (8480016771134175879) -->
- <skip />
+ <string name="permlab_setKeyboardLayout" msgid="4778731703600909340">"キーボードレイアウトの変更"</string>
+ <string name="permdesc_setKeyboardLayout" msgid="8480016771134175879">"キーボードレイアウトの変更をアプリに許可します。通常のアプリでは不要です。"</string>
<string name="permlab_signalPersistentProcesses" msgid="4539002991947376659">"アプリへのLinuxシグナルの送信"</string>
<string name="permdesc_signalPersistentProcesses" msgid="4896992079182649141">"受信したシグナルをすべての継続プロセスに送信するようリクエストすることをアプリに許可します。"</string>
<string name="permlab_persistentActivity" msgid="8841113627955563938">"アプリの常時実行"</string>
@@ -1009,11 +1007,17 @@
<string name="wifi_p2p_enter_pin_message" msgid="5920929550367828970">"必要なPINを入力してください:"</string>
<string name="wifi_p2p_show_pin_message" msgid="8530563323880921094">"PIN:"</string>
<string name="select_character" msgid="3365550120617701745">"文字を挿入"</string>
- <string name="sms_control_default_app_name" msgid="3058577482636640465">"不明なアプリ"</string>
<string name="sms_control_title" msgid="7296612781128917719">"SMSメッセージの送信中"</string>
- <string name="sms_control_message" msgid="4073755190243093924">"大量のSMSメッセージを送信しようとしています。[OK]で送信、[キャンセル]で中止します。"</string>
- <string name="sms_control_yes" msgid="2532062172402615953">"OK"</string>
- <string name="sms_control_no" msgid="1715320703137199869">"キャンセル"</string>
+ <string name="sms_control_message" msgid="3867899169651496433">"<b><xliff:g id="APP_NAME">%1$s</xliff:g></b>が大量のSMSメッセージを送信しています。このアプリにこのままメッセージの送信を許可しますか?"</string>
+ <string name="sms_control_yes" msgid="3663725993855816807">"許可する"</string>
+ <string name="sms_control_no" msgid="625438561395534982">"許可しない"</string>
+ <string name="sms_short_code_confirm_title" msgid="1666863092640877318">"ショートコードへのSMSの送信"</string>
+ <string name="sms_premium_short_code_confirm_title" msgid="3811263856304367838">"プレミアムSMSを送信しますか?"</string>
+ <string name="sms_short_code_confirm_message" msgid="5616409294907295407">"<b><xliff:g id="APP_NAME">%1$s</xliff:g></b>が、SMSショートコードと思われる<b><xliff:g id="DEST_ADDRESS">%2$s</xliff:g></b>にテキストメッセージを送信しようとしています。<p>一部のショートコードにテキストメッセージを送信すると、プレミアムサービスの料金がモバイルアカウントが請求される場合があります。<p>このアプリにメッセージの送信を許可しますか?"</string>
+ <string name="sms_premium_short_code_confirm_message" msgid="6214083016284738667">"<b><xliff:g id="APP_NAME">%1$s</xliff:g></b>が、プレミアムSMSショートコード<b><xliff:g id="DEST_ADDRESS">%2$s</xliff:g></b>にテキストメッセージを送信しようとしています。<p><b>この宛先にメッセージを送信すると、プレミアムサービスの料金がモバイルアカウントに請求されます。</b><p>このアプリにメッセージの送信を許可しますか?"</string>
+ <string name="sms_short_code_confirm_allow" msgid="8957573662645722940">"メッセージを送信"</string>
+ <string name="sms_short_code_confirm_deny" msgid="6374609298084435887">"送信しない"</string>
+ <string name="sms_short_code_confirm_report" msgid="2588793956061677070">"悪意のあるアプリを報告"</string>
<string name="sim_removed_title" msgid="6227712319223226185">"SIMカードが取り外されました"</string>
<string name="sim_removed_message" msgid="2333164559970958645">"有効なSIMカードを挿入して再起動するまでは、モバイルネットワークは利用できません。"</string>
<string name="sim_done_button" msgid="827949989369963775">"完了"</string>
@@ -1063,10 +1067,8 @@
<string name="adb_active_notification_message" msgid="1016654627626476142">"タップしてUSBデバッグを無効にします。"</string>
<string name="select_input_method" msgid="4653387336791222978">"入力方法の選択"</string>
<string name="configure_input_methods" msgid="9091652157722495116">"入力方法をセットアップ"</string>
- <!-- no translation found for use_physical_keyboard (6203112478095117625) -->
- <skip />
- <!-- no translation found for hardware (7517821086888990278) -->
- <skip />
+ <string name="use_physical_keyboard" msgid="6203112478095117625">"物理キーボード"</string>
+ <string name="hardware" msgid="7517821086888990278">"ハードウェア"</string>
<string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="candidates_style" msgid="4333913089637062257"><u>"候補"</u></string>
diff --git a/core/res/res/values-ko/strings.xml b/core/res/res/values-ko/strings.xml
index 4f580ba..0ada67d 100644
--- a/core/res/res/values-ko/strings.xml
+++ b/core/res/res/values-ko/strings.xml
@@ -286,10 +286,8 @@
<string name="permdesc_setOrientation" msgid="3046126619316671476">"앱이 언제든지 화면 회전을 변경할 수 있도록 허용합니다. 일반 앱에는 필요하지 않습니다."</string>
<string name="permlab_setPointerSpeed" msgid="9175371613322562934">"포인터 속도 변경"</string>
<string name="permdesc_setPointerSpeed" msgid="6866563234274104233">"앱이 언제든지 마우스 또는 트랙패드 포인터의 속도를 변경할 수 있도록 허용합니다. 일반 앱에는 필요하지 않습니다."</string>
- <!-- no translation found for permlab_setKeyboardLayout (4778731703600909340) -->
- <skip />
- <!-- no translation found for permdesc_setKeyboardLayout (8480016771134175879) -->
- <skip />
+ <string name="permlab_setKeyboardLayout" msgid="4778731703600909340">"키보드 레이아웃 변경"</string>
+ <string name="permdesc_setKeyboardLayout" msgid="8480016771134175879">"앱이 키보드 레이아웃을 변경할 수 있도록 허용합니다. 일반 앱에는 필요하지 않습니다."</string>
<string name="permlab_signalPersistentProcesses" msgid="4539002991947376659">"앱에 Linux 시그널 보내기"</string>
<string name="permdesc_signalPersistentProcesses" msgid="4896992079182649141">"제공된 시그널을 모든 영구 프로세스로 전송하는 것을 앱이 요청할 수 있도록 허용합니다."</string>
<string name="permlab_persistentActivity" msgid="8841113627955563938">"앱이 항상 실행되도록 설정"</string>
@@ -1009,11 +1007,17 @@
<string name="wifi_p2p_enter_pin_message" msgid="5920929550367828970">"필수 PIN 입력:"</string>
<string name="wifi_p2p_show_pin_message" msgid="8530563323880921094">"PIN:"</string>
<string name="select_character" msgid="3365550120617701745">"문자 삽입"</string>
- <string name="sms_control_default_app_name" msgid="3058577482636640465">"알 수 없는 앱"</string>
<string name="sms_control_title" msgid="7296612781128917719">"SMS 메시지를 보내는 중"</string>
- <string name="sms_control_message" msgid="4073755190243093924">"SMS 메시지를 대량 전송 중입니다. 계속하려면 \'확인\'을 터치하고 전송을 중지하려면 \'취소\'를 터치하세요."</string>
- <string name="sms_control_yes" msgid="2532062172402615953">"확인"</string>
- <string name="sms_control_no" msgid="1715320703137199869">"취소"</string>
+ <string name="sms_control_message" msgid="3867899169651496433">"<b><xliff:g id="APP_NAME">%1$s</xliff:g></b>이(가) SMS 메시지를 대량으로 보내고 있습니다. 해당 앱이 메시지를 계속 보내도록 하시겠습니까?"</string>
+ <string name="sms_control_yes" msgid="3663725993855816807">"허용"</string>
+ <string name="sms_control_no" msgid="625438561395534982">"거부"</string>
+ <string name="sms_short_code_confirm_title" msgid="1666863092640877318">"SMS를 단축 코드로 보내시겠습니까?"</string>
+ <string name="sms_premium_short_code_confirm_title" msgid="3811263856304367838">"프리미엄 SMS를 보내도록 하시겠습니까?"</string>
+ <string name="sms_short_code_confirm_message" msgid="5616409294907295407">"<b><xliff:g id="APP_NAME">%1$s</xliff:g></b>이(가) SMS 단축 코드로 추정되는 문자 메시지를 <b><xliff:g id="DEST_ADDRESS">%2$s</xliff:g></b>(으)로 보내려 합니다.<p>문자 메시지를 단축 코드로 보내면 사용자의 모바일 계정에 프리미엄 서비스 요금이 청구될 수 있습니다.<p>해당 앱이 메시지를 보내도록 하시겠습니까?"</string>
+ <string name="sms_premium_short_code_confirm_message" msgid="6214083016284738667">"<b><xliff:g id="APP_NAME">%1$s</xliff:g></b>이(가) 문자 메시지를 프리미엄 SMS 단축 코드인 <b><xliff:g id="DEST_ADDRESS">%2$s</xliff:g></b>(으)로 보내려 합니다.<p><b>이 목적지로 메시지를 보내면 사용자의 모바일 계정에 프리미엄 서비스 요금이 청구됩니다.</b><p>해당 앱이 메시지를 보내도록 하시겠습니까?"</string>
+ <string name="sms_short_code_confirm_allow" msgid="8957573662645722940">"메시지 보내기"</string>
+ <string name="sms_short_code_confirm_deny" msgid="6374609298084435887">"보내지 않음"</string>
+ <string name="sms_short_code_confirm_report" msgid="2588793956061677070">"악성 앱 신고"</string>
<string name="sim_removed_title" msgid="6227712319223226185">"SIM 카드 제거됨"</string>
<string name="sim_removed_message" msgid="2333164559970958645">"유효한 SIM 카드를 삽입하여 다시 시작할 때까지 모바일 네트워크를 사용할 수 없습니다."</string>
<string name="sim_done_button" msgid="827949989369963775">"완료"</string>
@@ -1063,10 +1067,8 @@
<string name="adb_active_notification_message" msgid="1016654627626476142">"USB 디버깅을 사용하지 않으려면 터치하세요."</string>
<string name="select_input_method" msgid="4653387336791222978">"입력 방법 선택"</string>
<string name="configure_input_methods" msgid="9091652157722495116">"입력 방법 설정"</string>
- <!-- no translation found for use_physical_keyboard (6203112478095117625) -->
- <skip />
- <!-- no translation found for hardware (7517821086888990278) -->
- <skip />
+ <string name="use_physical_keyboard" msgid="6203112478095117625">"물리적 키보드"</string>
+ <string name="hardware" msgid="7517821086888990278">"하드웨어"</string>
<string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="candidates_style" msgid="4333913089637062257"><u>"가능한 원인"</u></string>
diff --git a/core/res/res/values-lt/strings.xml b/core/res/res/values-lt/strings.xml
index c588fa6..b37cfda 100644
--- a/core/res/res/values-lt/strings.xml
+++ b/core/res/res/values-lt/strings.xml
@@ -286,10 +286,8 @@
<string name="permdesc_setOrientation" msgid="3046126619316671476">"Leidžiama programai bet kada kaitalioti ekraną. Įprastoms programoms to neturėtų prireikti."</string>
<string name="permlab_setPointerSpeed" msgid="9175371613322562934">"keisti žymiklio greitį"</string>
<string name="permdesc_setPointerSpeed" msgid="6866563234274104233">"Leidžiama programai keisti pelės ar sensorinio pulto žymiklio greitį. Įprastoms programoms to neturėtų prireikti."</string>
- <!-- no translation found for permlab_setKeyboardLayout (4778731703600909340) -->
- <skip />
- <!-- no translation found for permdesc_setKeyboardLayout (8480016771134175879) -->
- <skip />
+ <string name="permlab_setKeyboardLayout" msgid="4778731703600909340">"keisti klaviatūros išdėstymą"</string>
+ <string name="permdesc_setKeyboardLayout" msgid="8480016771134175879">"Leidžiama programai pakeisti klaviatūros išdėstymą. Įprastoms programoms to neturėtų prireikti."</string>
<string name="permlab_signalPersistentProcesses" msgid="4539002991947376659">"siųsti „Linux“ signalus programoms"</string>
<string name="permdesc_signalPersistentProcesses" msgid="4896992079182649141">"Leidžiama programai pateikti užklausą, kad teikiamas signalas būtų siunčiamas visiems nuolatiniams procesams."</string>
<string name="permlab_persistentActivity" msgid="8841113627955563938">"nustatyti, kad programa būtų visada vykdoma"</string>
@@ -1009,11 +1007,17 @@
<string name="wifi_p2p_enter_pin_message" msgid="5920929550367828970">"Įveskite reikiamą PIN kodą:"</string>
<string name="wifi_p2p_show_pin_message" msgid="8530563323880921094">"PIN kodas:"</string>
<string name="select_character" msgid="3365550120617701745">"Įterpti simbolį"</string>
- <string name="sms_control_default_app_name" msgid="3058577482636640465">"Nežinoma programa"</string>
<string name="sms_control_title" msgid="7296612781128917719">"SMS pranešimų siuntimas"</string>
- <string name="sms_control_message" msgid="4073755190243093924">"Siunčiama daug SMS pranešimų. Palieskite „Gerai“, jei norite tęsti, arba „Atšaukti“, jei norite sustabdyti siuntimą."</string>
- <string name="sms_control_yes" msgid="2532062172402615953">"Gerai"</string>
- <string name="sms_control_no" msgid="1715320703137199869">"Atšaukti"</string>
+ <string name="sms_control_message" msgid="3867899169651496433">"Naudojant <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> siunčiama daug SMS pranešimų. Ar norite leisti šiai programai toliau siųsti pranešimus?"</string>
+ <string name="sms_control_yes" msgid="3663725993855816807">"Leisti"</string>
+ <string name="sms_control_no" msgid="625438561395534982">"Uždrausti"</string>
+ <string name="sms_short_code_confirm_title" msgid="1666863092640877318">"Siųsti SMS trumpuoju numeriu?"</string>
+ <string name="sms_premium_short_code_confirm_title" msgid="3811263856304367838">"Siųsti brangesnį SMS?"</string>
+ <string name="sms_short_code_confirm_message" msgid="5616409294907295407">"Naudojant <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> prašoma išsiųsti teksto pranešimą <b><xliff:g id="DEST_ADDRESS">%2$s</xliff:g></b>, o tai yra trumpasis SMS numeris.<p><b>Siųsdami pranešimus kai kuriais trumpaisiais numeriais galite būti apmokestinti mobiliojo ryšio sąskaitoje už brangesnes paslaugas.</b><p>Ar norite leisti šiai programai siųsti pranešimą?"</string>
+ <string name="sms_premium_short_code_confirm_message" msgid="6214083016284738667">"Naudojant <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> prašoma išsiųsti teksto pranešimą <b><xliff:g id="DEST_ADDRESS">%2$s</xliff:g></b>, o tai yra brangesnis trumpasis SMS numeris.<p><b>Siųsdami pranešimą šiam gavėjui mobiliojo ryšio sąskaitoje būsite apmokestinti už brangesnes paslaugas.</b><p>Ar norite leisti šiai programai siųsti pranešimą?"</string>
+ <string name="sms_short_code_confirm_allow" msgid="8957573662645722940">"Siųsti pranešimą"</string>
+ <string name="sms_short_code_confirm_deny" msgid="6374609298084435887">"Nesiųsti"</string>
+ <string name="sms_short_code_confirm_report" msgid="2588793956061677070">"Pranešti apie kenkėj. programą"</string>
<string name="sim_removed_title" msgid="6227712319223226185">"SIM kortelė pašalinta"</string>
<string name="sim_removed_message" msgid="2333164559970958645">"Mobilusis tinklas bus nepasiekiamas, kol nepaleisite iš naujo įdėję tinkamą SIM kortelę."</string>
<string name="sim_done_button" msgid="827949989369963775">"Atlikta"</string>
@@ -1063,10 +1067,8 @@
<string name="adb_active_notification_message" msgid="1016654627626476142">"Palieskite, kad neleistumėte USB derinimo."</string>
<string name="select_input_method" msgid="4653387336791222978">"Pasirinkite įvesties metodą"</string>
<string name="configure_input_methods" msgid="9091652157722495116">"Nustatyti įvesties metodus"</string>
- <!-- no translation found for use_physical_keyboard (6203112478095117625) -->
- <skip />
- <!-- no translation found for hardware (7517821086888990278) -->
- <skip />
+ <string name="use_physical_keyboard" msgid="6203112478095117625">"Fizinė klaviatūra"</string>
+ <string name="hardware" msgid="7517821086888990278">"Apar. įr."</string>
<string name="fast_scroll_alphabet" msgid="5433275485499039199">" AĄBCČDEĘĖFGHIĮYJKLMNOPRSŠTUŲŪVZŽ"</string>
<string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789AĄBCČDEĘĖFGHIĮYJKLMNOPRSŠTUŲŪVZŽ"</string>
<string name="candidates_style" msgid="4333913089637062257"><u>"kandidatai"</u></string>
diff --git a/core/res/res/values-lv/strings.xml b/core/res/res/values-lv/strings.xml
index d710347..2c59d24 100644
--- a/core/res/res/values-lv/strings.xml
+++ b/core/res/res/values-lv/strings.xml
@@ -286,10 +286,8 @@
<string name="permdesc_setOrientation" msgid="3046126619316671476">"Ļauj lietotnei jebkurā laikā mainīt ekrāna pozīciju. Parastajām lietotnēm tas nekad nav nepieciešams."</string>
<string name="permlab_setPointerSpeed" msgid="9175371613322562934">"Rādītāja ātruma mainīšana"</string>
<string name="permdesc_setPointerSpeed" msgid="6866563234274104233">"Ļauj lietotnei jebkurā laikā mainīt peles vai skārienpaliktņa rādītāja ātrumu. Parastajām lietotnēm tas nekad nav nepieciešams."</string>
- <!-- no translation found for permlab_setKeyboardLayout (4778731703600909340) -->
- <skip />
- <!-- no translation found for permdesc_setKeyboardLayout (8480016771134175879) -->
- <skip />
+ <string name="permlab_setKeyboardLayout" msgid="4778731703600909340">"Tastatūras izkārtojuma maiņa"</string>
+ <string name="permdesc_setKeyboardLayout" msgid="8480016771134175879">"Ļauj lietotnei mainīt tastatūras izkārtojumu. Parastajām lietotnēm tas nekad nav nepieciešams."</string>
<string name="permlab_signalPersistentProcesses" msgid="4539002991947376659">"sūtīt Linux signālus lietotnēm"</string>
<string name="permdesc_signalPersistentProcesses" msgid="4896992079182649141">"Ļauj lietotnei pieprasīt, lai piegādātais signāls tiktu sūtīts visiem pastāvīgajiem procesiem."</string>
<string name="permlab_persistentActivity" msgid="8841113627955563938">"likt lietotnei vienmēr darboties"</string>
@@ -1009,11 +1007,17 @@
<string name="wifi_p2p_enter_pin_message" msgid="5920929550367828970">"Ierakstiet pieprasīto PIN:"</string>
<string name="wifi_p2p_show_pin_message" msgid="8530563323880921094">"PIN:"</string>
<string name="select_character" msgid="3365550120617701745">"Ievietojiet rakstzīmi"</string>
- <string name="sms_control_default_app_name" msgid="3058577482636640465">"Nezināma lietotne"</string>
<string name="sms_control_title" msgid="7296612781128917719">"Īsziņu sūtīšana"</string>
- <string name="sms_control_message" msgid="4073755190243093924">"Tiek sūtīts daudz īsziņu. Pieskarieties Labi, lai turpinātu, vai Atcelt, lai apturētu sūtīšanu."</string>
- <string name="sms_control_yes" msgid="2532062172402615953">"Labi"</string>
- <string name="sms_control_no" msgid="1715320703137199869">"Atcelt"</string>
+ <string name="sms_control_message" msgid="3867899169651496433">"Lietotne <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> sūta daudz īsziņu. Vai vēlaties, lai šī lietotne turpinātu sūtīt ziņojumus?"</string>
+ <string name="sms_control_yes" msgid="3663725993855816807">"Atļaut"</string>
+ <string name="sms_control_no" msgid="625438561395534982">"Aizliegt"</string>
+ <string name="sms_short_code_confirm_title" msgid="1666863092640877318">"Vai sūtīt īsziņu uz īso kodu?"</string>
+ <string name="sms_premium_short_code_confirm_title" msgid="3811263856304367838">"Vai nosūtīt īpašo īsziņu?"</string>
+ <string name="sms_short_code_confirm_message" msgid="5616409294907295407">"Lietotne <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> vēlas nosūtīt īsziņu uz adresi <b><xliff:g id="DEST_ADDRESS">%2$s</xliff:g></b>, kas, iespējams, ir īsziņas īsais kods.<p><b>Sūtot īsziņas uz dažiem īsajiem kodiem, no jūsu mobilā konta var tikt iekasēta maksa par paaugstinātas maksas pakalpojumiem.</b><p>Vai vēlaties atļaut šai lietotnei sūtīt šo ziņojumu?"</string>
+ <string name="sms_premium_short_code_confirm_message" msgid="6214083016284738667">"Lietotne <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> vēlas nosūtīt īsziņu uz adresi <b><xliff:g id="DEST_ADDRESS">%2$s</xliff:g></b>, kas, iespējams, ir paaugstinātas maksas īsziņas īsais kods.<p><b>Sūtot ziņojumu uz šo galamērķi, no jūsu mobilā konta tiks iekasēta maksa par paaugstinātas maksas pakalpojumiem.</b><p>Vai vēlaties atļaut šai lietotnei sūtīt šo ziņojumu?"</string>
+ <string name="sms_short_code_confirm_allow" msgid="8957573662645722940">"Sūtīt ziņojumu"</string>
+ <string name="sms_short_code_confirm_deny" msgid="6374609298084435887">"Nesūtīt"</string>
+ <string name="sms_short_code_confirm_report" msgid="2588793956061677070">"Ziņot par ļaunprātīgu lietotni"</string>
<string name="sim_removed_title" msgid="6227712319223226185">"SIM karte ir izņemta."</string>
<string name="sim_removed_message" msgid="2333164559970958645">"Mobilais tīkls nebūs pieejams līdz brīdim, kad restartēsiet ierīci ar ievietotu derīgu SIM karti."</string>
<string name="sim_done_button" msgid="827949989369963775">"Gatavs"</string>
@@ -1063,10 +1067,8 @@
<string name="adb_active_notification_message" msgid="1016654627626476142">"Pieskarieties, lai atspējotu USB atkļūdošanu."</string>
<string name="select_input_method" msgid="4653387336791222978">"Ievades metodes izvēle"</string>
<string name="configure_input_methods" msgid="9091652157722495116">"Iestatīt ievades metodes"</string>
- <!-- no translation found for use_physical_keyboard (6203112478095117625) -->
- <skip />
- <!-- no translation found for hardware (7517821086888990278) -->
- <skip />
+ <string name="use_physical_keyboard" msgid="6203112478095117625">"Fiziskā tastatūra"</string>
+ <string name="hardware" msgid="7517821086888990278">"Aparatūra"</string>
<string name="fast_scroll_alphabet" msgid="5433275485499039199">" AĀBCČDEĒFGĢHIĪJKĶLĻMNŅOPRSŠTUŪVZŽ"</string>
<string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789AĀBCČDEĒFGĢHIĪJKĶLĻMNŅOPRSŠTUŪVZŽ"</string>
<string name="candidates_style" msgid="4333913089637062257"><u>"kandidāti"</u></string>
diff --git a/core/res/res/values-ms/strings.xml b/core/res/res/values-ms/strings.xml
index 38fc473..a97b9c1 100644
--- a/core/res/res/values-ms/strings.xml
+++ b/core/res/res/values-ms/strings.xml
@@ -286,10 +286,8 @@
<string name="permdesc_setOrientation" msgid="3046126619316671476">"Membenarkan apl untuk menukar putaran skrin pada bila-bila masa. Tidak sekali-kali diperlukan untuk apl biasa."</string>
<string name="permlab_setPointerSpeed" msgid="9175371613322562934">"tukar kelajuan penuding"</string>
<string name="permdesc_setPointerSpeed" msgid="6866563234274104233">"Membenarkan apl untuk menukar kelajuan penunjuk tetikus atau pad jejak pada bila-bila masa. Tidak sekali-kali diperlukan untuk apl biasa."</string>
- <!-- no translation found for permlab_setKeyboardLayout (4778731703600909340) -->
- <skip />
- <!-- no translation found for permdesc_setKeyboardLayout (8480016771134175879) -->
- <skip />
+ <string name="permlab_setKeyboardLayout" msgid="4778731703600909340">"tukar susun atur papan kekunci"</string>
+ <string name="permdesc_setKeyboardLayout" msgid="8480016771134175879">"Membenarkan apl menukar susun atur papan kekunci. Tidak sekali-kali diperlukan untuk apl biasa."</string>
<string name="permlab_signalPersistentProcesses" msgid="4539002991947376659">"hantar isyarat Linux kepada apl"</string>
<string name="permdesc_signalPersistentProcesses" msgid="4896992079182649141">"Membenarkan apl meminta isyarat yang dibekalkan dihantar kepada semua proses yang berterusan."</string>
<string name="permlab_persistentActivity" msgid="8841113627955563938">"buatkan apl sentiasa berjalan"</string>
@@ -1009,11 +1007,17 @@
<string name="wifi_p2p_enter_pin_message" msgid="5920929550367828970">"Taipkan PIN yang diperlukan:"</string>
<string name="wifi_p2p_show_pin_message" msgid="8530563323880921094">"PIN:"</string>
<string name="select_character" msgid="3365550120617701745">"Masukkan aksara"</string>
- <string name="sms_control_default_app_name" msgid="3058577482636640465">"Apl tidak diketahui"</string>
<string name="sms_control_title" msgid="7296612781128917719">"Menghantar mesej SMS"</string>
- <string name="sms_control_message" msgid="4073755190243093924">"Sejumlah besar mesej SMS sedang dihantar. Sentuh \"OK\" untuk meneruskan atau \"Batal\" untuk menghentikan penghantaran."</string>
- <string name="sms_control_yes" msgid="2532062172402615953">"OK"</string>
- <string name="sms_control_no" msgid="1715320703137199869">"Batal"</string>
+ <string name="sms_control_message" msgid="3867899169651496433">"<b><xliff:g id="APP_NAME">%1$s</xliff:g></b> sedang menghantar banyak mesej SMS. Adakah anda mahu membenarkan apl ini terus menghantar mesej?"</string>
+ <string name="sms_control_yes" msgid="3663725993855816807">"Benarkan"</string>
+ <string name="sms_control_no" msgid="625438561395534982">"Nafikan"</string>
+ <string name="sms_short_code_confirm_title" msgid="1666863092640877318">"Hantar SMS ke kod pendek?"</string>
+ <string name="sms_premium_short_code_confirm_title" msgid="3811263856304367838">"Hantar SMS premium?"</string>
+ <string name="sms_short_code_confirm_message" msgid="5616409294907295407">"<b><xliff:g id="APP_NAME">%1$s</xliff:g></b> ingin menghantar mesej teks kepada <b><xliff:g id="DEST_ADDRESS">%2$s</xliff:g></b>, yang merupakan kod pendek SMS.<p>Menghantar mesej teks ke sesetengah kod pendek boleh menyebabkan akaun mudah alih anda dikenakan bayaran perkhidmatan premium.<p>Adakah anda mahu membenarkan apl ini menghantar mesej itu?"</string>
+ <string name="sms_premium_short_code_confirm_message" msgid="6214083016284738667">"<b><xliff:g id="APP_NAME">%1$s</xliff:g></b> ingin menghantar mesej teks ke <b><xliff:g id="DEST_ADDRESS">%2$s</xliff:g></b>, yang merupakan kod pendek SMS premium.<p><b>Menghantar mesej ke destinasi ini akan menyebabkan akaun mudah alih anda dikenakan bayaran untuk perkhidmatan premium.</b><p>Adakah anda mahu membenarkan apl ini menghantar mesej itu?"</string>
+ <string name="sms_short_code_confirm_allow" msgid="8957573662645722940">"Hantar mesej"</string>
+ <string name="sms_short_code_confirm_deny" msgid="6374609298084435887">"Jangan hantar"</string>
+ <string name="sms_short_code_confirm_report" msgid="2588793956061677070">"Laporkan aplikasi hasad"</string>
<string name="sim_removed_title" msgid="6227712319223226185">"Kad SIM dikeluarkan"</string>
<string name="sim_removed_message" msgid="2333164559970958645">"Rangkaian mudah alih tidak akan tersedia sehingga anda mula semula dengan kad SIM yang sah dimasukkan."</string>
<string name="sim_done_button" msgid="827949989369963775">"Selesai"</string>
@@ -1063,10 +1067,8 @@
<string name="adb_active_notification_message" msgid="1016654627626476142">"Sentuh untuk melumpuhkan penyahpepijatan USB."</string>
<string name="select_input_method" msgid="4653387336791222978">"Pilih kaedah input"</string>
<string name="configure_input_methods" msgid="9091652157722495116">"Sediakan kaedah input"</string>
- <!-- no translation found for use_physical_keyboard (6203112478095117625) -->
- <skip />
- <!-- no translation found for hardware (7517821086888990278) -->
- <skip />
+ <string name="use_physical_keyboard" msgid="6203112478095117625">"Papan kekunci fizikal"</string>
+ <string name="hardware" msgid="7517821086888990278">"Perkakasan"</string>
<string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="candidates_style" msgid="4333913089637062257"><u>"calon"</u></string>
diff --git a/core/res/res/values-nb/strings.xml b/core/res/res/values-nb/strings.xml
index df05f01..409ee6d 100644
--- a/core/res/res/values-nb/strings.xml
+++ b/core/res/res/values-nb/strings.xml
@@ -286,10 +286,8 @@
<string name="permdesc_setOrientation" msgid="3046126619316671476">"Gir appen tillatelse til når som helst å endre rotasjonen av skjermen. Skal aldri være nødvendig for vanlige apper."</string>
<string name="permlab_setPointerSpeed" msgid="9175371613322562934">"endre pekerhastighet"</string>
<string name="permdesc_setPointerSpeed" msgid="6866563234274104233">"Lar appen når som helst endre markørhastigheten til musen eller styreflaten. Skal aldri være nødvendig for vanlige apper."</string>
- <!-- no translation found for permlab_setKeyboardLayout (4778731703600909340) -->
- <skip />
- <!-- no translation found for permdesc_setKeyboardLayout (8480016771134175879) -->
- <skip />
+ <string name="permlab_setKeyboardLayout" msgid="4778731703600909340">"endre tastaturutformingen"</string>
+ <string name="permdesc_setKeyboardLayout" msgid="8480016771134175879">"Lar appen endre tastaturutformingen. Skal ikke være nødvendig for vanlige apper."</string>
<string name="permlab_signalPersistentProcesses" msgid="4539002991947376659">"sende Linux-signaler til apper"</string>
<string name="permdesc_signalPersistentProcesses" msgid="4896992079182649141">"Lar appen be om at det leverte signalet sendes til alle vedvarende prosesser."</string>
<string name="permlab_persistentActivity" msgid="8841113627955563938">"angi at appen alltid skal kjøre"</string>
@@ -1009,11 +1007,17 @@
<string name="wifi_p2p_enter_pin_message" msgid="5920929550367828970">"Skriv inn påkrevd PIN-kode:"</string>
<string name="wifi_p2p_show_pin_message" msgid="8530563323880921094">"PIN:"</string>
<string name="select_character" msgid="3365550120617701745">"Sett inn tegn"</string>
- <string name="sms_control_default_app_name" msgid="3058577482636640465">"Ukjent app"</string>
<string name="sms_control_title" msgid="7296612781128917719">"Sender SMS-meldinger"</string>
- <string name="sms_control_message" msgid="4073755190243093924">"Et stort antall SMS-meldinger sendes. Trykk på OK for å fortsette, eller trykk på Avbryt for å avbryte sendingen."</string>
- <string name="sms_control_yes" msgid="2532062172402615953">"OK"</string>
- <string name="sms_control_no" msgid="1715320703137199869">"Avbryt"</string>
+ <string name="sms_control_message" msgid="3867899169651496433">"<b><xliff:g id="APP_NAME">%1$s</xliff:g></b> sender et stort antall SMS. Vil du la appen fortsette å sende ut meldinger?"</string>
+ <string name="sms_control_yes" msgid="3663725993855816807">"Tillat"</string>
+ <string name="sms_control_no" msgid="625438561395534982">"Sperr"</string>
+ <string name="sms_short_code_confirm_title" msgid="1666863092640877318">"Vil du sende SMS til kortkoden?"</string>
+ <string name="sms_premium_short_code_confirm_title" msgid="3811263856304367838">"Vil du sende premium-SMS?"</string>
+ <string name="sms_short_code_confirm_message" msgid="5616409294907295407">"<b><xliff:g id="APP_NAME">%1$s</xliff:g></b> vil sende en tekstmelding til <b><xliff:g id="DEST_ADDRESS">%2$s</xliff:g></b>, som ser ut ti å være en SMS-kortkode.<p>Hvis du sender en melding til denne destinasjonen, kan mobilkontoen din komme til å belastes for premium-tjenester.<p>Vil du la denne meldingen sendes av appen?"</string>
+ <string name="sms_premium_short_code_confirm_message" msgid="6214083016284738667">"<b><xliff:g id="APP_NAME">%1$s</xliff:g></b> vil sende en tekstmelding til <b><xliff:g id="DEST_ADDRESS">%2$s</xliff:g></b>, som er en premium SMS-kortkode.<p><b>Hvis du sender en melding til denne destinasjonen, belastes mobilkontoen din for premium-tjenester.</b><p>Vil du la denne meldingen sendes av appen?"</string>
+ <string name="sms_short_code_confirm_allow" msgid="8957573662645722940">"Send melding"</string>
+ <string name="sms_short_code_confirm_deny" msgid="6374609298084435887">"Ikke send"</string>
+ <string name="sms_short_code_confirm_report" msgid="2588793956061677070">"Rapportér skadelig app"</string>
<string name="sim_removed_title" msgid="6227712319223226185">"SIM-kort er fjernet"</string>
<string name="sim_removed_message" msgid="2333164559970958645">"Det mobile nettverket forblir utilgjengelig inntil du starter på nytt med et gyldig SIM-kort."</string>
<string name="sim_done_button" msgid="827949989369963775">"Fullført"</string>
@@ -1063,10 +1067,8 @@
<string name="adb_active_notification_message" msgid="1016654627626476142">"Trykk for å deaktivere USB-feilsøking."</string>
<string name="select_input_method" msgid="4653387336791222978">"Velg inndatametode"</string>
<string name="configure_input_methods" msgid="9091652157722495116">"Konfigurer inndatametoder"</string>
- <!-- no translation found for use_physical_keyboard (6203112478095117625) -->
- <skip />
- <!-- no translation found for hardware (7517821086888990278) -->
- <skip />
+ <string name="use_physical_keyboard" msgid="6203112478095117625">"Fysisk tastatur"</string>
+ <string name="hardware" msgid="7517821086888990278">"Maskinvare"</string>
<string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZÆØÅ"</string>
<string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZÆØÅ"</string>
<string name="candidates_style" msgid="4333913089637062257">"TAG_FONT"<u>"kandidater"</u>"CLOSE_FONT"</string>
diff --git a/core/res/res/values-nl/strings.xml b/core/res/res/values-nl/strings.xml
index 3d48936..acb6bef 100644
--- a/core/res/res/values-nl/strings.xml
+++ b/core/res/res/values-nl/strings.xml
@@ -286,10 +286,8 @@
<string name="permdesc_setOrientation" msgid="3046126619316671476">"Hiermee kan de app de rotatie van het scherm op elk moment wijzigen. Nooit vereist voor normale apps."</string>
<string name="permlab_setPointerSpeed" msgid="9175371613322562934">"aanwijzersnelheid wijzigen"</string>
<string name="permdesc_setPointerSpeed" msgid="6866563234274104233">"Hiermee kan de app de snelheid van de muis- of trackpadaanwijzer op elk moment wijzigen. Nooit vereist voor normale apps."</string>
- <!-- no translation found for permlab_setKeyboardLayout (4778731703600909340) -->
- <skip />
- <!-- no translation found for permdesc_setKeyboardLayout (8480016771134175879) -->
- <skip />
+ <string name="permlab_setKeyboardLayout" msgid="4778731703600909340">"toetsenbordindeling wijzigen"</string>
+ <string name="permdesc_setKeyboardLayout" msgid="8480016771134175879">"Hiermee kan de app de toetsenbordindeling wijzigen. Nooit vereist voor normale apps."</string>
<string name="permlab_signalPersistentProcesses" msgid="4539002991947376659">"Linux-signalen verzenden naar apps"</string>
<string name="permdesc_signalPersistentProcesses" msgid="4896992079182649141">"Hiermee kan de app ervoor zorgen dat het geleverde signaal wordt verzonden naar alle persistente processen."</string>
<string name="permlab_persistentActivity" msgid="8841113627955563938">"app altijd laten uitvoeren"</string>
@@ -1009,11 +1007,17 @@
<string name="wifi_p2p_enter_pin_message" msgid="5920929550367828970">"Voer de gewenste pincode in:"</string>
<string name="wifi_p2p_show_pin_message" msgid="8530563323880921094">"Pincode"</string>
<string name="select_character" msgid="3365550120617701745">"Teken invoegen"</string>
- <string name="sms_control_default_app_name" msgid="3058577482636640465">"Onbekende app"</string>
<string name="sms_control_title" msgid="7296612781128917719">"SMS-berichten verzenden"</string>
- <string name="sms_control_message" msgid="4073755190243093924">"Er wordt een groot aantal sms\'jes verzonden. Raak \'OK\' aan om door te gaan of \'Annuleren\' om de verzending te stoppen."</string>
- <string name="sms_control_yes" msgid="2532062172402615953">"OK"</string>
- <string name="sms_control_no" msgid="1715320703137199869">"Annuleren"</string>
+ <string name="sms_control_message" msgid="3867899169651496433">"<b><xliff:g id="APP_NAME">%1$s</xliff:g></b> verzendt moment een groot aantal sms-berichten. Wilt u toestaan dat deze app berichten blijft verzenden?"</string>
+ <string name="sms_control_yes" msgid="3663725993855816807">"Toestaan"</string>
+ <string name="sms_control_no" msgid="625438561395534982">"Weigeren"</string>
+ <string name="sms_short_code_confirm_title" msgid="1666863092640877318">"Sms verzenden naar shortcode?"</string>
+ <string name="sms_premium_short_code_confirm_title" msgid="3811263856304367838">"Premium-sms verzenden?"</string>
+ <string name="sms_short_code_confirm_message" msgid="5616409294907295407">"<b><xliff:g id="APP_NAME">%1$s</xliff:g></b> wil een sms-bericht verzenden naar <b><xliff:g id="DEST_ADDRESS">%2$s</xliff:g></b>. Dit is waarschijnlijk een sms-shortcode.<p>Als u sms-berichten naar bepaalde shortcodes verzendt, worden mogelijk kosten voor premiumservices in rekening gebracht op uw mobiele account.<p>Wilt u toestaan dat deze app het bericht verzendt?"</string>
+ <string name="sms_premium_short_code_confirm_message" msgid="6214083016284738667">"<b><xliff:g id="APP_NAME">%1$s</xliff:g></b> wil een sms-bericht verzenden naar <b><xliff:g id="DEST_ADDRESS">%2$s</xliff:g></b>. Dit is premium sms-shortcode.<p><b>Als u een bericht naar deze bestemming verzendt, kosten voor premiumservices in rekening gebracht op uw mobiele account.</b><p>Wilt u toestaan dat deze app het bericht verzendt?"</string>
+ <string name="sms_short_code_confirm_allow" msgid="8957573662645722940">"Bericht verzenden"</string>
+ <string name="sms_short_code_confirm_deny" msgid="6374609298084435887">"Niet verzenden"</string>
+ <string name="sms_short_code_confirm_report" msgid="2588793956061677070">"Kwaadaardige app melden"</string>
<string name="sim_removed_title" msgid="6227712319223226185">"Simkaart verwijderd"</string>
<string name="sim_removed_message" msgid="2333164559970958645">"Het mobiele netwerk is niet beschikbaar totdat u het apparaat opnieuw start met een geldige simkaart."</string>
<string name="sim_done_button" msgid="827949989369963775">"Gereed"</string>
@@ -1063,10 +1067,8 @@
<string name="adb_active_notification_message" msgid="1016654627626476142">"Raak deze optie aan om USB-foutopsporing uit te schakelen."</string>
<string name="select_input_method" msgid="4653387336791222978">"Invoermethode selecteren"</string>
<string name="configure_input_methods" msgid="9091652157722495116">"Invoermethoden instellen"</string>
- <!-- no translation found for use_physical_keyboard (6203112478095117625) -->
- <skip />
- <!-- no translation found for hardware (7517821086888990278) -->
- <skip />
+ <string name="use_physical_keyboard" msgid="6203112478095117625">"Fysiek toetsenbord"</string>
+ <string name="hardware" msgid="7517821086888990278">"Hardware"</string>
<string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="candidates_style" msgid="4333913089637062257"><u>"kandidaten"</u></string>
diff --git a/core/res/res/values-pl/strings.xml b/core/res/res/values-pl/strings.xml
index d566c14..39a6583 100644
--- a/core/res/res/values-pl/strings.xml
+++ b/core/res/res/values-pl/strings.xml
@@ -286,10 +286,8 @@
<string name="permdesc_setOrientation" msgid="3046126619316671476">"Pozwala aplikacji na zmianę obrotu ekranu w dowolnym momencie. To uprawnienie nie powinno być potrzebne zwykłym aplikacjom."</string>
<string name="permlab_setPointerSpeed" msgid="9175371613322562934">"zmiana szybkości wskaźnika"</string>
<string name="permdesc_setPointerSpeed" msgid="6866563234274104233">"Pozwala aplikacji zmienić szybkość wskaźnika myszy lub touchpada w dowolnym momencie. Nieprzeznaczone dla zwykłych aplikacji."</string>
- <!-- no translation found for permlab_setKeyboardLayout (4778731703600909340) -->
- <skip />
- <!-- no translation found for permdesc_setKeyboardLayout (8480016771134175879) -->
- <skip />
+ <string name="permlab_setKeyboardLayout" msgid="4778731703600909340">"zmiana układu klawiatury"</string>
+ <string name="permdesc_setKeyboardLayout" msgid="8480016771134175879">"Zezwala aplikacji na zmianę układu klawiatury. Nieprzeznaczone dla zwykłych aplikacji."</string>
<string name="permlab_signalPersistentProcesses" msgid="4539002991947376659">"wysyłanie sygnałów systemu Linux do aplikacji"</string>
<string name="permdesc_signalPersistentProcesses" msgid="4896992079182649141">"Pozwala aplikacji na żądanie, aby dostarczony sygnał został wysłany do wszystkich trwałych procesów."</string>
<string name="permlab_persistentActivity" msgid="8841113627955563938">"sprawianie, że aplikacja jest cały czas uruchomiona"</string>
@@ -1009,11 +1007,17 @@
<string name="wifi_p2p_enter_pin_message" msgid="5920929550367828970">"Wpisz wymagany kod PIN:"</string>
<string name="wifi_p2p_show_pin_message" msgid="8530563323880921094">"Kod PIN:"</string>
<string name="select_character" msgid="3365550120617701745">"Wstaw znak"</string>
- <string name="sms_control_default_app_name" msgid="3058577482636640465">"Nieznana aplikacja"</string>
<string name="sms_control_title" msgid="7296612781128917719">"Wysyłanie wiadomości SMS"</string>
- <string name="sms_control_message" msgid="4073755190243093924">"Wysyłana jest duża liczba wiadomości SMS. Dotknij OK, aby kontynuować, lub Anuluj, aby zatrzymać wysyłanie."</string>
- <string name="sms_control_yes" msgid="2532062172402615953">"OK"</string>
- <string name="sms_control_no" msgid="1715320703137199869">"Anuluj"</string>
+ <string name="sms_control_message" msgid="3867899169651496433">"<b><xliff:g id="APP_NAME">%1$s</xliff:g></b> wysyła wiele SMS-ów. Chcesz pozwolić tej aplikacji dalej wysyłać SMS-y?"</string>
+ <string name="sms_control_yes" msgid="3663725993855816807">"Pozwól"</string>
+ <string name="sms_control_no" msgid="625438561395534982">"Odmów"</string>
+ <string name="sms_short_code_confirm_title" msgid="1666863092640877318">"Wysłać droższego SMS-a?"</string>
+ <string name="sms_premium_short_code_confirm_title" msgid="3811263856304367838">"Wysłać droższego SMS-a?"</string>
+ <string name="sms_short_code_confirm_message" msgid="5616409294907295407">"<b><xliff:g id="APP_NAME">%1$s</xliff:g></b> chce wysłać SMS-a pod numer <b><xliff:g id="DEST_ADDRESS">%2$s</xliff:g></b>, który wygląda na dodatkowo płatny.<p>Może to spowodować doliczenie do Twojego rachunku za komórkę opłaty za usługę dodatkową.<p>Chcesz pozwolić tej aplikacji na wysłanie SMS-a?"</string>
+ <string name="sms_premium_short_code_confirm_message" msgid="6214083016284738667">"<b><xliff:g id="APP_NAME">%1$s</xliff:g></b> chce wysłać SMS-a pod numer <b><xliff:g id="DEST_ADDRESS">%2$s</xliff:g></b>, który jest dodatkowo płatny.<p><b>To spowoduje doliczenie do Twojego rachunku za komórkę opłaty za usługę dodatkową.</b><p>Chcesz pozwolić tej aplikacji na wysłanie SMS-a?"</string>
+ <string name="sms_short_code_confirm_allow" msgid="8957573662645722940">"Wyślij wiadomość"</string>
+ <string name="sms_short_code_confirm_deny" msgid="6374609298084435887">"Nie wysyłaj"</string>
+ <string name="sms_short_code_confirm_report" msgid="2588793956061677070">"Zgłoś złośliwą aplikację"</string>
<string name="sim_removed_title" msgid="6227712319223226185">"Karta SIM wyjęta"</string>
<string name="sim_removed_message" msgid="2333164559970958645">"Sieć komórkowa będzie niedostępna do chwili ponownego uruchomienia urządzenia z użyciem ważnej karty SIM."</string>
<string name="sim_done_button" msgid="827949989369963775">"Gotowe"</string>
@@ -1063,10 +1067,8 @@
<string name="adb_active_notification_message" msgid="1016654627626476142">"Dotknij, aby wyłączyć debugowanie USB."</string>
<string name="select_input_method" msgid="4653387336791222978">"Wybierz metodę wprowadzania"</string>
<string name="configure_input_methods" msgid="9091652157722495116">"Konfiguruj metody wprowadzania"</string>
- <!-- no translation found for use_physical_keyboard (6203112478095117625) -->
- <skip />
- <!-- no translation found for hardware (7517821086888990278) -->
- <skip />
+ <string name="use_physical_keyboard" msgid="6203112478095117625">"Klawiatura fizyczna"</string>
+ <string name="hardware" msgid="7517821086888990278">"Sprzęt"</string>
<string name="fast_scroll_alphabet" msgid="5433275485499039199">" AĄBCĆDEĘFGHIJKLŁMNŃOÓPQRSŚTUVWXYZŹŻ"</string>
<string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="candidates_style" msgid="4333913089637062257"><u>"kandydaci"</u></string>
diff --git a/core/res/res/values-pt-rPT/strings.xml b/core/res/res/values-pt-rPT/strings.xml
index 0f55711..c35cbb6 100644
--- a/core/res/res/values-pt-rPT/strings.xml
+++ b/core/res/res/values-pt-rPT/strings.xml
@@ -286,10 +286,8 @@
<string name="permdesc_setOrientation" msgid="3046126619316671476">"Permite que a aplicação altere a rotação do ecrã em qualquer momento. Nunca deve ser necessário para aplicações normais."</string>
<string name="permlab_setPointerSpeed" msgid="9175371613322562934">"alterar a veloc. do ponteiro"</string>
<string name="permdesc_setPointerSpeed" msgid="6866563234274104233">"Permite à aplicação mudar em qualquer altura a velocidade do ponteiro do rato ou do trackpad. Nunca deverá ser necessário para aplicações normais."</string>
- <!-- no translation found for permlab_setKeyboardLayout (4778731703600909340) -->
- <skip />
- <!-- no translation found for permdesc_setKeyboardLayout (8480016771134175879) -->
- <skip />
+ <string name="permlab_setKeyboardLayout" msgid="4778731703600909340">"alterar o esquema de teclado"</string>
+ <string name="permdesc_setKeyboardLayout" msgid="8480016771134175879">"Permite que a aplicação altere o esquema de teclado. Nunca deverá ser necessário para aplicações normais."</string>
<string name="permlab_signalPersistentProcesses" msgid="4539002991947376659">"enviar sinais Linux para aplicações"</string>
<string name="permdesc_signalPersistentProcesses" msgid="4896992079182649141">"Permite à aplicação pedir que o sinal fornecido seja enviado a todos os processos persistentes."</string>
<string name="permlab_persistentActivity" msgid="8841113627955563938">"fazer com que a aplicação seja sempre executada"</string>
@@ -1009,11 +1007,17 @@
<string name="wifi_p2p_enter_pin_message" msgid="5920929550367828970">"Introduza o PIN solicitado:"</string>
<string name="wifi_p2p_show_pin_message" msgid="8530563323880921094">"PIN:"</string>
<string name="select_character" msgid="3365550120617701745">"Introduzir carácter"</string>
- <string name="sms_control_default_app_name" msgid="3058577482636640465">"Aplicação desconhecida"</string>
<string name="sms_control_title" msgid="7296612781128917719">"A enviar mensagens SMS"</string>
- <string name="sms_control_message" msgid="4073755190243093924">"Está a ser enviado um grande número de mensagens SMS. Toque em “OK” para continuar ou “Cancelar” para parar o envio."</string>
- <string name="sms_control_yes" msgid="2532062172402615953">"OK"</string>
- <string name="sms_control_no" msgid="1715320703137199869">"Cancelar"</string>
+ <string name="sms_control_message" msgid="3867899169651496433">"<b><xliff:g id="APP_NAME">%1$s</xliff:g></b> está a enviar um grande número de mensagens SMS. Pretende autorizar que a aplicação continue a enviar mensagens?"</string>
+ <string name="sms_control_yes" msgid="3663725993855816807">"Permitir"</string>
+ <string name="sms_control_no" msgid="625438561395534982">"Recusar"</string>
+ <string name="sms_short_code_confirm_title" msgid="1666863092640877318">"Enviar SMS ao código pequeno?"</string>
+ <string name="sms_premium_short_code_confirm_title" msgid="3811263856304367838">"Enviar SMS premium?"</string>
+ <string name="sms_short_code_confirm_message" msgid="5616409294907295407">"<b><xliff:g id="APP_NAME">%1$s</xliff:g></b> pretende enviar um SMS para <b><xliff:g id="DEST_ADDRESS">%2$s</xliff:g></b>, que parece ser um código SMS pequeno.<p>Enviar esta mensagem a alguns códigos pequenos pode fazer com que sejam faturados serviços premium na sua conta de telemóvel.<p>Pretende autorizar que a aplicação envie a mensagem?"</string>
+ <string name="sms_premium_short_code_confirm_message" msgid="6214083016284738667">"<b><xliff:g id="APP_NAME">%1$s</xliff:g></b> pretende enviar um SMS a <b><xliff:g id="DEST_ADDRESS">%2$s</xliff:g></b>, que é um pequeno código de SMS premium.<p><b>Enviar uma mensagem para este destino irá fazer com que sejam faturados serviços premium na sua conta de telemóvel.</b><p>Pretende autorizar que a aplicação envie a mensagem?"</string>
+ <string name="sms_short_code_confirm_allow" msgid="8957573662645722940">"Enviar mensagem"</string>
+ <string name="sms_short_code_confirm_deny" msgid="6374609298084435887">"Não enviar"</string>
+ <string name="sms_short_code_confirm_report" msgid="2588793956061677070">"Comunicar aplicação maliciosa"</string>
<string name="sim_removed_title" msgid="6227712319223226185">"Cartão SIM removido"</string>
<string name="sim_removed_message" msgid="2333164559970958645">"A rede de telemóvel estará indisponível até que reinicie o aparelho com um cartão SIM válido inserido."</string>
<string name="sim_done_button" msgid="827949989369963775">"Concluído"</string>
@@ -1063,10 +1067,8 @@
<string name="adb_active_notification_message" msgid="1016654627626476142">"Toque para desativar a depuração USB."</string>
<string name="select_input_method" msgid="4653387336791222978">"Escolher o método de entrada"</string>
<string name="configure_input_methods" msgid="9091652157722495116">"Configurar métodos de introdução"</string>
- <!-- no translation found for use_physical_keyboard (6203112478095117625) -->
- <skip />
- <!-- no translation found for hardware (7517821086888990278) -->
- <skip />
+ <string name="use_physical_keyboard" msgid="6203112478095117625">"Teclado físico"</string>
+ <string name="hardware" msgid="7517821086888990278">"Hardware"</string>
<string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="candidates_style" msgid="4333913089637062257"><u>"candidatos"</u></string>
diff --git a/core/res/res/values-pt/strings.xml b/core/res/res/values-pt/strings.xml
index 1beb4e7..c22a170 100644
--- a/core/res/res/values-pt/strings.xml
+++ b/core/res/res/values-pt/strings.xml
@@ -286,10 +286,8 @@
<string name="permdesc_setOrientation" msgid="3046126619316671476">"Permite que o aplicativo gire a tela a qualquer momento. Nunca deve ser necessário para aplicativos normais."</string>
<string name="permlab_setPointerSpeed" msgid="9175371613322562934">"alterar velocidade do ponteiro"</string>
<string name="permdesc_setPointerSpeed" msgid="6866563234274104233">"Permite que o aplicativo altere a velocidade do cursos do mouse ou trackpad a qualquer momento. Nunca deve ser necessário para aplicativos normais."</string>
- <!-- no translation found for permlab_setKeyboardLayout (4778731703600909340) -->
- <skip />
- <!-- no translation found for permdesc_setKeyboardLayout (8480016771134175879) -->
- <skip />
+ <string name="permlab_setKeyboardLayout" msgid="4778731703600909340">"alterar layout do teclado"</string>
+ <string name="permdesc_setKeyboardLayout" msgid="8480016771134175879">"Permite que o aplicativo altere o layout do teclado. Não será necessário para aplicativos normais."</string>
<string name="permlab_signalPersistentProcesses" msgid="4539002991947376659">"enviar sinais para aplicativos Linux"</string>
<string name="permdesc_signalPersistentProcesses" msgid="4896992079182649141">"Permite que o aplicativo solicite o envio do sinal fornecido a todos os processos persistentes."</string>
<string name="permlab_persistentActivity" msgid="8841113627955563938">"sempre executar o aplicativo"</string>
@@ -1009,11 +1007,17 @@
<string name="wifi_p2p_enter_pin_message" msgid="5920929550367828970">"Digite o PIN obrigatório:"</string>
<string name="wifi_p2p_show_pin_message" msgid="8530563323880921094">"PIN:"</string>
<string name="select_character" msgid="3365550120617701745">"Inserir caractere"</string>
- <string name="sms_control_default_app_name" msgid="3058577482636640465">"Aplicativo desconhecido"</string>
<string name="sms_control_title" msgid="7296612781128917719">"Enviando mensagens SMS"</string>
- <string name="sms_control_message" msgid="4073755190243093924">"Muitas mensagens SMS estão sendo enviadas. Selecione \"OK\" para continuar ou \"Cancelar\" para interromper o envio."</string>
- <string name="sms_control_yes" msgid="2532062172402615953">"OK"</string>
- <string name="sms_control_no" msgid="1715320703137199869">"Cancelar"</string>
+ <string name="sms_control_message" msgid="3867899169651496433">"<b><xliff:g id="APP_NAME">%1$s</xliff:g></b> envia uma grande quantidade de mensagens SMS. Deseja permitir que este aplicativo continue enviando mensagens?"</string>
+ <string name="sms_control_yes" msgid="3663725993855816807">"Permitir"</string>
+ <string name="sms_control_no" msgid="625438561395534982">"Negar"</string>
+ <string name="sms_short_code_confirm_title" msgid="1666863092640877318">"Enviar SMS para código curto?"</string>
+ <string name="sms_premium_short_code_confirm_title" msgid="3811263856304367838">"Enviar SMS premium?"</string>
+ <string name="sms_short_code_confirm_message" msgid="5616409294907295407">"<b><xliff:g id="APP_NAME">%1$s</xliff:g></b> deseja enviar uma mensagem de texto para <b><xliff:g id="DEST_ADDRESS">%2$s</xliff:g></b>, que parece ser um código curto SMS.<p>O envio de mensagens de texto a alguns códigos curtos pode fazer com que a conta seja cobrada por serviços premium.<p>Deseja permitir que este aplicativo envie a mensagem?"</string>
+ <string name="sms_premium_short_code_confirm_message" msgid="6214083016284738667">"<b><xliff:g id="APP_NAME">%1$s</xliff:g></b> deseja enviar uma mensagem de texto para <b><xliff:g id="DEST_ADDRESS">%2$s</xliff:g></b>, que é um código curto SMS premium.<p><b>O envio de uma mensagem a esse destino fará com que a conta seja cobrada por serviços premium.</b><p>Deseja permitir que este aplicativo envie a mensagem?"</string>
+ <string name="sms_short_code_confirm_allow" msgid="8957573662645722940">"Enviar mensagem"</string>
+ <string name="sms_short_code_confirm_deny" msgid="6374609298084435887">"Não enviar"</string>
+ <string name="sms_short_code_confirm_report" msgid="2588793956061677070">"Denunciar aplicativo malicioso"</string>
<string name="sim_removed_title" msgid="6227712319223226185">"Cartão SIM removido"</string>
<string name="sim_removed_message" msgid="2333164559970958645">"A rede móvel ficará indisponível até que você reinicie com um cartão SIM válido inserido."</string>
<string name="sim_done_button" msgid="827949989369963775">"Concluído"</string>
@@ -1063,10 +1067,8 @@
<string name="adb_active_notification_message" msgid="1016654627626476142">"Toque para desativar a depuração do USB."</string>
<string name="select_input_method" msgid="4653387336791222978">"Selecione o método de entrada"</string>
<string name="configure_input_methods" msgid="9091652157722495116">"Configurar métodos de entrada"</string>
- <!-- no translation found for use_physical_keyboard (6203112478095117625) -->
- <skip />
- <!-- no translation found for hardware (7517821086888990278) -->
- <skip />
+ <string name="use_physical_keyboard" msgid="6203112478095117625">"Teclado físico"</string>
+ <string name="hardware" msgid="7517821086888990278">"Hardware"</string>
<string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="candidates_style" msgid="4333913089637062257"><u>"candidatos"</u></string>
diff --git a/core/res/res/values-rm/strings.xml b/core/res/res/values-rm/strings.xml
index 637e4b1..6f066de 100644
--- a/core/res/res/values-rm/strings.xml
+++ b/core/res/res/values-rm/strings.xml
@@ -1489,13 +1489,27 @@
<!-- no translation found for wifi_p2p_show_pin_message (8530563323880921094) -->
<skip />
<string name="select_character" msgid="3365550120617701745">"Inserir in caracter"</string>
- <!-- no translation found for sms_control_default_app_name (3058577482636640465) -->
- <skip />
<string name="sms_control_title" msgid="7296612781128917719">"Trametter messadis SMS"</string>
- <!-- no translation found for sms_control_message (4073755190243093924) -->
+ <!-- no translation found for sms_control_message (3867899169651496433) -->
<skip />
- <string name="sms_control_yes" msgid="2532062172402615953">"OK"</string>
- <string name="sms_control_no" msgid="1715320703137199869">"Interrumper"</string>
+ <!-- no translation found for sms_control_yes (3663725993855816807) -->
+ <skip />
+ <!-- no translation found for sms_control_no (625438561395534982) -->
+ <skip />
+ <!-- no translation found for sms_short_code_confirm_title (1666863092640877318) -->
+ <skip />
+ <!-- no translation found for sms_premium_short_code_confirm_title (3811263856304367838) -->
+ <skip />
+ <!-- no translation found for sms_short_code_confirm_message (5616409294907295407) -->
+ <skip />
+ <!-- no translation found for sms_premium_short_code_confirm_message (6214083016284738667) -->
+ <skip />
+ <!-- no translation found for sms_short_code_confirm_allow (8957573662645722940) -->
+ <skip />
+ <!-- no translation found for sms_short_code_confirm_deny (6374609298084435887) -->
+ <skip />
+ <!-- no translation found for sms_short_code_confirm_report (2588793956061677070) -->
+ <skip />
<!-- no translation found for sim_removed_title (6227712319223226185) -->
<skip />
<!-- no translation found for sim_removed_message (2333164559970958645) -->
diff --git a/core/res/res/values-ro/strings.xml b/core/res/res/values-ro/strings.xml
index 0f773a5..619e3b9 100644
--- a/core/res/res/values-ro/strings.xml
+++ b/core/res/res/values-ro/strings.xml
@@ -286,10 +286,8 @@
<string name="permdesc_setOrientation" msgid="3046126619316671476">"Permite aplicaţiei să modifice rotaţia ecranului în orice moment. Nu ar trebui să fie niciodată necesară pentru aplicaţiile obişnuite."</string>
<string name="permlab_setPointerSpeed" msgid="9175371613322562934">"modifică viteza indicatorului"</string>
<string name="permdesc_setPointerSpeed" msgid="6866563234274104233">"Permite aplicaţiei să modifice oricând viteza indicatorului mouse-ului sau al trackpadului. Nu ar trebui să fie niciodată necesară pentru aplicaţiile obişnuite."</string>
- <!-- no translation found for permlab_setKeyboardLayout (4778731703600909340) -->
- <skip />
- <!-- no translation found for permdesc_setKeyboardLayout (8480016771134175879) -->
- <skip />
+ <string name="permlab_setKeyboardLayout" msgid="4778731703600909340">"modificaţi aspectul tastaturii"</string>
+ <string name="permdesc_setKeyboardLayout" msgid="8480016771134175879">"Permite aplicaţiei să modifice aspectul tastaturii. Nu ar trebui să fie niciodată necesară pentru aplicaţii obişnuite."</string>
<string name="permlab_signalPersistentProcesses" msgid="4539002991947376659">"trimitere semnale Linux către aplicaţii"</string>
<string name="permdesc_signalPersistentProcesses" msgid="4896992079182649141">"Permite aplicaţiei să solicite trimiterea semnalului furnizat către toate procesele persistente."</string>
<string name="permlab_persistentActivity" msgid="8841113627955563938">"rulare continuă a aplicaţiei"</string>
@@ -1009,11 +1007,17 @@
<string name="wifi_p2p_enter_pin_message" msgid="5920929550367828970">"Introduceţi codul PIN necesar:"</string>
<string name="wifi_p2p_show_pin_message" msgid="8530563323880921094">"Cod PIN:"</string>
<string name="select_character" msgid="3365550120617701745">"Introduceţi caracterul"</string>
- <string name="sms_control_default_app_name" msgid="3058577482636640465">"Aplicaţie necunoscută"</string>
<string name="sms_control_title" msgid="7296612781128917719">"Se trimit mesaje SMS"</string>
- <string name="sms_control_message" msgid="4073755190243093924">"În acest moment se trimit multe mesaje SMS. Atingeţi „OK” pentru a continua sau „Anulaţi” pentru a opri trimiterea."</string>
- <string name="sms_control_yes" msgid="2532062172402615953">"OK"</string>
- <string name="sms_control_no" msgid="1715320703137199869">"Anulaţi"</string>
+ <string name="sms_control_message" msgid="3867899169651496433">"<b><xliff:g id="APP_NAME">%1$s</xliff:g></b> trimite un număr mare de mesaje SMS. Permiteţi acestei aplicaţii să trimită în continuare mesaje?"</string>
+ <string name="sms_control_yes" msgid="3663725993855816807">"Permiteţi"</string>
+ <string name="sms_control_no" msgid="625438561395534982">"Refuzaţi"</string>
+ <string name="sms_short_code_confirm_title" msgid="1666863092640877318">"Trimiteţi SMS la codul scurt?"</string>
+ <string name="sms_premium_short_code_confirm_title" msgid="3811263856304367838">"Trimiteţi SMS premium?"</string>
+ <string name="sms_short_code_confirm_message" msgid="5616409294907295407">"<b><xliff:g id="APP_NAME">%1$s</xliff:g></b> intenţionează să trimită un mesaj text la <b><xliff:g id="DEST_ADDRESS">%2$s</xliff:g></b>, care pare a fi un cod scurt SMS.<p>Trimiterea de mesaje text la unele coduri scurte poate determina taxarea contului dvs. mobil pentru servicii premium.<p>Permiteţi acestei aplicaţii să trimită mesajul?"</string>
+ <string name="sms_premium_short_code_confirm_message" msgid="6214083016284738667">"<b><xliff:g id="APP_NAME">%1$s</xliff:g></b> intenţionează să trimită un mesaj text la <b><xliff:g id="DEST_ADDRESS">%2$s</xliff:g></b>, care este un cod scurt SMS premium.<p><b>Trimiterea unui mesaj la această destinaţie va determina taxarea contului dvs. mobil pentru servicii premium.</b><p>Permiteţi acestei aplicaţii să trimită mesajul?"</string>
+ <string name="sms_short_code_confirm_allow" msgid="8957573662645722940">"Trimiteţi mesajul"</string>
+ <string name="sms_short_code_confirm_deny" msgid="6374609298084435887">"Nu trimiteţi"</string>
+ <string name="sms_short_code_confirm_report" msgid="2588793956061677070">"Raport. aplic.rău intenţionată"</string>
<string name="sim_removed_title" msgid="6227712319223226185">"Card SIM eliminat"</string>
<string name="sim_removed_message" msgid="2333164559970958645">"Reţeaua mobilă va fi indisponibilă până când reporniţi cu o cartelă SIM validă introdusă."</string>
<string name="sim_done_button" msgid="827949989369963775">"Terminat"</string>
@@ -1063,10 +1067,8 @@
<string name="adb_active_notification_message" msgid="1016654627626476142">"Atingeţi pentru a dezactiva depanarea USB."</string>
<string name="select_input_method" msgid="4653387336791222978">"Alegeţi metoda de introducere"</string>
<string name="configure_input_methods" msgid="9091652157722495116">"Configurare metode introducere"</string>
- <!-- no translation found for use_physical_keyboard (6203112478095117625) -->
- <skip />
- <!-- no translation found for hardware (7517821086888990278) -->
- <skip />
+ <string name="use_physical_keyboard" msgid="6203112478095117625">"Tastatură fizică"</string>
+ <string name="hardware" msgid="7517821086888990278">"Hardware"</string>
<string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="candidates_style" msgid="4333913089637062257"><u>"candidaţi"</u></string>
diff --git a/core/res/res/values-ru/strings.xml b/core/res/res/values-ru/strings.xml
index 7b7c95bd..1de5237 100644
--- a/core/res/res/values-ru/strings.xml
+++ b/core/res/res/values-ru/strings.xml
@@ -286,10 +286,8 @@
<string name="permdesc_setOrientation" msgid="3046126619316671476">"Приложение сможет менять ориентацию экрана. Это разрешение не используется обычными приложениями."</string>
<string name="permlab_setPointerSpeed" msgid="9175371613322562934">"изменять скорость указателя"</string>
<string name="permdesc_setPointerSpeed" msgid="6866563234274104233">"Приложение сможет в любой момент изменить скорость движения указателя мыши или сенсорной панели. Это разрешение не используется обычными приложениями."</string>
- <!-- no translation found for permlab_setKeyboardLayout (4778731703600909340) -->
- <skip />
- <!-- no translation found for permdesc_setKeyboardLayout (8480016771134175879) -->
- <skip />
+ <string name="permlab_setKeyboardLayout" msgid="4778731703600909340">"менять раскладку автоматически"</string>
+ <string name="permdesc_setKeyboardLayout" msgid="8480016771134175879">"Разрешить автоматическую смену раскладки клавиатуры (используется лишь в некоторых приложениях)."</string>
<string name="permlab_signalPersistentProcesses" msgid="4539002991947376659">"отправка сигналов Linux приложениям"</string>
<string name="permdesc_signalPersistentProcesses" msgid="4896992079182649141">"Приложение сможет запрашивать передачу полученного сигнала всем постоянным процессам."</string>
<string name="permlab_persistentActivity" msgid="8841113627955563938">"постоянная работа приложения"</string>
@@ -1009,11 +1007,17 @@
<string name="wifi_p2p_enter_pin_message" msgid="5920929550367828970">"Введите PIN-код:"</string>
<string name="wifi_p2p_show_pin_message" msgid="8530563323880921094">"PIN-код:"</string>
<string name="select_character" msgid="3365550120617701745">"Введите символ"</string>
- <string name="sms_control_default_app_name" msgid="3058577482636640465">"Неизвестное приложение"</string>
<string name="sms_control_title" msgid="7296612781128917719">"Отправка SMS-сообщений"</string>
- <string name="sms_control_message" msgid="4073755190243093924">"Отправляется большое количество SMS-сообщений. Нажмите \"ОК\", чтобы продолжить отправку, или \"Отмена\", чтобы прекратить ее."</string>
- <string name="sms_control_yes" msgid="2532062172402615953">"ОК"</string>
- <string name="sms_control_no" msgid="1715320703137199869">"Отмена"</string>
+ <string name="sms_control_message" msgid="3867899169651496433">"<b><xliff:g id="APP_NAME">%1$s</xliff:g></b> отправляет большое количество SMS. Разрешить приложению и дальше отправлять сообщения?"</string>
+ <string name="sms_control_yes" msgid="3663725993855816807">"Разрешить"</string>
+ <string name="sms_control_no" msgid="625438561395534982">"Запретить"</string>
+ <string name="sms_short_code_confirm_title" msgid="1666863092640877318">"Отправить SMS?"</string>
+ <string name="sms_premium_short_code_confirm_title" msgid="3811263856304367838">"Отправить SMS?"</string>
+ <string name="sms_short_code_confirm_message" msgid="5616409294907295407">"<b><xliff:g id="APP_NAME">%1$s</xliff:g></b> собирается отправить SMS-сообщение на короткий номер <b><xliff:g id="DEST_ADDRESS">%2$s</xliff:g></b><p> За отправку сообщений на некоторые короткие номера с вашего счета могут списываться дополнительные средства.<p>Разрешить отправку?"</string>
+ <string name="sms_premium_short_code_confirm_message" msgid="6214083016284738667">"<b><xliff:g id="APP_NAME">%1$s</xliff:g></b> собирается отправить SMS на короткий номер <b><xliff:g id="DEST_ADDRESS">%2$s</xliff:g></b>.<p><b> Если это произойдет, с вашего счета будут списаны дополнительные средства.</b><p>Разрешить отправку?"</string>
+ <string name="sms_short_code_confirm_allow" msgid="8957573662645722940">"Отправить сообщение"</string>
+ <string name="sms_short_code_confirm_deny" msgid="6374609298084435887">"Не отправлять"</string>
+ <string name="sms_short_code_confirm_report" msgid="2588793956061677070">"Сообщить о вредоносном ПО"</string>
<string name="sim_removed_title" msgid="6227712319223226185">"SIM-карта удалена"</string>
<string name="sim_removed_message" msgid="2333164559970958645">"Пока вы не вставите действующую SIM-карту, мобильная сеть будет недоступна."</string>
<string name="sim_done_button" msgid="827949989369963775">"Готово"</string>
@@ -1063,10 +1067,8 @@
<string name="adb_active_notification_message" msgid="1016654627626476142">"Нажмите, чтобы отключить отладку по USB."</string>
<string name="select_input_method" msgid="4653387336791222978">"Выберите способ ввода"</string>
<string name="configure_input_methods" msgid="9091652157722495116">"Настройка способов ввода"</string>
- <!-- no translation found for use_physical_keyboard (6203112478095117625) -->
- <skip />
- <!-- no translation found for hardware (7517821086888990278) -->
- <skip />
+ <string name="use_physical_keyboard" msgid="6203112478095117625">"Физическая клавиатура"</string>
+ <string name="hardware" msgid="7517821086888990278">"Аппаратура"</string>
<string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="candidates_style" msgid="4333913089637062257"><u>"варианты"</u></string>
diff --git a/core/res/res/values-sk/strings.xml b/core/res/res/values-sk/strings.xml
index a2ac96e..34c9eb0 100644
--- a/core/res/res/values-sk/strings.xml
+++ b/core/res/res/values-sk/strings.xml
@@ -286,10 +286,8 @@
<string name="permdesc_setOrientation" msgid="3046126619316671476">"Umožňuje aplikácii kedykoľvek zmeniť otáčanie obrazovky. Bežné aplikácie by toto nastavenie nemali nikdy potrebovať."</string>
<string name="permlab_setPointerSpeed" msgid="9175371613322562934">"zmena rýchlosti ukazovateľa"</string>
<string name="permdesc_setPointerSpeed" msgid="6866563234274104233">"Umožňuje aplikácii kedykoľvek zmeniť rýchlosť kurzora myši alebo touchpadu. Bežné aplikácie by toto nastavenie nemali nikdy potrebovať."</string>
- <!-- no translation found for permlab_setKeyboardLayout (4778731703600909340) -->
- <skip />
- <!-- no translation found for permdesc_setKeyboardLayout (8480016771134175879) -->
- <skip />
+ <string name="permlab_setKeyboardLayout" msgid="4778731703600909340">"zmeniť rozloženie klávesnice"</string>
+ <string name="permdesc_setKeyboardLayout" msgid="8480016771134175879">"Umožňuje aplikácii zmeniť rozloženie klávesnice. Bežné aplikácie by toto nastavenie nemali nikdy potrebovať."</string>
<string name="permlab_signalPersistentProcesses" msgid="4539002991947376659">"odoslať aplikáciám signály systému Linux"</string>
<string name="permdesc_signalPersistentProcesses" msgid="4896992079182649141">"Umožňuje aplikácii vyžiadať odoslanie poskytnutého signálu všetkým trvalým procesom."</string>
<string name="permlab_persistentActivity" msgid="8841113627955563938">"nastaviť, aby bola aplikácia neustále spustená"</string>
@@ -1009,11 +1007,17 @@
<string name="wifi_p2p_enter_pin_message" msgid="5920929550367828970">"Zadajte požadovaný kód PIN:"</string>
<string name="wifi_p2p_show_pin_message" msgid="8530563323880921094">"PIN:"</string>
<string name="select_character" msgid="3365550120617701745">"Vkladanie znakov"</string>
- <string name="sms_control_default_app_name" msgid="3058577482636640465">"Neznáma aplikácia"</string>
<string name="sms_control_title" msgid="7296612781128917719">"Odosielanie správ SMS"</string>
- <string name="sms_control_message" msgid="4073755190243093924">"Odosiela sa veľký počet správ SMS. Ak chcete pokračovať, dotknite sa tlačidla OK. Ak chcete odosielanie ukončiť, dotknite sa tlačidla Zrušiť."</string>
- <string name="sms_control_yes" msgid="2532062172402615953">"OK"</string>
- <string name="sms_control_no" msgid="1715320703137199869">"Zrušiť"</string>
+ <string name="sms_control_message" msgid="3867899169651496433">"Aplikácia <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> posiela veľký počet správ SMS. Chcete tejto aplikácií povoliť, aby aj naďalej posielala správy?"</string>
+ <string name="sms_control_yes" msgid="3663725993855816807">"Povoliť"</string>
+ <string name="sms_control_no" msgid="625438561395534982">"Odmietnuť"</string>
+ <string name="sms_short_code_confirm_title" msgid="1666863092640877318">"Odoslať SMS na skrátené číslo?"</string>
+ <string name="sms_premium_short_code_confirm_title" msgid="3811263856304367838">"Odoslať prémiovú správu SMS?"</string>
+ <string name="sms_short_code_confirm_message" msgid="5616409294907295407">"Aplikácia <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> chce odoslať textovú správu na číslo <b><xliff:g id="DEST_ADDRESS">%2$s</xliff:g></b>, ktoré sa zdá byť skráteným číslom SMS.<p>Odoslanie správy na skrátené číslo môže spôsobiť, že na účet vášho mobilného zariadenia budú účtované poplatky za prémiové služby.<p>Chcete aplikácií povoliť túto správu odoslať?"</string>
+ <string name="sms_premium_short_code_confirm_message" msgid="6214083016284738667">"Aplikácia <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> chce odoslať textovú správu na číslo <b><xliff:g id="DEST_ADDRESS">%2$s</xliff:g></b>, ktoré je prémiovým skráteným číslom SMS.<p><b>Odoslanie správy na toto číslo spôsobí, že na účet vášho mobilného zariadenia budú účtované poplatky za prémiové služby.</b><p>Chcete aplikácii povoliť túto správu odoslať?"</string>
+ <string name="sms_short_code_confirm_allow" msgid="8957573662645722940">"Odoslať správu"</string>
+ <string name="sms_short_code_confirm_deny" msgid="6374609298084435887">"Neodoslať"</string>
+ <string name="sms_short_code_confirm_report" msgid="2588793956061677070">"Nahlásiť škodlivú aplikáciu"</string>
<string name="sim_removed_title" msgid="6227712319223226185">"Karta SIM bola odobraná"</string>
<string name="sim_removed_message" msgid="2333164559970958645">"Mobilná sieť nebude k dispozícii, kým nevložíte platnú kartu SIM a zariadenie nereštartujete."</string>
<string name="sim_done_button" msgid="827949989369963775">"Hotovo"</string>
@@ -1063,10 +1067,8 @@
<string name="adb_active_notification_message" msgid="1016654627626476142">"Dotknutím zakážete ladenie USB."</string>
<string name="select_input_method" msgid="4653387336791222978">"Zvoliť metódu vstupu"</string>
<string name="configure_input_methods" msgid="9091652157722495116">"Nastavenie metód vstupu"</string>
- <!-- no translation found for use_physical_keyboard (6203112478095117625) -->
- <skip />
- <!-- no translation found for hardware (7517821086888990278) -->
- <skip />
+ <string name="use_physical_keyboard" msgid="6203112478095117625">"Fyzická klávesnica"</string>
+ <string name="hardware" msgid="7517821086888990278">"Hardvér"</string>
<string name="fast_scroll_alphabet" msgid="5433275485499039199">" AÁÄBCČDĎDZDŽEÉFGHCHIÍJKLĽMNŇOÓÔPRŔSŠTŤUÚVWXYÝZŽ"</string>
<string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="candidates_style" msgid="4333913089637062257"><u>"kandidáti"</u></string>
diff --git a/core/res/res/values-sl/strings.xml b/core/res/res/values-sl/strings.xml
index 2b452ae..a1a9a03 100644
--- a/core/res/res/values-sl/strings.xml
+++ b/core/res/res/values-sl/strings.xml
@@ -286,10 +286,8 @@
<string name="permdesc_setOrientation" msgid="3046126619316671476">"Programu omogoča, da kadar koli zasuka zaslon. Ne uporabljajte za navadne programe."</string>
<string name="permlab_setPointerSpeed" msgid="9175371613322562934">"spreminjanje hitrosti kazalca"</string>
<string name="permdesc_setPointerSpeed" msgid="6866563234274104233">"Programu omogoča spreminjanje hitrosti kazalca miške ali sledilne ploščice. Tega ni treba nikoli uporabiti za navadne programe."</string>
- <!-- no translation found for permlab_setKeyboardLayout (4778731703600909340) -->
- <skip />
- <!-- no translation found for permdesc_setKeyboardLayout (8480016771134175879) -->
- <skip />
+ <string name="permlab_setKeyboardLayout" msgid="4778731703600909340">"spreminjanje postavitve tipkovnice"</string>
+ <string name="permdesc_setKeyboardLayout" msgid="8480016771134175879">"Aplikaciji omogoča, da kadar koli spremeni postavitev tipkovnice. Običajne aplikacije tega ne potrebujejo."</string>
<string name="permlab_signalPersistentProcesses" msgid="4539002991947376659">"pošiljanje signalov Linuxa programom"</string>
<string name="permdesc_signalPersistentProcesses" msgid="4896992079182649141">"Programu omogoča, da zahteva, da je posredovani signal poslan vsem trajnim procesom."</string>
<string name="permlab_persistentActivity" msgid="8841113627955563938">"neprekinjeno izvajanje programov"</string>
@@ -1009,11 +1007,17 @@
<string name="wifi_p2p_enter_pin_message" msgid="5920929550367828970">"Vnesite zahtevano kodo PIN:"</string>
<string name="wifi_p2p_show_pin_message" msgid="8530563323880921094">"PIN:"</string>
<string name="select_character" msgid="3365550120617701745">"Vstavljanje znaka"</string>
- <string name="sms_control_default_app_name" msgid="3058577482636640465">"Neznan program"</string>
<string name="sms_control_title" msgid="7296612781128917719">"Pošiljanje sporočil SMS"</string>
- <string name="sms_control_message" msgid="4073755190243093924">"V pošiljanju je veliko sporočil SMS. Če želite nadaljevati, izberite »V redu«. Če želite pošiljanje ustaviti, izberite »Prekliči«."</string>
- <string name="sms_control_yes" msgid="2532062172402615953">"V redu"</string>
- <string name="sms_control_no" msgid="1715320703137199869">"Prekliči"</string>
+ <string name="sms_control_message" msgid="3867899169651496433">"<b><xliff:g id="APP_NAME">%1$s</xliff:g></b> pošilja veliko SMS-ov. Ali želite dovoliti, da jih še naprej pošilja?"</string>
+ <string name="sms_control_yes" msgid="3663725993855816807">"Dovoli"</string>
+ <string name="sms_control_no" msgid="625438561395534982">"Zavrni"</string>
+ <string name="sms_short_code_confirm_title" msgid="1666863092640877318">"Pošljem SMS na kratko štev.?"</string>
+ <string name="sms_premium_short_code_confirm_title" msgid="3811263856304367838">"Pošljem SMS za plačlj. stor.?"</string>
+ <string name="sms_short_code_confirm_message" msgid="5616409294907295407">"<b><xliff:g id="APP_NAME">%1$s</xliff:g></b> želi poslati SMS na številko <b><xliff:g id="DEST_ADDRESS">%2$s</xliff:g></b>, kar je videti kot kratka številka za plačljive storitve SMS.<p>S pošiljanjem sporočil na to številko bo vaš račun za mobilni telefon bremenjen za plačljive storitve.<p>Ali želite aplikaciji dovoliti, da pošlje sporočilo?"</string>
+ <string name="sms_premium_short_code_confirm_message" msgid="6214083016284738667">"<b><xliff:g id="APP_NAME">%1$s</xliff:g></b> želi poslati SMS na številko <b><xliff:g id="DEST_ADDRESS">%2$s</xliff:g></b>, kar je kratka številka za plačljive storitve SMS.<p><b>S pošiljanjem sporočil na to številko bo vaš račun za mobilni telefon bremenjen za plačljive storitve.</b><p>Ali želite aplikaciji dovoliti, da pošlje sporočilo?"</string>
+ <string name="sms_short_code_confirm_allow" msgid="8957573662645722940">"Pošlji sporočilo"</string>
+ <string name="sms_short_code_confirm_deny" msgid="6374609298084435887">"Ne pošlji"</string>
+ <string name="sms_short_code_confirm_report" msgid="2588793956061677070">"Prijavi zlonamerno aplikacijo"</string>
<string name="sim_removed_title" msgid="6227712319223226185">"Kartica SIM odstranjena"</string>
<string name="sim_removed_message" msgid="2333164559970958645">"Mobilno omrežje ne bo na voljo, dokler naprave vnovič ne zaženete z veljavno kartico SIM."</string>
<string name="sim_done_button" msgid="827949989369963775">"Dokončano"</string>
@@ -1063,10 +1067,8 @@
<string name="adb_active_notification_message" msgid="1016654627626476142">"Dotaknite se, če želite onemogočiti iskanje in odpravljanje napak prek vrat USB."</string>
<string name="select_input_method" msgid="4653387336791222978">"Izberite način vnosa"</string>
<string name="configure_input_methods" msgid="9091652157722495116">"Nastavi načine vnosa"</string>
- <!-- no translation found for use_physical_keyboard (6203112478095117625) -->
- <skip />
- <!-- no translation found for hardware (7517821086888990278) -->
- <skip />
+ <string name="use_physical_keyboard" msgid="6203112478095117625">"Fizična tipkovnica"</string>
+ <string name="hardware" msgid="7517821086888990278">"Strojna oprema"</string>
<string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="candidates_style" msgid="4333913089637062257"><u>"kandidati"</u></string>
diff --git a/core/res/res/values-sr/strings.xml b/core/res/res/values-sr/strings.xml
index 0fdce67..b28719b 100644
--- a/core/res/res/values-sr/strings.xml
+++ b/core/res/res/values-sr/strings.xml
@@ -286,10 +286,8 @@
<string name="permdesc_setOrientation" msgid="3046126619316671476">"Дозвољава апликацији да у сваком тренутку промени ротацију екрана. Уобичајене апликације никада не би требало да је користе."</string>
<string name="permlab_setPointerSpeed" msgid="9175371613322562934">"промена брзине показивача"</string>
<string name="permdesc_setPointerSpeed" msgid="6866563234274104233">"Дозвољава апликацији да у било ком тренутку промени брзину показивача миша или показивачког уређаја са плочицом. Уобичајене апликације никада не би требало да је користе."</string>
- <!-- no translation found for permlab_setKeyboardLayout (4778731703600909340) -->
- <skip />
- <!-- no translation found for permdesc_setKeyboardLayout (8480016771134175879) -->
- <skip />
+ <string name="permlab_setKeyboardLayout" msgid="4778731703600909340">"промена распореда тастатуре"</string>
+ <string name="permdesc_setKeyboardLayout" msgid="8480016771134175879">"Дозвољава апликацији да мења распоред тастатуре. Уобичајене апликације никада не би требало да је користе."</string>
<string name="permlab_signalPersistentProcesses" msgid="4539002991947376659">"слање Linux сигнала апликацијама"</string>
<string name="permdesc_signalPersistentProcesses" msgid="4896992079182649141">"Дозвољава апликацији да захтева да испоручени сигнал буде послат свим трајним процесима."</string>
<string name="permlab_persistentActivity" msgid="8841113627955563938">"омогућавање непрекидне активности апликације"</string>
@@ -1009,11 +1007,17 @@
<string name="wifi_p2p_enter_pin_message" msgid="5920929550367828970">"Унесите потребни PIN:"</string>
<string name="wifi_p2p_show_pin_message" msgid="8530563323880921094">"PIN:"</string>
<string name="select_character" msgid="3365550120617701745">"Уметање знака"</string>
- <string name="sms_control_default_app_name" msgid="3058577482636640465">"Непозната апликација"</string>
<string name="sms_control_title" msgid="7296612781128917719">"Слање SMS порука"</string>
- <string name="sms_control_message" msgid="4073755190243093924">"Шаље се велики број SMS порука. Додирните Потврди да бисте наставили или Откажи да бисте зауставили слање."</string>
- <string name="sms_control_yes" msgid="2532062172402615953">"Потврди"</string>
- <string name="sms_control_no" msgid="1715320703137199869">"Откажи"</string>
+ <string name="sms_control_message" msgid="3867899169651496433">"<b><xliff:g id="APP_NAME">%1$s</xliff:g></b> шаље велики број SMS порука. Желите ли да дозволите овој апликацији да настави са слањем порука?"</string>
+ <string name="sms_control_yes" msgid="3663725993855816807">"Дозволи"</string>
+ <string name="sms_control_no" msgid="625438561395534982">"Одбиј"</string>
+ <string name="sms_short_code_confirm_title" msgid="1666863092640877318">"Пошаљи SMS на кратак кôд?"</string>
+ <string name="sms_premium_short_code_confirm_title" msgid="3811263856304367838">"Желите да пошаљете премијум SMS?"</string>
+ <string name="sms_short_code_confirm_message" msgid="5616409294907295407">"<b><xliff:g id="APP_NAME">%1$s</xliff:g></b> жели да вам пошаље текстуалну поруку на адресу <b><xliff:g id="DEST_ADDRESS">%2$s</xliff:g></b>, која можда представља кратак кôд SMS-а.<p>Слање порука на неке кратке кодове може да се наплаћује као премијум услуга са налога за мобилни уређај.<p>Желите ли да дозволите овој апликацији да пошаље поруку?"</string>
+ <string name="sms_premium_short_code_confirm_message" msgid="6214083016284738667">"<b><xliff:g id="APP_NAME">%1$s</xliff:g></b> жели да вам пошаље текстуалну поруку на адресу <b><xliff:g id="DEST_ADDRESS">%2$s</xliff:g></b>, која представља кратак кôд премијум SMS-а.<p><b>Ако се пошаље порука на ово одредиште, биће вам наплаћена премијум услуга са налога за мобилни уређај.</b><p>Желите ли да дозволите овој апликацији да пошаље поруку?"</string>
+ <string name="sms_short_code_confirm_allow" msgid="8957573662645722940">"Пошаљи поруку"</string>
+ <string name="sms_short_code_confirm_deny" msgid="6374609298084435887">"Не шаљи"</string>
+ <string name="sms_short_code_confirm_report" msgid="2588793956061677070">"Пријави злонамерну апликацију"</string>
<string name="sim_removed_title" msgid="6227712319223226185">"SIM картица је уклоњена"</string>
<string name="sim_removed_message" msgid="2333164559970958645">"Мобилна мрежа неће бити доступна док не покренете систем поново уз уметање важеће SIM картице."</string>
<string name="sim_done_button" msgid="827949989369963775">"Готово"</string>
@@ -1063,10 +1067,8 @@
<string name="adb_active_notification_message" msgid="1016654627626476142">"Додирните да бисте онемогућили отклањање грешака са USB-а."</string>
<string name="select_input_method" msgid="4653387336791222978">"Избор метода уноса"</string>
<string name="configure_input_methods" msgid="9091652157722495116">"Подеси методе уноса"</string>
- <!-- no translation found for use_physical_keyboard (6203112478095117625) -->
- <skip />
- <!-- no translation found for hardware (7517821086888990278) -->
- <skip />
+ <string name="use_physical_keyboard" msgid="6203112478095117625">"Физичка тастатура"</string>
+ <string name="hardware" msgid="7517821086888990278">"Хардвер"</string>
<string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="candidates_style" msgid="4333913089637062257"><u>"кандидати"</u></string>
diff --git a/core/res/res/values-sv/strings.xml b/core/res/res/values-sv/strings.xml
index 2c4efc5..da3640d 100644
--- a/core/res/res/values-sv/strings.xml
+++ b/core/res/res/values-sv/strings.xml
@@ -286,10 +286,8 @@
<string name="permdesc_setOrientation" msgid="3046126619316671476">"Gör att appen när som helst kan ändra skärmläget. Behövs inte för vanliga appar."</string>
<string name="permlab_setPointerSpeed" msgid="9175371613322562934">"ändra markörens hastighet"</string>
<string name="permdesc_setPointerSpeed" msgid="6866563234274104233">"Tillåter att appen när som helst ändrar hastigheten för musens eller styrplattans markör. Ska inte behövas för vanliga appar."</string>
- <!-- no translation found for permlab_setKeyboardLayout (4778731703600909340) -->
- <skip />
- <!-- no translation found for permdesc_setKeyboardLayout (8480016771134175879) -->
- <skip />
+ <string name="permlab_setKeyboardLayout" msgid="4778731703600909340">"ändra tangentbordslayout"</string>
+ <string name="permdesc_setKeyboardLayout" msgid="8480016771134175879">"Tillåter att appen ändrar tangentbordets layout. Ska inte behövas för vanliga appar."</string>
<string name="permlab_signalPersistentProcesses" msgid="4539002991947376659">"skicka Linux-signaler till appar"</string>
<string name="permdesc_signalPersistentProcesses" msgid="4896992079182649141">"Tillåter att appen begär att den angivna signalen skickas till alla beständiga processer."</string>
<string name="permlab_persistentActivity" msgid="8841113627955563938">"se till att appen alltid körs"</string>
@@ -1009,11 +1007,17 @@
<string name="wifi_p2p_enter_pin_message" msgid="5920929550367828970">"Ange den obligatoriska PIN-koden:"</string>
<string name="wifi_p2p_show_pin_message" msgid="8530563323880921094">"PIN-kod:"</string>
<string name="select_character" msgid="3365550120617701745">"Infoga tecken"</string>
- <string name="sms_control_default_app_name" msgid="3058577482636640465">"Okänd app"</string>
<string name="sms_control_title" msgid="7296612781128917719">"Skickar SMS"</string>
- <string name="sms_control_message" msgid="4073755190243093924">"Flera SMS skickas. Tryck på OK om du vill fortsätta eller på Avbryt om du vill avsluta sändningen."</string>
- <string name="sms_control_yes" msgid="2532062172402615953">"OK"</string>
- <string name="sms_control_no" msgid="1715320703137199869">"Avbryt"</string>
+ <string name="sms_control_message" msgid="3867899169651496433">"<b><xliff:g id="APP_NAME">%1$s</xliff:g></b> skickar ett stort antal SMS. Vill du tillåta att appen fortsätter att skicka meddelanden?"</string>
+ <string name="sms_control_yes" msgid="3663725993855816807">"Tillåt"</string>
+ <string name="sms_control_no" msgid="625438561395534982">"Neka"</string>
+ <string name="sms_short_code_confirm_title" msgid="1666863092640877318">"Skicka SMS till kortkod?"</string>
+ <string name="sms_premium_short_code_confirm_title" msgid="3811263856304367838">"Skicka premium-SMS?"</string>
+ <string name="sms_short_code_confirm_message" msgid="5616409294907295407">"<b><xliff:g id="APP_NAME">%1$s</xliff:g></b> vill skicka ett SMS till <b><xliff:g id="DEST_ADDRESS">%2$s</xliff:g></b> som verkar vara en kortkod för SMS.<p>När du skickar SMS till kortkoder kan mobilkontot debiteras för premiumtjänster.<p>Vill du tillåta att appen skickar meddelandet?"</string>
+ <string name="sms_premium_short_code_confirm_message" msgid="6214083016284738667">"<b><xliff:g id="APP_NAME">%1$s</xliff:g></b> vill skicka ett SMS till <b><xliff:g id="DEST_ADDRESS">%2$s</xliff:g></b> som är en kortkod för SMS.<p><b>Om du skickar ett meddelande till den här mottagaren kommer ditt mobilkonto att debiteras för premiumtjänster.</b><p>Vill du tillåta att appen skickar meddelandet?"</string>
+ <string name="sms_short_code_confirm_allow" msgid="8957573662645722940">"Skicka meddelande"</string>
+ <string name="sms_short_code_confirm_deny" msgid="6374609298084435887">"Skicka inte"</string>
+ <string name="sms_short_code_confirm_report" msgid="2588793956061677070">"Rapportera skadlig app"</string>
<string name="sim_removed_title" msgid="6227712319223226185">"SIM-kortet togs bort"</string>
<string name="sim_removed_message" msgid="2333164559970958645">"Det mobila nätverket kommer inte att vara tillgängligt förrän du startar om med ett giltigt SIM-kort."</string>
<string name="sim_done_button" msgid="827949989369963775">"Klar"</string>
@@ -1063,10 +1067,8 @@
<string name="adb_active_notification_message" msgid="1016654627626476142">"Tryck om du vill inaktivera USB-felsökning."</string>
<string name="select_input_method" msgid="4653387336791222978">"Välj inmatningsmetod"</string>
<string name="configure_input_methods" msgid="9091652157722495116">"Konfigurera inmatningsmetoder"</string>
- <!-- no translation found for use_physical_keyboard (6203112478095117625) -->
- <skip />
- <!-- no translation found for hardware (7517821086888990278) -->
- <skip />
+ <string name="use_physical_keyboard" msgid="6203112478095117625">"Fysiskt tangentbord"</string>
+ <string name="hardware" msgid="7517821086888990278">"Maskinvara"</string>
<string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="candidates_style" msgid="4333913089637062257"><u>"kandidater"</u></string>
diff --git a/core/res/res/values-sw/strings.xml b/core/res/res/values-sw/strings.xml
index 41345bd..5f9a8b1 100644
--- a/core/res/res/values-sw/strings.xml
+++ b/core/res/res/values-sw/strings.xml
@@ -286,10 +286,8 @@
<string name="permdesc_setOrientation" msgid="3046126619316671476">"Inaruhusu programu kubadilisha mzunguko wa skrini wakati wowote. Kamwe hazihitajiki kwa programu za kawaida."</string>
<string name="permlab_setPointerSpeed" msgid="9175371613322562934">"Badilisha kasi ya pointa"</string>
<string name="permdesc_setPointerSpeed" msgid="6866563234274104233">"Inaruhusu programu kubadilisha kasi ya kielekezi cha kipanya au pedi ya kufuatilia wakati wowote. Kamwe haitahitajika kwa programu za kawaida."</string>
- <!-- no translation found for permlab_setKeyboardLayout (4778731703600909340) -->
- <skip />
- <!-- no translation found for permdesc_setKeyboardLayout (8480016771134175879) -->
- <skip />
+ <string name="permlab_setKeyboardLayout" msgid="4778731703600909340">"badilisha mpangilio wa kibodi"</string>
+ <string name="permdesc_setKeyboardLayout" msgid="8480016771134175879">"Inaruhusu programu kubadilisha mpangilio wa kibodi. Haipaswi kamwe kuhitajika kwa programu za kawaida."</string>
<string name="permlab_signalPersistentProcesses" msgid="4539002991947376659">"Tuma ishara za Linux kwa programu"</string>
<string name="permdesc_signalPersistentProcesses" msgid="4896992079182649141">"Inaruhusu programu kuomba ishara iliyotolewa kutumwa kwa michakato inyoendelea."</string>
<string name="permlab_persistentActivity" msgid="8841113627955563938">"Fanya programu kuendeshwa kila mara"</string>
@@ -1009,11 +1007,17 @@
<string name="wifi_p2p_enter_pin_message" msgid="5920929550367828970">"Charaza PIN inayohitajika:"</string>
<string name="wifi_p2p_show_pin_message" msgid="8530563323880921094">"PIN:"</string>
<string name="select_character" msgid="3365550120617701745">"Ingiza kibambo"</string>
- <string name="sms_control_default_app_name" msgid="3058577482636640465">"Programu isiyojulikana"</string>
<string name="sms_control_title" msgid="7296612781128917719">"Inatuma ujumbe wa SMS"</string>
- <string name="sms_control_message" msgid="4073755190243093924">"Idadi kubwa ya jumbe za SMS inatumwa. Gusa SAWA kuendelea, au Ghairi kuwacha kutuma."</string>
- <string name="sms_control_yes" msgid="2532062172402615953">"Sawa"</string>
- <string name="sms_control_no" msgid="1715320703137199869">"Ghairi"</string>
+ <string name="sms_control_message" msgid="3867899169651496433">"<b><xliff:g id="APP_NAME">%1$s</xliff:g></b> inatuma idadi kubwa ya ujumbe wa SMS. Je, unataka kuruhusu programu hii kuendelea kutuma ujumbe?"</string>
+ <string name="sms_control_yes" msgid="3663725993855816807">"Ruhusu"</string>
+ <string name="sms_control_no" msgid="625438561395534982">"Kataa"</string>
+ <string name="sms_short_code_confirm_title" msgid="1666863092640877318">"Tuma ujumbe mfupi kwa msimbo mfupi?"</string>
+ <string name="sms_premium_short_code_confirm_title" msgid="3811263856304367838">"Tuma ujumbe mfupi wa ada?"</string>
+ <string name="sms_short_code_confirm_message" msgid="5616409294907295407">"<b><xliff:g id="APP_NAME">%1$s</xliff:g></b>ingependa kutuma ujumbe kwa <b>i<xliff:g id="DEST_ADDRESS">%2$s</xliff:g></b>, ambayo inaonekana kama msimbo mfupi wa ujumbe mfupi.<p>Kutuma ujumbe mfupi kwa baadhi ya misimbo mifupi kunaweza kusababisha akaunti yako ya simu kulipishwa huduma ya ada.<p>Je, unataka kuruhusu programu hii kutuma ujumbe?"</string>
+ <string name="sms_premium_short_code_confirm_message" msgid="6214083016284738667">"<b><xliff:g id="APP_NAME">%1$s</xliff:g></b> ingetaka kutuma ujumbe wa maandishi kwa <b><xliff:g id="DEST_ADDRESS">%2$s</xliff:g></b>, ambayo ni msimbo mfupi wa SMS ya ada.<p><b>Kutuma ujumbe kwa mwisho huu kutasababisha akaunti yako ya simu kulipishwa kwa huduma ya ada.</b><p>Je, unataka kuruhusu programu hii kutuma ujumbe?"</string>
+ <string name="sms_short_code_confirm_allow" msgid="8957573662645722940">"Tuma ujumbe"</string>
+ <string name="sms_short_code_confirm_deny" msgid="6374609298084435887">"Usitume"</string>
+ <string name="sms_short_code_confirm_report" msgid="2588793956061677070">"Ripoti programu mbaya"</string>
<string name="sim_removed_title" msgid="6227712319223226185">"Kadi ya SIM imeondolewa"</string>
<string name="sim_removed_message" msgid="2333164559970958645">"mtandao wa simu hutapatika hadi uanzishe upya na SIM kadi halali iliyoingizwa."</string>
<string name="sim_done_button" msgid="827949989369963775">"Kwisha"</string>
@@ -1063,10 +1067,8 @@
<string name="adb_active_notification_message" msgid="1016654627626476142">"Gusa ili kulemaza utatuaji wa USB."</string>
<string name="select_input_method" msgid="4653387336791222978">"Chagua njia ya ingizo"</string>
<string name="configure_input_methods" msgid="9091652157722495116">"Weka mbinu za ingizo"</string>
- <!-- no translation found for use_physical_keyboard (6203112478095117625) -->
- <skip />
- <!-- no translation found for hardware (7517821086888990278) -->
- <skip />
+ <string name="use_physical_keyboard" msgid="6203112478095117625">"Kibodi halisi"</string>
+ <string name="hardware" msgid="7517821086888990278">"Maunzi"</string>
<string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="candidates_style" msgid="4333913089637062257"><u>"wagombeaji"</u></string>
diff --git a/core/res/res/values-th/strings.xml b/core/res/res/values-th/strings.xml
index 3f479e5..0dd113f 100644
--- a/core/res/res/values-th/strings.xml
+++ b/core/res/res/values-th/strings.xml
@@ -286,10 +286,8 @@
<string name="permdesc_setOrientation" msgid="3046126619316671476">"อนุญาตให้แอปพลิเคชันเปลี่ยนการหมุนของหน้าจอได้ตลอดเวลา ไม่ควรต้องใช้สำหรับแอปพลิเคชันทั่วไป"</string>
<string name="permlab_setPointerSpeed" msgid="9175371613322562934">"เปลี่ยนความเร็วของตัวชี้"</string>
<string name="permdesc_setPointerSpeed" msgid="6866563234274104233">"อนุญาตให้แอปพลิเคชันเปลี่ยนความเร็วตัวชี้ของเมาส์หรือแทร็กแพดได้ทุกเมื่อ ไม่ควรต้องใช้สำหรับแอปพลิเคชันทั่วไป"</string>
- <!-- no translation found for permlab_setKeyboardLayout (4778731703600909340) -->
- <skip />
- <!-- no translation found for permdesc_setKeyboardLayout (8480016771134175879) -->
- <skip />
+ <string name="permlab_setKeyboardLayout" msgid="4778731703600909340">"เปลี่ยนการจัดวางแป้นพิมพ์"</string>
+ <string name="permdesc_setKeyboardLayout" msgid="8480016771134175879">"อนุญาตให้แอปพลิเคชันเปลี่ยนการจัดวางแป้นพิมพ์ ไม่ควรต้องใช้สำหรับแอปพลิเคชันทั่วไป"</string>
<string name="permlab_signalPersistentProcesses" msgid="4539002991947376659">"ส่งสัญญาณ Linux ไปยังแอปพลิเคชัน"</string>
<string name="permdesc_signalPersistentProcesses" msgid="4896992079182649141">"อนุญาตให้แอปพลิเคชันร้องขอให้ส่งสัญญาณแจ้งไปยังกระบวนการที่ยังทำงานอยู่ทั้งหมด"</string>
<string name="permlab_persistentActivity" msgid="8841113627955563938">"ทำให้แอปพลิเคชันทำงานเสมอ"</string>
@@ -1009,11 +1007,17 @@
<string name="wifi_p2p_enter_pin_message" msgid="5920929550367828970">"พิมพ์ PIN ที่ต้องการ:"</string>
<string name="wifi_p2p_show_pin_message" msgid="8530563323880921094">"PIN:"</string>
<string name="select_character" msgid="3365550120617701745">"ใส่อักขระ"</string>
- <string name="sms_control_default_app_name" msgid="3058577482636640465">"แอปพลิเคชันที่ไม่รู้จัก"</string>
<string name="sms_control_title" msgid="7296612781128917719">"กำลังส่งข้อความ SMS"</string>
- <string name="sms_control_message" msgid="4073755190243093924">"กำลังส่งข้อความ SMS จำนวนมาก แตะ \"ตกลง\" เพื่อทำงานต่อหรือ \"ยกเลิก\" เพื่อหยุดส่ง"</string>
- <string name="sms_control_yes" msgid="2532062172402615953">"ตกลง"</string>
- <string name="sms_control_no" msgid="1715320703137199869">"ยกเลิก"</string>
+ <string name="sms_control_message" msgid="3867899169651496433">"<b><xliff:g id="APP_NAME">%1$s</xliff:g></b> กำลังส่งข้อความ SMS จำนวนมาก คุณต้องการอนุญาตใ้ห้แอปพลิเคชันนี้ส่งข้อความต่อหรือไม่"</string>
+ <string name="sms_control_yes" msgid="3663725993855816807">"อนุญาต"</string>
+ <string name="sms_control_no" msgid="625438561395534982">"ปฏิเสธ"</string>
+ <string name="sms_short_code_confirm_title" msgid="1666863092640877318">"ส่ง SMS เป็นรหัสสั้นหรือไม่"</string>
+ <string name="sms_premium_short_code_confirm_title" msgid="3811263856304367838">"ส่ง SMS พรีเมียมหรือไม่"</string>
+ <string name="sms_short_code_confirm_message" msgid="5616409294907295407">"<b><xliff:g id="APP_NAME">%1$s</xliff:g></b> ต้องการส่งข้อความให้กับ <b><xliff:g id="DEST_ADDRESS">%2$s</xliff:g></b> ซึ่งเป็น SMS รหัสสั้น<p>การส่งข้อความเป็นรหัสสั้นบางอย่างอาจทำให้มีการเรียกเก็บเงินในบัญชีมือถือของคุณสำหรับบริการพรีเมียม<p>คุณต้องการอนุญาตให้แอปพลิเคชันนี้ส่งข้อความหรือไม่"</string>
+ <string name="sms_premium_short_code_confirm_message" msgid="6214083016284738667">"<b><xliff:g id="APP_NAME">%1$s</xliff:g></b> ต้องการส่งข้อความให้กับ <b><xliff:g id="DEST_ADDRESS">%2$s</xliff:g></b> ซึ่งเป็น SMS รหัสสั้นแบบพรีเมียม<p><b>การส่งข้อความไปยังปลายทางนี้จะทำให้มีการเรียกเก็บเงินในบัญชีมือถือของคุณสำหรับบริการพรีเมียม</b><p>คุณต้องการอนุญาตให้แอปพลิเคชันนี้ส่งข้อความหรือไม่"</string>
+ <string name="sms_short_code_confirm_allow" msgid="8957573662645722940">"ส่งข้อความ"</string>
+ <string name="sms_short_code_confirm_deny" msgid="6374609298084435887">"ไม่ส่ง"</string>
+ <string name="sms_short_code_confirm_report" msgid="2588793956061677070">"รายงานแอปที่เป็นอันตราย"</string>
<string name="sim_removed_title" msgid="6227712319223226185">"นำซิมการ์ดออกแล้ว"</string>
<string name="sim_removed_message" msgid="2333164559970958645">"เครือข่ายมือถือจะไม่สามารถใช้งานได้จนกว่าคุณจะรีสตาร์ทโดยใส่ซิมการ์ดที่ถูกต้องแล้ว"</string>
<string name="sim_done_button" msgid="827949989369963775">"เสร็จสิ้น"</string>
@@ -1063,10 +1067,8 @@
<string name="adb_active_notification_message" msgid="1016654627626476142">"แตะเพื่อปิดใช้งานการแก้ไขข้อบกพร่องของ USB"</string>
<string name="select_input_method" msgid="4653387336791222978">"เลือกวิธีการป้อนข้อมูล"</string>
<string name="configure_input_methods" msgid="9091652157722495116">"ตั้งค่าวิธีการป้อนข้อมูล"</string>
- <!-- no translation found for use_physical_keyboard (6203112478095117625) -->
- <skip />
- <!-- no translation found for hardware (7517821086888990278) -->
- <skip />
+ <string name="use_physical_keyboard" msgid="6203112478095117625">"แป้นพิมพ์บนเครื่อง"</string>
+ <string name="hardware" msgid="7517821086888990278">"ฮาร์ดแวร์"</string>
<string name="fast_scroll_alphabet" msgid="5433275485499039199">" กขฃคฅฆงจฉชซฌญฎฏฐฑฒณดตถทธนบปผฝพฟภมยรลวศษสหฬอฮ"</string>
<string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" กขฃคฅฆงจฉชซฌญฎฏฐฑฒณดตถทธนบปผฝพฟภมยรลวศษสหฬอฮ"</string>
<string name="candidates_style" msgid="4333913089637062257"><u>"ตัวเลือก"</u></string>
diff --git a/core/res/res/values-tl/strings.xml b/core/res/res/values-tl/strings.xml
index a5d3f08..f72709a 100644
--- a/core/res/res/values-tl/strings.xml
+++ b/core/res/res/values-tl/strings.xml
@@ -286,10 +286,8 @@
<string name="permdesc_setOrientation" msgid="3046126619316671476">"Pinapayagan ang app na baguhin ang pag-ikot ng screen anumang oras. Hindi kailanman dapat na kailanganin para sa normal na apps."</string>
<string name="permlab_setPointerSpeed" msgid="9175371613322562934">"baguhin ang bilis ng pointer"</string>
<string name="permdesc_setPointerSpeed" msgid="6866563234274104233">"Pinapayagan ang app na baguhin ang bilis ng mouse o trackpad pointer anumang oras. Hindi kailanman dapat na kailanganin para sa normal na apps."</string>
- <!-- no translation found for permlab_setKeyboardLayout (4778731703600909340) -->
- <skip />
- <!-- no translation found for permdesc_setKeyboardLayout (8480016771134175879) -->
- <skip />
+ <string name="permlab_setKeyboardLayout" msgid="4778731703600909340">"baguhin ang layout ng keyboard"</string>
+ <string name="permdesc_setKeyboardLayout" msgid="8480016771134175879">"Pinapayagan ang app na baguhin ang layout ng keyboard. Hindi kailanman dapat na kailanganin para sa mga normal na app."</string>
<string name="permlab_signalPersistentProcesses" msgid="4539002991947376659">"magpadala ng mga signal ng Linux sa apps"</string>
<string name="permdesc_signalPersistentProcesses" msgid="4896992079182649141">"Pinapayagan ang app na hilinging maipadala ang ibinigay na signal sa lahat ng nagpapatuloy na proseso."</string>
<string name="permlab_persistentActivity" msgid="8841113627955563938">"palaging patakbuhin ang app"</string>
@@ -1009,11 +1007,17 @@
<string name="wifi_p2p_enter_pin_message" msgid="5920929550367828970">"I-type ang kinakailangang PIN:"</string>
<string name="wifi_p2p_show_pin_message" msgid="8530563323880921094">"PIN:"</string>
<string name="select_character" msgid="3365550120617701745">"Magpasok ng character"</string>
- <string name="sms_control_default_app_name" msgid="3058577482636640465">"Hindi kilalang app"</string>
<string name="sms_control_title" msgid="7296612781128917719">"Nagpapadala ng mga SMS na mensahe"</string>
- <string name="sms_control_message" msgid="4073755190243093924">"Ipinapadala ang malaking bilang ng mga mensaheng SMS. Pindutin ang OK upang magpatuloy, o Kanselahin upang ihinto ang pagpapadala."</string>
- <string name="sms_control_yes" msgid="2532062172402615953">"OK"</string>
- <string name="sms_control_no" msgid="1715320703137199869">"Kanselahin"</string>
+ <string name="sms_control_message" msgid="3867899169651496433">"Ang <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> ay nagpapadala ng maraming mensaheng SMS. Gusto mo bang payagan ang app na ito na magpatuloy sa pagpapadala ng mga mensahe?"</string>
+ <string name="sms_control_yes" msgid="3663725993855816807">"Payagan"</string>
+ <string name="sms_control_no" msgid="625438561395534982">"Tanggihan"</string>
+ <string name="sms_short_code_confirm_title" msgid="1666863092640877318">"Magpadala SMS sa short code?"</string>
+ <string name="sms_premium_short_code_confirm_title" msgid="3811263856304367838">"Ipadala ang premium na SMS?"</string>
+ <string name="sms_short_code_confirm_message" msgid="5616409294907295407">"Ang <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> ay gustong magpadala ng text message sa <b><xliff:g id="DEST_ADDRESS">%2$s</xliff:g></b>, na lumilitaw na isang SMS na short code.<p>Ang pagpapadala ng mga text message sa ilang short code ay maaaring magdulot ng pagsingil sa iyong mobile account para sa mga premium na serbisyo.<p>Gusto mo bang payagan ang app na ito na ipadala ang mensahe?"</string>
+ <string name="sms_premium_short_code_confirm_message" msgid="6214083016284738667">"Ang <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> ay gustong magpadala ng text message sa <b><xliff:g id="DEST_ADDRESS">%2$s</xliff:g></b>, na isang premium na SMS na short code.<p><b>Ang pagpapadala ng mensahe sa patutunguhang ito ay magdudulot ng pagsingil sa iyong mobile account para sa mga premium na serbisyo.</b><p>Gusto mo bang payagan ang app na ito na ipadala ang mensahe?"</string>
+ <string name="sms_short_code_confirm_allow" msgid="8957573662645722940">"Ipadala ang mensahe"</string>
+ <string name="sms_short_code_confirm_deny" msgid="6374609298084435887">"Huwag ipadala"</string>
+ <string name="sms_short_code_confirm_report" msgid="2588793956061677070">"Mag-ulat ng nakakapahamak na app"</string>
<string name="sim_removed_title" msgid="6227712319223226185">"Naalis ang SIM card"</string>
<string name="sim_removed_message" msgid="2333164559970958645">"Hindi magiging available ang mobile network hanggang mag-restart ka gamit ang isang may-bisang SIM card"</string>
<string name="sim_done_button" msgid="827949989369963775">"Tapos na"</string>
@@ -1063,10 +1067,8 @@
<string name="adb_active_notification_message" msgid="1016654627626476142">"Pindutin upang huwag paganahin ang pag-debug ng USB."</string>
<string name="select_input_method" msgid="4653387336791222978">"Pumili ng pamamaraan ng pag-input"</string>
<string name="configure_input_methods" msgid="9091652157722495116">"I-set up paraan ng pag-input"</string>
- <!-- no translation found for use_physical_keyboard (6203112478095117625) -->
- <skip />
- <!-- no translation found for hardware (7517821086888990278) -->
- <skip />
+ <string name="use_physical_keyboard" msgid="6203112478095117625">"Aktwal na keyboard"</string>
+ <string name="hardware" msgid="7517821086888990278">"Hardware"</string>
<string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="candidates_style" msgid="4333913089637062257"><u>"mga kandidato"</u></string>
diff --git a/core/res/res/values-tr/strings.xml b/core/res/res/values-tr/strings.xml
index 86c1a70..cb99c5f 100644
--- a/core/res/res/values-tr/strings.xml
+++ b/core/res/res/values-tr/strings.xml
@@ -286,10 +286,8 @@
<string name="permdesc_setOrientation" msgid="3046126619316671476">"Uygulamaya, istediği zaman ekran dönüşünü değiştirme izni verir. Normal uygulamalar için gerekli değildir."</string>
<string name="permlab_setPointerSpeed" msgid="9175371613322562934">"işaretçi hızını değiştir"</string>
<string name="permdesc_setPointerSpeed" msgid="6866563234274104233">"Uygulamaya, istediği zaman fare veya izleme yüzeyi işaretçi hızını değiştirme izni verir. Normal uygulamalar için gerekli değildir."</string>
- <!-- no translation found for permlab_setKeyboardLayout (4778731703600909340) -->
- <skip />
- <!-- no translation found for permdesc_setKeyboardLayout (8480016771134175879) -->
- <skip />
+ <string name="permlab_setKeyboardLayout" msgid="4778731703600909340">"klavye düzenini değiştir"</string>
+ <string name="permdesc_setKeyboardLayout" msgid="8480016771134175879">"Uygulamaya klavye düzenini değiştirme izni verir. Normal uygulamalar için hiçbir zaman gerekmez."</string>
<string name="permlab_signalPersistentProcesses" msgid="4539002991947376659">"uygulamalara Linux sinyalleri gönder"</string>
<string name="permdesc_signalPersistentProcesses" msgid="4896992079182649141">"Uygulamaya, sağlanan sinyalin tüm kalıcı işlemlere gönderilmesini isteme izni verir."</string>
<string name="permlab_persistentActivity" msgid="8841113627955563938">"uygulamayı her zaman çalıştır"</string>
@@ -1009,11 +1007,17 @@
<string name="wifi_p2p_enter_pin_message" msgid="5920929550367828970">"Gerekli PIN\'i yazın:"</string>
<string name="wifi_p2p_show_pin_message" msgid="8530563323880921094">"PIN:"</string>
<string name="select_character" msgid="3365550120617701745">"Karakter ekle"</string>
- <string name="sms_control_default_app_name" msgid="3058577482636640465">"Bilinmeyen uygulama"</string>
<string name="sms_control_title" msgid="7296612781128917719">"SMS mesajları gönderiliyor"</string>
- <string name="sms_control_message" msgid="4073755190243093924">"Çok sayıda SMS mesajı gönderiliyor. Devam etmek için Tamam\'a, göndermeyi durdurmak için İptal\'e dokunun."</string>
- <string name="sms_control_yes" msgid="2532062172402615953">"Tamam"</string>
- <string name="sms_control_no" msgid="1715320703137199869">"İptal"</string>
+ <string name="sms_control_message" msgid="3867899169651496433">"<b><xliff:g id="APP_NAME">%1$s</xliff:g></b> çok sayıda SMS mesajı gönderiyor. Bu uygulamanın mesaj göndermeye devam etmesine izin veriyor musunuz?"</string>
+ <string name="sms_control_yes" msgid="3663725993855816807">"İzin ver"</string>
+ <string name="sms_control_no" msgid="625438561395534982">"Reddet"</string>
+ <string name="sms_short_code_confirm_title" msgid="1666863092640877318">"Kısa koda SMS gönderilsin mi?"</string>
+ <string name="sms_premium_short_code_confirm_title" msgid="3811263856304367838">"Premium SMS gönderilsin mi?"</string>
+ <string name="sms_short_code_confirm_message" msgid="5616409294907295407">"<b><xliff:g id="APP_NAME">%1$s</xliff:g></b>, SMS kısa koduna sahip olduğu anlaşılan <b><xliff:g id="DEST_ADDRESS">%2$s</xliff:g></b> hedefine bir kısa mesaj göndermek istiyor.<p>Bazı kısa kodlara kısa mesaj göndermek mobil hesabınızın premium hizmetle faturalandırılmasına neden olabilir.</b><p>Bu uygulamanın mesaj göndermesine izin vermek istiyor musunuz?"</string>
+ <string name="sms_premium_short_code_confirm_message" msgid="6214083016284738667">"<b><xliff:g id="APP_NAME">%1$s</xliff:g></b> premium SMS kısa koduna sahip <b><xliff:g id="DEST_ADDRESS">%2$s</xliff:g></b> hedefine kısa mesaj göndermek istiyor.<p><b>Bu hedefe mesaj göndermek mobil hesabınızın premium hizmetle faturalandırılmasına neden olur.</b><p>Bu uygulamanın mesaj göndermesine izin vermek istiyor musunuz?"</string>
+ <string name="sms_short_code_confirm_allow" msgid="8957573662645722940">"Mesajı gönder"</string>
+ <string name="sms_short_code_confirm_deny" msgid="6374609298084435887">"Gönderme"</string>
+ <string name="sms_short_code_confirm_report" msgid="2588793956061677070">"Kötü amaçlı uygulamayı bildir"</string>
<string name="sim_removed_title" msgid="6227712319223226185">"SIM kart çıkarıldı"</string>
<string name="sim_removed_message" msgid="2333164559970958645">"Geçerli bir SIM kart yerleştirilmiş olarak yeniden başlatana kadar mobil ağ kullanılamayacak."</string>
<string name="sim_done_button" msgid="827949989369963775">"Tamamlandı"</string>
@@ -1063,10 +1067,8 @@
<string name="adb_active_notification_message" msgid="1016654627626476142">"USB hata ayıklama özelliğini devre dışı bırakmak için dokunun."</string>
<string name="select_input_method" msgid="4653387336791222978">"Giriş yöntemini seçin"</string>
<string name="configure_input_methods" msgid="9091652157722495116">"Giriş yöntemlerini ayarla"</string>
- <!-- no translation found for use_physical_keyboard (6203112478095117625) -->
- <skip />
- <!-- no translation found for hardware (7517821086888990278) -->
- <skip />
+ <string name="use_physical_keyboard" msgid="6203112478095117625">"Fiziksel klavye"</string>
+ <string name="hardware" msgid="7517821086888990278">"Donanım"</string>
<string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="candidates_style" msgid="4333913089637062257"><u>"adaylar"</u></string>
diff --git a/core/res/res/values-uk/strings.xml b/core/res/res/values-uk/strings.xml
index 154468c..6731903 100644
--- a/core/res/res/values-uk/strings.xml
+++ b/core/res/res/values-uk/strings.xml
@@ -286,10 +286,8 @@
<string name="permdesc_setOrientation" msgid="3046126619316671476">"Дозволяє програмі будь-коли змінювати обертання екрана. Ніколи не застосовується для звичайних програм."</string>
<string name="permlab_setPointerSpeed" msgid="9175371613322562934">"змінювати швидкість указівника"</string>
<string name="permdesc_setPointerSpeed" msgid="6866563234274104233">"Дозволяє програмі будь-коли змінювати швидкість вказівника миші чи сенсорної панелі. Ніколи не застосовується для звичайних програм."</string>
- <!-- no translation found for permlab_setKeyboardLayout (4778731703600909340) -->
- <skip />
- <!-- no translation found for permdesc_setKeyboardLayout (8480016771134175879) -->
- <skip />
+ <string name="permlab_setKeyboardLayout" msgid="4778731703600909340">"змінити розкладку клавіатури"</string>
+ <string name="permdesc_setKeyboardLayout" msgid="8480016771134175879">"Дозволяє програмі змінювати розкладку клавіатури. Ніколи не застосовується для звичайних програм."</string>
<string name="permlab_signalPersistentProcesses" msgid="4539002991947376659">"надсилати сигнали Linux програмам"</string>
<string name="permdesc_signalPersistentProcesses" msgid="4896992079182649141">"Дозволяє програмі подавати запит щодо надсилання наданого сигналу всім сталим процесам."</string>
<string name="permlab_persistentActivity" msgid="8841113627955563938">"заставляти програму постійно функціонувати"</string>
@@ -1009,11 +1007,17 @@
<string name="wifi_p2p_enter_pin_message" msgid="5920929550367828970">"Введіть потрібний PIN-код:"</string>
<string name="wifi_p2p_show_pin_message" msgid="8530563323880921094">"PIN-код:"</string>
<string name="select_character" msgid="3365550120617701745">"Вставл-ня символу"</string>
- <string name="sms_control_default_app_name" msgid="3058577482636640465">"Невідома програма"</string>
<string name="sms_control_title" msgid="7296612781128917719">"Надсил. SMS повідомлень"</string>
- <string name="sms_control_message" msgid="4073755190243093924">"Надсилається велика кількість SMS повідомлень. Торкніться \"OK\", щоб продовжити, або \"Скасувати\", щоб припинити надсилання."</string>
- <string name="sms_control_yes" msgid="2532062172402615953">"OK"</string>
- <string name="sms_control_no" msgid="1715320703137199869">"Скасувати"</string>
+ <string name="sms_control_message" msgid="3867899169651496433">"Програма <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> надсилає велику кількість SMS-повідомлень. Дозволити цій програмі й надалі надсилати повідомлення?"</string>
+ <string name="sms_control_yes" msgid="3663725993855816807">"Дозволити"</string>
+ <string name="sms_control_no" msgid="625438561395534982">"Відмовити"</string>
+ <string name="sms_short_code_confirm_title" msgid="1666863092640877318">"Надіслати SMS на короткий код?"</string>
+ <string name="sms_premium_short_code_confirm_title" msgid="3811263856304367838">"Надіслати спеціальне SMS?"</string>
+ <string name="sms_short_code_confirm_message" msgid="5616409294907295407">"Програма <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> хоче надіслати текстове повідомлення на адресу <b><xliff:g id="DEST_ADDRESS">%2$s</xliff:g></b>, яка є коротким кодом SMS.<p><b>Якщо надсилати текстові повідомлення на певні короткі коди, з вашого мобільного рахунку буде стягнено плату за спеціальні послуги.</b><p>Дозволити цій програмі надіслати повідомлення?"</string>
+ <string name="sms_premium_short_code_confirm_message" msgid="6214083016284738667">"Програма <b><xliff:g id="APP_NAME">%1$s</xliff:g></b> хоче надіслати текстове повідомлення на адресу <b><xliff:g id="DEST_ADDRESS">%2$s</xliff:g></b>, яка є коротким кодом спеціальних SMS.<p><b>Якщо надіслати повідомлення на цю адресу, з вашого мобільного рахунку буде стягнено плату за спеціальні послуги.</b><p>Дозволити цій програмі надіслати повідомлення?"</string>
+ <string name="sms_short_code_confirm_allow" msgid="8957573662645722940">"Надіслати повідомлення"</string>
+ <string name="sms_short_code_confirm_deny" msgid="6374609298084435887">"Не надсилати"</string>
+ <string name="sms_short_code_confirm_report" msgid="2588793956061677070">"Повідом. про шкідливу програму"</string>
<string name="sim_removed_title" msgid="6227712319223226185">"SIM-карту вилучено"</string>
<string name="sim_removed_message" msgid="2333164559970958645">"Мобільна мережа буде недоступна, поки ви не здійсните перезапуск, вставивши дійсну SIM-карту."</string>
<string name="sim_done_button" msgid="827949989369963775">"Готово"</string>
@@ -1063,10 +1067,8 @@
<string name="adb_active_notification_message" msgid="1016654627626476142">"Торкніться, щоб вимкнути налагодження USB."</string>
<string name="select_input_method" msgid="4653387336791222978">"Вибрати метод введення"</string>
<string name="configure_input_methods" msgid="9091652157722495116">"Налаштувати методи введення"</string>
- <!-- no translation found for use_physical_keyboard (6203112478095117625) -->
- <skip />
- <!-- no translation found for hardware (7517821086888990278) -->
- <skip />
+ <string name="use_physical_keyboard" msgid="6203112478095117625">"Фізична клавіатура"</string>
+ <string name="hardware" msgid="7517821086888990278">"Обладнання"</string>
<string name="fast_scroll_alphabet" msgid="5433275485499039199">" АБВГҐДЕЄЖЗИІЇЙКЛМНОПРСТУФХЦЧШЩЬЮЯ"</string>
<string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789АБВГҐДЕЄЖЗИІЇЙКЛМНОПРСТУФХЦЧШЩЬЮЯ"</string>
<string name="candidates_style" msgid="4333913089637062257"><u>"кандидати"</u></string>
diff --git a/core/res/res/values-vi/strings.xml b/core/res/res/values-vi/strings.xml
index cbad241..c4d9470 100644
--- a/core/res/res/values-vi/strings.xml
+++ b/core/res/res/values-vi/strings.xml
@@ -286,10 +286,8 @@
<string name="permdesc_setOrientation" msgid="3046126619316671476">"Cho phép ứng dụng thay đổi độ xoay màn hình bất cứ lúc nào. Không cần thiết cho các ứng dụng thông thường."</string>
<string name="permlab_setPointerSpeed" msgid="9175371613322562934">"thay đổi tốc độ con trỏ"</string>
<string name="permdesc_setPointerSpeed" msgid="6866563234274104233">"Cho phép ứng dụng thay đổi tốc độ của chuột hoặc con trỏ trên ô di chuột bất kỳ lúc nào. Không cần thiết cho các ứng dụng thông thường."</string>
- <!-- no translation found for permlab_setKeyboardLayout (4778731703600909340) -->
- <skip />
- <!-- no translation found for permdesc_setKeyboardLayout (8480016771134175879) -->
- <skip />
+ <string name="permlab_setKeyboardLayout" msgid="4778731703600909340">"thay đổi bố cục bàn phím"</string>
+ <string name="permdesc_setKeyboardLayout" msgid="8480016771134175879">"Cho phép các ứng dụng thay đổi bố cục bàn phím. Không bao giờ cần thiết cho các ứng dụng bình thường."</string>
<string name="permlab_signalPersistentProcesses" msgid="4539002991947376659">"gửi tín hiệu Linux đến ứng dụng"</string>
<string name="permdesc_signalPersistentProcesses" msgid="4896992079182649141">"Cho phép ứng dụng yêu cầu tín hiệu đã cung cấp được gửi đến tất cả các quá trình liên tục."</string>
<string name="permlab_persistentActivity" msgid="8841113627955563938">"đặt ứng dụng luôn chạy"</string>
@@ -1009,11 +1007,17 @@
<string name="wifi_p2p_enter_pin_message" msgid="5920929550367828970">"Nhập PIN bắt buộc:"</string>
<string name="wifi_p2p_show_pin_message" msgid="8530563323880921094">"Mã PIN:"</string>
<string name="select_character" msgid="3365550120617701745">"Chèn ký tự"</string>
- <string name="sms_control_default_app_name" msgid="3058577482636640465">"Ứng dụng không xác định"</string>
<string name="sms_control_title" msgid="7296612781128917719">"Đang gửi tin nhắn SMS"</string>
- <string name="sms_control_message" msgid="4073755190243093924">"Một lượng lớn các tin nhắn SMS đang được gửi. Chạm OK để tiếp tục hoặc Hủy để ngừng gửi."</string>
- <string name="sms_control_yes" msgid="2532062172402615953">"OK"</string>
- <string name="sms_control_no" msgid="1715320703137199869">"Hủy"</string>
+ <string name="sms_control_message" msgid="3867899169651496433">"<b><xliff:g id="APP_NAME">%1$s</xliff:g></b> đang gửi rất nhiều tin nhắn SMS. Bạn có muốn cho phép ứng dụng này tiếp tục gửi tin nhắn không?"</string>
+ <string name="sms_control_yes" msgid="3663725993855816807">"Cho phép"</string>
+ <string name="sms_control_no" msgid="625438561395534982">"Từ chối"</string>
+ <string name="sms_short_code_confirm_title" msgid="1666863092640877318">"Gửi SMS cho mã ngắn?"</string>
+ <string name="sms_premium_short_code_confirm_title" msgid="3811263856304367838">"Gửi tin nhắn SMS trả phí?"</string>
+ <string name="sms_short_code_confirm_message" msgid="5616409294907295407">"<b><xliff:g id="APP_NAME">%1$s</xliff:g></b> muốn gửi tin nhắn văn bản cho <b><xliff:g id="DEST_ADDRESS">%2$s</xliff:g></b>, dường như là một mã ngắn SMS.<p>Việc gửi tin nhắn văn bản cho một số mã ngắn có thể khiến cho tài khoản di động của bạn bị lập hóa đơn cho dịch vụ trả phí.<p>Bạn có muốn cho phép ứng dụng này gửi tin nhắn không?"</string>
+ <string name="sms_premium_short_code_confirm_message" msgid="6214083016284738667">"<b><xliff:g id="APP_NAME">%1$s</xliff:g></b> muốn gửi tin nhắn văn bản cho <b><xliff:g id="DEST_ADDRESS">%2$s</xliff:g></b>, là một mã ngắn SMS trả phí.<p><b>Gửi tin nhắn tới địa chỉ này sẽ khiến cho tài khoản di động của bạn bị lập hóa đơn cho dịch vụ trả phí.</b><p>Bạn có muốn cho phép ứng dụng này gửi tin nhắn không?"</string>
+ <string name="sms_short_code_confirm_allow" msgid="8957573662645722940">"Gửi tin nhắn"</string>
+ <string name="sms_short_code_confirm_deny" msgid="6374609298084435887">"Không gửi"</string>
+ <string name="sms_short_code_confirm_report" msgid="2588793956061677070">"Báo cáo ứng dụng độc hại"</string>
<string name="sim_removed_title" msgid="6227712319223226185">"Đã xóa thẻ SIM"</string>
<string name="sim_removed_message" msgid="2333164559970958645">"Mạng di động sẽ không khả dụng cho đến khi bạn khởi động lại với thẻ SIM hợp lệ được lắp."</string>
<string name="sim_done_button" msgid="827949989369963775">"Xong"</string>
@@ -1063,10 +1067,8 @@
<string name="adb_active_notification_message" msgid="1016654627626476142">"Chạm để vô hiệu hóa gỡ lỗi USB."</string>
<string name="select_input_method" msgid="4653387336791222978">"Chọn phương thức nhập"</string>
<string name="configure_input_methods" msgid="9091652157722495116">"Thiết lập phương thức nhập"</string>
- <!-- no translation found for use_physical_keyboard (6203112478095117625) -->
- <skip />
- <!-- no translation found for hardware (7517821086888990278) -->
- <skip />
+ <string name="use_physical_keyboard" msgid="6203112478095117625">"Bàn phím thực"</string>
+ <string name="hardware" msgid="7517821086888990278">"Phần cứng"</string>
<string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="candidates_style" msgid="4333913089637062257"><u>"ứng viên"</u></string>
diff --git a/core/res/res/values-zh-rCN/strings.xml b/core/res/res/values-zh-rCN/strings.xml
index cb612e1..c0c30ff 100644
--- a/core/res/res/values-zh-rCN/strings.xml
+++ b/core/res/res/values-zh-rCN/strings.xml
@@ -286,10 +286,8 @@
<string name="permdesc_setOrientation" msgid="3046126619316671476">"允许应用随时更改屏幕的旋转状态。普通应用绝不需要此权限。"</string>
<string name="permlab_setPointerSpeed" msgid="9175371613322562934">"更改指针速度"</string>
<string name="permdesc_setPointerSpeed" msgid="6866563234274104233">"允许应用随时更改鼠标或触控板指针速度。普通应用绝不需要此权限。"</string>
- <!-- no translation found for permlab_setKeyboardLayout (4778731703600909340) -->
- <skip />
- <!-- no translation found for permdesc_setKeyboardLayout (8480016771134175879) -->
- <skip />
+ <string name="permlab_setKeyboardLayout" msgid="4778731703600909340">"更改键盘布局"</string>
+ <string name="permdesc_setKeyboardLayout" msgid="8480016771134175879">"允许应用更改键盘布局。普通应用绝不需要此权限。"</string>
<string name="permlab_signalPersistentProcesses" msgid="4539002991947376659">"向应用发送 Linux 信号"</string>
<string name="permdesc_signalPersistentProcesses" msgid="4896992079182649141">"允许应用请求将提供的信号发送给所有持续的进程。"</string>
<string name="permlab_persistentActivity" msgid="8841113627955563938">"让应用始终运行"</string>
@@ -1009,11 +1007,17 @@
<string name="wifi_p2p_enter_pin_message" msgid="5920929550367828970">"键入所需的 PIN:"</string>
<string name="wifi_p2p_show_pin_message" msgid="8530563323880921094">"PIN:"</string>
<string name="select_character" msgid="3365550120617701745">"插入字符"</string>
- <string name="sms_control_default_app_name" msgid="3058577482636640465">"未知应用"</string>
<string name="sms_control_title" msgid="7296612781128917719">"正在发送短信"</string>
- <string name="sms_control_message" msgid="4073755190243093924">"正在发送大量短信。触摸“确定”继续,或触摸“取消”停止发送。"</string>
- <string name="sms_control_yes" msgid="2532062172402615953">"确定"</string>
- <string name="sms_control_no" msgid="1715320703137199869">"取消"</string>
+ <string name="sms_control_message" msgid="3867899169651496433">"<b><xliff:g id="APP_NAME">%1$s</xliff:g></b>在发送大量短信。是否允许该应用继续发送短信?"</string>
+ <string name="sms_control_yes" msgid="3663725993855816807">"允许"</string>
+ <string name="sms_control_no" msgid="625438561395534982">"拒绝"</string>
+ <string name="sms_short_code_confirm_title" msgid="1666863092640877318">"向短码发送短信吗?"</string>
+ <string name="sms_premium_short_code_confirm_title" msgid="3811263856304367838">"发送付费短信吗?"</string>
+ <string name="sms_short_code_confirm_message" msgid="5616409294907295407">"<b><xliff:g id="APP_NAME">%1$s</xliff:g></b>想要向 <b><xliff:g id="DEST_ADDRESS">%2$s</xliff:g></b>(这似乎是一个短信短码)发送短信。<p>向某些短码发送短信可能会导致您的移动帐户因使用付费服务而扣费。<p>是否允许该应用发送短信?"</string>
+ <string name="sms_premium_short_code_confirm_message" msgid="6214083016284738667">"<b><xliff:g id="APP_NAME">%1$s</xliff:g></b>想要向 <b><xliff:g id="DEST_ADDRESS">%2$s</xliff:g></b>(这是一个付费短信短码)发送短信。<p><b>向该地址发送短信会导致您的移动帐户因使用付费服务而扣费</b>。<p>是否允许该应用发送短信?"</string>
+ <string name="sms_short_code_confirm_allow" msgid="8957573662645722940">"发送短信"</string>
+ <string name="sms_short_code_confirm_deny" msgid="6374609298084435887">"不发送"</string>
+ <string name="sms_short_code_confirm_report" msgid="2588793956061677070">"举报恶意应用"</string>
<string name="sim_removed_title" msgid="6227712319223226185">"已移除 SIM 卡"</string>
<string name="sim_removed_message" msgid="2333164559970958645">"移动网络不可用。请插入有效的 SIM 卡并重新启动。"</string>
<string name="sim_done_button" msgid="827949989369963775">"完成"</string>
@@ -1063,10 +1067,8 @@
<string name="adb_active_notification_message" msgid="1016654627626476142">"触摸以停用 USB 调试。"</string>
<string name="select_input_method" msgid="4653387336791222978">"选择输入法"</string>
<string name="configure_input_methods" msgid="9091652157722495116">"设置输入法"</string>
- <!-- no translation found for use_physical_keyboard (6203112478095117625) -->
- <skip />
- <!-- no translation found for hardware (7517821086888990278) -->
- <skip />
+ <string name="use_physical_keyboard" msgid="6203112478095117625">"物理键盘"</string>
+ <string name="hardware" msgid="7517821086888990278">"硬件"</string>
<string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="candidates_style" msgid="4333913089637062257"><u>"候选"</u></string>
diff --git a/core/res/res/values-zh-rTW/strings.xml b/core/res/res/values-zh-rTW/strings.xml
index c2ae68e..1e08a95 100644
--- a/core/res/res/values-zh-rTW/strings.xml
+++ b/core/res/res/values-zh-rTW/strings.xml
@@ -286,10 +286,8 @@
<string name="permdesc_setOrientation" msgid="3046126619316671476">"允許應用程式隨時變更螢幕旋轉狀態 (一般應用程式不需使用)。"</string>
<string name="permlab_setPointerSpeed" msgid="9175371613322562934">"變更指標速度"</string>
<string name="permdesc_setPointerSpeed" msgid="6866563234274104233">"允許應用程式隨時變更滑鼠或觸控板游標的移動速度 (一般應用程式不需使用)。"</string>
- <!-- no translation found for permlab_setKeyboardLayout (4778731703600909340) -->
- <skip />
- <!-- no translation found for permdesc_setKeyboardLayout (8480016771134175879) -->
- <skip />
+ <string name="permlab_setKeyboardLayout" msgid="4778731703600909340">"變更鍵盤配置"</string>
+ <string name="permdesc_setKeyboardLayout" msgid="8480016771134175879">"允許應用程式變更鍵盤配置 (一般應用程式不需使用)。"</string>
<string name="permlab_signalPersistentProcesses" msgid="4539002991947376659">"將 Linux 訊號傳送給應用程式"</string>
<string name="permdesc_signalPersistentProcesses" msgid="4896992079182649141">"允許應用程式要求將提供的訊號傳送給所有持續運作中的處理程序。"</string>
<string name="permlab_persistentActivity" msgid="8841113627955563938">"一律執行應用程式"</string>
@@ -1009,11 +1007,17 @@
<string name="wifi_p2p_enter_pin_message" msgid="5920929550367828970">"請輸入必要的 PIN:"</string>
<string name="wifi_p2p_show_pin_message" msgid="8530563323880921094">"PIN:"</string>
<string name="select_character" msgid="3365550120617701745">"插入字元"</string>
- <string name="sms_control_default_app_name" msgid="3058577482636640465">"不明的應用程式"</string>
<string name="sms_control_title" msgid="7296612781128917719">"傳送 SMS 簡訊"</string>
- <string name="sms_control_message" msgid="4073755190243093924">"即將傳送大量的 SMS 簡訊。輕觸 [確定] 可繼續傳送,或輕觸 [取消] 停止傳送。"</string>
- <string name="sms_control_yes" msgid="2532062172402615953">"確定"</string>
- <string name="sms_control_no" msgid="1715320703137199869">"取消"</string>
+ <string name="sms_control_message" msgid="3867899169651496433">"<b></b>「<xliff:g id="APP_NAME">%1$s</xliff:g>」正在傳送大量簡訊。您要允許這個應用程式繼續傳送簡訊嗎?"</string>
+ <string name="sms_control_yes" msgid="3663725993855816807">"允許"</string>
+ <string name="sms_control_no" msgid="625438561395534982">"拒絕"</string>
+ <string name="sms_short_code_confirm_title" msgid="1666863092640877318">"傳送簡訊給短碼?"</string>
+ <string name="sms_premium_short_code_confirm_title" msgid="3811263856304367838">"傳送付費簡訊?"</string>
+ <string name="sms_short_code_confirm_message" msgid="5616409294907295407">"<b></b>「<xliff:g id="APP_NAME">%1$s</xliff:g>」想要傳送簡訊給簡訊短碼 <b><xliff:g id="DEST_ADDRESS">%2$s</xliff:g></b>。<p>傳送簡訊給簡訊短碼之後,系統即會從您的行動帳戶扣除付費服務的費用。<p>您要允許這個應用程式傳送簡訊嗎?"</string>
+ <string name="sms_premium_short_code_confirm_message" msgid="6214083016284738667">"<b></b>「<xliff:g id="APP_NAME">%1$s</xliff:g>」想要傳送簡訊給付費簡訊短碼 <b><xliff:g id="DEST_ADDRESS">%2$s</xliff:g></b>。<p><b>傳送簡訊給這個對象之後,系統即會從您的行動帳戶扣除付費服務的費用。</b><p>您要允許這個應用程式傳送簡訊嗎?"</string>
+ <string name="sms_short_code_confirm_allow" msgid="8957573662645722940">"傳送簡訊"</string>
+ <string name="sms_short_code_confirm_deny" msgid="6374609298084435887">"不要傳送"</string>
+ <string name="sms_short_code_confirm_report" msgid="2588793956061677070">"檢舉惡意應用程式"</string>
<string name="sim_removed_title" msgid="6227712319223226185">"SIM 卡已移除"</string>
<string name="sim_removed_message" msgid="2333164559970958645">"您必須先插入有效的 SIM 卡再重新啟動手機,才能使用行動網路。"</string>
<string name="sim_done_button" msgid="827949989369963775">"完成"</string>
@@ -1063,10 +1067,8 @@
<string name="adb_active_notification_message" msgid="1016654627626476142">"輕觸即可停用 USB 偵錯。"</string>
<string name="select_input_method" msgid="4653387336791222978">"選擇輸入法"</string>
<string name="configure_input_methods" msgid="9091652157722495116">"設定輸入法"</string>
- <!-- no translation found for use_physical_keyboard (6203112478095117625) -->
- <skip />
- <!-- no translation found for hardware (7517821086888990278) -->
- <skip />
+ <string name="use_physical_keyboard" msgid="6203112478095117625">"實體鍵盤"</string>
+ <string name="hardware" msgid="7517821086888990278">"硬體"</string>
<string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="candidates_style" msgid="4333913089637062257"><u>"待選項目"</u></string>
diff --git a/core/res/res/values-zu/strings.xml b/core/res/res/values-zu/strings.xml
index eea53ec..114d45b 100644
--- a/core/res/res/values-zu/strings.xml
+++ b/core/res/res/values-zu/strings.xml
@@ -286,10 +286,8 @@
<string name="permdesc_setOrientation" msgid="3046126619316671476">"Ivumela insiza ukuthi iguqule ukujikeleza kweskrini nganoma isiphi isikhathi. Akudingakeli izinsiza ezejwayelekile."</string>
<string name="permlab_setPointerSpeed" msgid="9175371613322562934">"guqula isivinini sesikhombi"</string>
<string name="permdesc_setPointerSpeed" msgid="6866563234274104233">"Ivumela insiza ukuthi iguqule ijubane legundane noma lendawo yokukhomba ngomunwe. Akufanele kudingakele izinsiza ezijwayelekile."</string>
- <!-- no translation found for permlab_setKeyboardLayout (4778731703600909340) -->
- <skip />
- <!-- no translation found for permdesc_setKeyboardLayout (8480016771134175879) -->
- <skip />
+ <string name="permlab_setKeyboardLayout" msgid="4778731703600909340">"shintsha isendlalelo sekhibhodi"</string>
+ <string name="permdesc_setKeyboardLayout" msgid="8480016771134175879">"Ivumela uhlelo lokusebenza ukushintsha isendlalelo sekhibhodi. Kufanele ingadingi izinhlelo zokusebenza ezivamile."</string>
<string name="permlab_signalPersistentProcesses" msgid="4539002991947376659">"Thumela imifanekiso ye-Linu ezinsizeni"</string>
<string name="permdesc_signalPersistentProcesses" msgid="4896992079182649141">"Ivumela insiza ukuthi icele ukuthi isiginali ethunyelwe idluliselwe kuzo zonke izinqubeko ezisalelayo."</string>
<string name="permlab_persistentActivity" msgid="8841113627955563938">"yenza insiza ukuthi ihlale isebenza"</string>
@@ -1009,11 +1007,17 @@
<string name="wifi_p2p_enter_pin_message" msgid="5920929550367828970">"Faka i-PIN edingekayo:"</string>
<string name="wifi_p2p_show_pin_message" msgid="8530563323880921094">"PIN:"</string>
<string name="select_character" msgid="3365550120617701745">"Faka uhlamvu"</string>
- <string name="sms_control_default_app_name" msgid="3058577482636640465">"insiza engaziwa"</string>
<string name="sms_control_title" msgid="7296612781128917719">"Ithumela imiyalezo ye-SMS"</string>
- <string name="sms_control_message" msgid="4073755190243093924">"Inani eliphezulu lwama-SMS liyathunyelwa. Khetha \"KULUNGILE\" ukuqhubeka, noma \"Khansela\" ukumisa ukuthumela."</string>
- <string name="sms_control_yes" msgid="2532062172402615953">"KULUNGILE"</string>
- <string name="sms_control_no" msgid="1715320703137199869">"Khansela"</string>
+ <string name="sms_control_message" msgid="3867899169651496433">"I-<b><xliff:g id="APP_NAME">%1$s</xliff:g></b> ithumela inombolo enkulu yemilayezo ye-SMS. Ufuna ukuvumela lolu hlelo lokusebenza ukuqhubeka ukuthumela imilayezo?"</string>
+ <string name="sms_control_yes" msgid="3663725993855816807">"Vumela"</string>
+ <string name="sms_control_no" msgid="625438561395534982">"Nqaba"</string>
+ <string name="sms_short_code_confirm_title" msgid="1666863092640877318">"Thumela i-SMS kukhodi emfushane?"</string>
+ <string name="sms_premium_short_code_confirm_title" msgid="3811263856304367838">"Ukuthumela i-SMS ye-premium?"</string>
+ <string name="sms_short_code_confirm_message" msgid="5616409294907295407">"I-<b><xliff:g id="APP_NAME">%1$s</xliff:g></b> ithanda ukuthumela umlayezo wombhalo ku-<b><xliff:g id="DEST_ADDRESS">%2$s</xliff:g></b>, okubonakala sengathi ikhodi ye-SMS emfushane.<p>Ukuthumela umlayezo wombhalo kungabangela i-akhawunti yeselula yakho ukuthi ikhokheliswe amasevisi e-premium.<p>Ufuna ukuvumela uhlelo lokusebenza ukuthumela umlayezo?"</string>
+ <string name="sms_premium_short_code_confirm_message" msgid="6214083016284738667">"I-<b><xliff:g id="APP_NAME">%1$s</xliff:g></b> ithanda ukuthumela umlayezo wombhalo ku-<b><xliff:g id="DEST_ADDRESS">%2$s</xliff:g></b>, okuyikhodi emfushane ye-SMS ye-premium.<p><b>Ukuthumela umlayezo kule ndawo kuzobangela i-akhawunti yeselula yakho ukuthi ikhokheliswe amasevisi e-premium.</b><p>Ufuna ukuvumela lolu hlelo lokusebenza ukuthumela umlayezo?"</string>
+ <string name="sms_short_code_confirm_allow" msgid="8957573662645722940">"Thumela umlayezo"</string>
+ <string name="sms_short_code_confirm_deny" msgid="6374609298084435887">"Ungathumeli"</string>
+ <string name="sms_short_code_confirm_report" msgid="2588793956061677070">"Bika uhlelo lokusebenza olungalungile"</string>
<string name="sim_removed_title" msgid="6227712319223226185">"Ikhadi le-SIM likhishiwe"</string>
<string name="sim_removed_message" msgid="2333164559970958645">"Inethiwekhi yeselula ngeke itholakale kuwena kuze kube uqala kabusha ufake ikhadi le-SIM elifanele."</string>
<string name="sim_done_button" msgid="827949989369963775">"Kwenziwe"</string>
@@ -1063,10 +1067,8 @@
<string name="adb_active_notification_message" msgid="1016654627626476142">"Thinta ukwenza ukuthi ukudibhaga kwe-USB kungasebenzi."</string>
<string name="select_input_method" msgid="4653387336791222978">"Khetha indlela yokufaka"</string>
<string name="configure_input_methods" msgid="9091652157722495116">"Izilungiselelo zezindlela zokufakwayo"</string>
- <!-- no translation found for use_physical_keyboard (6203112478095117625) -->
- <skip />
- <!-- no translation found for hardware (7517821086888990278) -->
- <skip />
+ <string name="use_physical_keyboard" msgid="6203112478095117625">"Ukwakheka kwekhibhodi"</string>
+ <string name="hardware" msgid="7517821086888990278">"I-Hardware"</string>
<string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="candidates_style" msgid="4333913089637062257"><u>"abahlanganyeli"</u></string>
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index de24d10..6f489d4 100755
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -2367,8 +2367,6 @@
<!-- Component name of an activity that allows the user to modify
the settings for this service. -->
<attr name="settingsActivity"/>
- <!-- Set true when the spell checker supports sentence level spell checking. -->
- <attr name="supportsSentenceSpellCheck" format="boolean" />
</declare-styleable>
<!-- This is the subtype of the spell checker. Subtype can describe locales (e.g. en_US, fr_FR...) -->
@@ -5382,6 +5380,21 @@
</declare-styleable>
<!-- =============================== -->
+ <!-- SizeAdaptiveLayout class attributes -->
+ <!-- =============================== -->
+ <eat-comment />
+ <declare-styleable name="SizeAdaptiveLayout_Layout">
+ <!-- The maximum valid height for this item. -->
+ <attr name="layout_maxHeight" format="dimension">
+ <!-- Indicates that the view may be resized arbitrarily large. -->
+ <enum name="unbounded" value="-1" />
+ </attr>
+ <!-- The minimum valid height for this item. -->
+ <attr name="layout_minHeight" format="dimension" />
+ </declare-styleable>
+ <declare-styleable name="SizeAdaptiveLayout" />
+
+ <!-- =============================== -->
<!-- LockPatternView class attributes -->
<!-- =============================== -->
<eat-comment />
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index 4a5e442..b564b97 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -205,6 +205,11 @@
<java-symbol type="id" name="big_picture" />
<java-symbol type="id" name="big_text" />
<java-symbol type="id" name="chronometer" />
+ <java-symbol type="id" name="inbox_text0" />
+ <java-symbol type="id" name="inbox_text1" />
+ <java-symbol type="id" name="inbox_text2" />
+ <java-symbol type="id" name="inbox_text3" />
+ <java-symbol type="id" name="inbox_text4" />
<java-symbol type="attr" name="actionModeShareDrawable" />
<java-symbol type="attr" name="alertDialogCenterButtons" />
@@ -1083,8 +1088,10 @@
<java-symbol type="layout" name="notification_intruder_content" />
<java-symbol type="layout" name="notification_template_base" />
<java-symbol type="layout" name="notification_template_big_picture" />
+ <java-symbol type="layout" name="notification_template_big_text" />
<java-symbol type="layout" name="notification_template_part_time" />
<java-symbol type="layout" name="notification_template_part_chronometer" />
+ <java-symbol type="layout" name="notification_template_inbox" />
<java-symbol type="anim" name="slide_in_child_bottom" />
<java-symbol type="anim" name="slide_in_right" />
@@ -3588,8 +3595,6 @@
<public type="attr" name="parentActivityName" />
- <public type="attr" name="supportsSentenceSpellCheck" />
-
<public type="attr" name="importantForAccessibility"/>
</resources>
diff --git a/core/tests/coretests/apks/install/Android.mk b/core/tests/coretests/apks/install/Android.mk
new file mode 100644
index 0000000..b38dc20
--- /dev/null
+++ b/core/tests/coretests/apks/install/Android.mk
@@ -0,0 +1,8 @@
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := $(call all-subdir-java-files)
+
+LOCAL_PACKAGE_NAME := install
+
+include $(FrameworkCoreTests_BUILD_PACKAGE)
diff --git a/core/tests/coretests/apks/install/AndroidManifest.xml b/core/tests/coretests/apks/install/AndroidManifest.xml
new file mode 100644
index 0000000..60f1ba0
--- /dev/null
+++ b/core/tests/coretests/apks/install/AndroidManifest.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2010 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.
+-->
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.frameworks.coretests.install_loc">
+
+ <application android:hasCode="false">
+ </application>
+</manifest>
diff --git a/core/tests/coretests/apks/install/res/values/strings.xml b/core/tests/coretests/apks/install/res/values/strings.xml
new file mode 100644
index 0000000..3b8b3b1
--- /dev/null
+++ b/core/tests/coretests/apks/install/res/values/strings.xml
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<!-- Just need this dummy file to have something to build. -->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="dummy">dummy</string>
+</resources>
diff --git a/core/tests/coretests/res/drawable/abe.jpg b/core/tests/coretests/res/drawable/abe.jpg
new file mode 100644
index 0000000..1f978a9
--- /dev/null
+++ b/core/tests/coretests/res/drawable/abe.jpg
Binary files differ
diff --git a/core/tests/coretests/res/drawable/gettysburg.png b/core/tests/coretests/res/drawable/gettysburg.png
new file mode 100644
index 0000000..7a2d596
--- /dev/null
+++ b/core/tests/coretests/res/drawable/gettysburg.png
Binary files differ
diff --git a/core/tests/coretests/res/layout/size_adaptive.xml b/core/tests/coretests/res/layout/size_adaptive.xml
new file mode 100644
index 0000000..03d0574
--- /dev/null
+++ b/core/tests/coretests/res/layout/size_adaptive.xml
@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2012 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.
+-->
+<com.android.internal.widget.SizeAdaptiveLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:internal="http://schemas.android.com/apk/prv/res/android"
+ android:id="@+id/multi1"
+ android:layout_width="match_parent"
+ android:layout_height="64dp" >
+
+ <include
+ android:id="@+id/one_u"
+ layout="@layout/size_adaptive_one_u"
+ android:layout_width="fill_parent"
+ android:layout_height="64dp"
+ internal:layout_minHeight="64dp"
+ internal:layout_maxHeight="64dp"
+ />
+
+ <include
+ android:id="@+id/four_u"
+ layout="@layout/size_adaptive_four_u"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ internal:layout_minHeight="65dp"
+ internal:layout_maxHeight="unbounded"/>
+
+</com.android.internal.widget.SizeAdaptiveLayout>
diff --git a/core/tests/coretests/res/layout/size_adaptive_color.xml b/core/tests/coretests/res/layout/size_adaptive_color.xml
new file mode 100644
index 0000000..cdb7a59
--- /dev/null
+++ b/core/tests/coretests/res/layout/size_adaptive_color.xml
@@ -0,0 +1,41 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2012 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.
+-->
+<com.android.internal.widget.SizeAdaptiveLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:internal="http://schemas.android.com/apk/prv/res/android"
+ android:background="#ffffff"
+ android:id="@+id/multi1"
+ android:layout_width="match_parent"
+ android:layout_height="64dp" >
+
+ <include
+ android:id="@+id/one_u"
+ layout="@layout/size_adaptive_one_u"
+ android:layout_width="fill_parent"
+ android:layout_height="64dp"
+ internal:layout_minHeight="64dp"
+ internal:layout_maxHeight="64dp"
+ />
+
+ <include
+ android:id="@+id/four_u"
+ layout="@layout/size_adaptive_four_u"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ internal:layout_minHeight="65dp"
+ internal:layout_maxHeight="unbounded"/>
+
+</com.android.internal.widget.SizeAdaptiveLayout>
diff --git a/core/tests/coretests/res/layout/size_adaptive_four_u.xml b/core/tests/coretests/res/layout/size_adaptive_four_u.xml
new file mode 100644
index 0000000..232b921
--- /dev/null
+++ b/core/tests/coretests/res/layout/size_adaptive_four_u.xml
@@ -0,0 +1,68 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2012 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.
+-->
+<GridLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/gridLayout4"
+ android:layout_width="match_parent"
+ android:layout_height="256dp"
+ android:background="#000000"
+ android:columnCount="2"
+ android:padding="1dp" >
+
+ <ImageView
+ android:id="@+id/actor"
+ android:layout_width="62dp"
+ android:layout_height="62dp"
+ android:layout_row="0"
+ android:layout_column="0"
+ android:layout_rowSpan="2"
+ android:contentDescription="@string/actor"
+ android:src="@drawable/abe" />
+
+ <TextView
+ android:layout_width="0dp"
+ android:id="@+id/name"
+ android:layout_row="0"
+ android:layout_column="1"
+ android:layout_gravity="fill_horizontal"
+ android:padding="3dp"
+ android:text="@string/actor"
+ android:textColor="#ffffff"
+ android:textStyle="bold" />
+
+ <ImageView
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_row="1"
+ android:layout_column="1"
+ android:layout_gravity="fill_horizontal"
+ android:padding="5dp"
+ android:adjustViewBounds="true"
+ android:background="#555555"
+ android:scaleType="centerCrop"
+ android:src="@drawable/gettysburg"
+ android:contentDescription="@string/caption" />
+
+ <TextView
+ android:layout_width="0dp"
+ android:id="@+id/note"
+ android:layout_row="2"
+ android:layout_column="1"
+ android:layout_gravity="fill_horizontal"
+ android:padding="3dp"
+ android:singleLine="true"
+ android:text="@string/first"
+ android:textColor="#ffffff" />
+</GridLayout>
diff --git a/core/tests/coretests/res/layout/size_adaptive_four_u_text.xml b/core/tests/coretests/res/layout/size_adaptive_four_u_text.xml
new file mode 100644
index 0000000..93a10de
--- /dev/null
+++ b/core/tests/coretests/res/layout/size_adaptive_four_u_text.xml
@@ -0,0 +1,59 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2012 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.
+-->
+<GridLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/gridLayout4"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:background="#000000"
+ android:columnCount="2"
+ android:padding="1dp"
+ android:orientation="horizontal" >
+
+ <ImageView
+ android:id="@+id/actor"
+ android:layout_width="62dp"
+ android:layout_height="62dp"
+ android:layout_row="0"
+ android:layout_column="0"
+ android:layout_rowSpan="2"
+ android:contentDescription="@string/actor"
+ android:src="@drawable/abe" />
+
+ <TextView
+ android:layout_width="0dp"
+ android:id="@+id/name"
+ android:layout_row="0"
+ android:layout_column="1"
+ android:layout_gravity="fill_horizontal"
+ android:padding="3dp"
+ android:text="@string/actor"
+ android:textColor="#ffffff"
+ android:textStyle="bold" />
+
+ <TextView
+ android:id="@+id/note"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_column="1"
+ android:layout_gravity="fill_horizontal"
+ android:layout_marginTop="5dp"
+ android:layout_row="1"
+ android:padding="3dp"
+ android:singleLine="false"
+ android:text="@string/first"
+ android:textColor="#ffffff" />
+
+ </GridLayout>
diff --git a/core/tests/coretests/res/layout/size_adaptive_gappy.xml b/core/tests/coretests/res/layout/size_adaptive_gappy.xml
new file mode 100644
index 0000000..d5e3b41
--- /dev/null
+++ b/core/tests/coretests/res/layout/size_adaptive_gappy.xml
@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2012 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.
+-->
+<com.android.internal.widget.SizeAdaptiveLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:internal="http://schemas.android.com/apk/prv/res/android"
+ android:id="@+id/multi_with_gap"
+ android:layout_width="match_parent"
+ android:layout_height="64dp" >
+
+ <include
+ android:id="@+id/one_u"
+ layout="@layout/size_adaptive_one_u"
+ android:layout_width="fill_parent"
+ android:layout_height="64dp"
+ internal:layout_minHeight="64dp"
+ internal:layout_maxHeight="64dp"
+ />
+
+ <include
+ android:id="@+id/four_u"
+ layout="@layout/size_adaptive_four_u"
+ android:layout_width="fill_parent"
+ android:layout_height="256dp"
+ internal:layout_minHeight="128dp"
+ internal:layout_maxHeight="unbounded"/>
+
+</com.android.internal.widget.SizeAdaptiveLayout>
diff --git a/core/tests/coretests/res/layout/size_adaptive_large_only.xml b/core/tests/coretests/res/layout/size_adaptive_large_only.xml
new file mode 100644
index 0000000..cf58265
--- /dev/null
+++ b/core/tests/coretests/res/layout/size_adaptive_large_only.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2012 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.
+-->
+<com.android.internal.widget.SizeAdaptiveLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:internal="http://schemas.android.com/apk/prv/res/android"
+ android:id="@+id/large_only_multi"
+ android:layout_width="match_parent"
+ android:layout_height="64dp" >
+
+ <include
+ android:id="@+id/four_u"
+ layout="@layout/size_adaptive_four_u"
+ android:layout_width="fill_parent"
+ android:layout_height="256dp"
+ internal:layout_minHeight="65dp"
+ internal:layout_maxHeight="unbounded"/>
+
+</com.android.internal.widget.SizeAdaptiveLayout>
diff --git a/core/tests/coretests/res/layout/size_adaptive_one_u.xml b/core/tests/coretests/res/layout/size_adaptive_one_u.xml
new file mode 100644
index 0000000..b6fe4a0
--- /dev/null
+++ b/core/tests/coretests/res/layout/size_adaptive_one_u.xml
@@ -0,0 +1,66 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2012 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.
+-->
+<GridLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/gridLayout1"
+ android:layout_width="match_parent"
+ android:layout_height="64dp"
+ android:background="#000000"
+ android:columnCount="3"
+ android:padding="1dp"
+ android:rowCount="2" >
+
+ <ImageView
+ android:id="@+id/actor"
+ android:layout_width="62dp"
+ android:layout_height="62dp"
+ android:layout_column="0"
+ android:layout_row="0"
+ android:layout_rowSpan="2"
+ android:contentDescription="@string/actor"
+ android:src="@drawable/abe" />
+
+ <TextView
+ android:id="@+id/name"
+ android:layout_gravity="fill"
+ android:padding="3dp"
+ android:text="@string/actor"
+ android:textColor="#ffffff"
+ android:textStyle="bold" />
+
+ <ImageView
+ android:layout_width="62dp"
+ android:layout_height="62dp"
+ android:layout_gravity="fill_vertical"
+ android:layout_rowSpan="2"
+ android:adjustViewBounds="true"
+ android:background="#555555"
+ android:padding="2dp"
+ android:scaleType="fitXY"
+ android:src="@drawable/gettysburg"
+ android:contentDescription="@string/caption" />
+
+ <TextView
+ android:id="@+id/note"
+ android:layout_width="0dp"
+ android:layout_height="0dp"
+ android:layout_gravity="fill"
+ android:layout_marginTop="5dp"
+ android:padding="3dp"
+ android:singleLine="true"
+ android:text="@string/first"
+ android:textColor="#ffffff" />
+
+</GridLayout>
diff --git a/core/tests/coretests/res/layout/size_adaptive_one_u_text.xml b/core/tests/coretests/res/layout/size_adaptive_one_u_text.xml
new file mode 100644
index 0000000..df54eb6
--- /dev/null
+++ b/core/tests/coretests/res/layout/size_adaptive_one_u_text.xml
@@ -0,0 +1,54 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2012 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.
+-->
+<GridLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/gridLayout1"
+ android:layout_width="match_parent"
+ android:layout_height="64dp"
+ android:background="#000000"
+ android:columnCount="2"
+ android:padding="1dp"
+ android:rowCount="2" >
+
+ <ImageView
+ android:id="@+id/actor"
+ android:layout_width="62dp"
+ android:layout_height="62dp"
+ android:layout_column="0"
+ android:layout_row="0"
+ android:layout_rowSpan="2"
+ android:contentDescription="@string/actor"
+ android:src="@drawable/abe" />
+
+ <TextView
+ android:id="@+id/name"
+ android:layout_gravity="fill"
+ android:padding="3dp"
+ android:text="@string/actor"
+ android:textColor="#ffffff"
+ android:textStyle="bold" />
+
+ <TextView
+ android:id="@+id/note"
+ android:layout_width="0dp"
+ android:layout_height="0dp"
+ android:layout_gravity="fill"
+ android:layout_marginTop="5dp"
+ android:padding="3dp"
+ android:singleLine="true"
+ android:text="@string/first"
+ android:textColor="#ffffff" />
+
+</GridLayout>
diff --git a/core/tests/coretests/res/layout/size_adaptive_overlapping.xml b/core/tests/coretests/res/layout/size_adaptive_overlapping.xml
new file mode 100644
index 0000000..4abe8b0
--- /dev/null
+++ b/core/tests/coretests/res/layout/size_adaptive_overlapping.xml
@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2012 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.
+-->
+<com.android.internal.widget.SizeAdaptiveLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:internal="http://schemas.android.com/apk/prv/res/android"
+ android:id="@+id/multi_with_overlap"
+ android:layout_width="match_parent"
+ android:layout_height="64dp" >
+
+ <include
+ android:id="@+id/one_u"
+ layout="@layout/size_adaptive_one_u"
+ android:layout_width="fill_parent"
+ android:layout_height="64dp"
+ internal:layout_minHeight="64dp"
+ internal:layout_maxHeight="64dp"
+ />
+
+ <include
+ android:id="@+id/four_u"
+ layout="@layout/size_adaptive_four_u"
+ android:layout_width="fill_parent"
+ android:layout_height="256dp"
+ internal:layout_minHeight="64dp"
+ internal:layout_maxHeight="256dp"/>
+
+</com.android.internal.widget.SizeAdaptiveLayout>
diff --git a/core/tests/coretests/res/layout/size_adaptive_singleton.xml b/core/tests/coretests/res/layout/size_adaptive_singleton.xml
new file mode 100644
index 0000000..eba387f
--- /dev/null
+++ b/core/tests/coretests/res/layout/size_adaptive_singleton.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2012 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.
+-->
+<com.android.internal.widget.SizeAdaptiveLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:internal="http://schemas.android.com/apk/prv/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="64dp" >
+
+ <include
+ android:id="@+id/one_u"
+ layout="@layout/size_adaptive_one_u_text"
+ android:layout_width="fill_parent"
+ android:layout_height="64dp"
+ internal:layout_minHeight="64dp"
+ internal:layout_maxHeight="64dp"
+ />
+
+</com.android.internal.widget.SizeAdaptiveLayout>
diff --git a/core/tests/coretests/res/layout/size_adaptive_text.xml b/core/tests/coretests/res/layout/size_adaptive_text.xml
new file mode 100644
index 0000000..a9f0ba9
--- /dev/null
+++ b/core/tests/coretests/res/layout/size_adaptive_text.xml
@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2012 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.
+-->
+<com.android.internal.widget.SizeAdaptiveLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:internal="http://schemas.android.com/apk/prv/res/android"
+ android:id="@+id/multi1"
+ android:layout_width="match_parent"
+ android:layout_height="64dp" >
+
+ <include
+ android:id="@+id/one_u"
+ layout="@layout/size_adaptive_one_u_text"
+ android:layout_width="fill_parent"
+ android:layout_height="64dp"
+ internal:layout_minHeight="64dp"
+ internal:layout_maxHeight="64dp"
+ />
+
+ <include
+ android:id="@+id/four_u"
+ layout="@layout/size_adaptive_four_u_text"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ internal:layout_minHeight="65dp"
+ internal:layout_maxHeight="unbounded"/>
+
+</com.android.internal.widget.SizeAdaptiveLayout>
diff --git a/core/tests/coretests/res/layout/size_adaptive_three_way.xml b/core/tests/coretests/res/layout/size_adaptive_three_way.xml
new file mode 100644
index 0000000..1eb5396
--- /dev/null
+++ b/core/tests/coretests/res/layout/size_adaptive_three_way.xml
@@ -0,0 +1,48 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2012 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.
+-->
+<com.android.internal.widget.SizeAdaptiveLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:internal="http://schemas.android.com/apk/prv/res/android"
+ android:id="@+id/three_way_multi"
+ android:layout_width="match_parent"
+ android:layout_height="64dp" >
+
+ <include
+ android:id="@+id/one_u"
+ layout="@layout/size_adaptive_one_u"
+ android:layout_width="fill_parent"
+ android:layout_height="64dp"
+ internal:layout_minHeight="64dp"
+ internal:layout_maxHeight="64dp"
+ />
+
+ <include
+ android:id="@+id/two_u"
+ layout="@layout/size_adaptive_four_u"
+ android:layout_width="fill_parent"
+ android:layout_height="128dp"
+ internal:layout_minHeight="65dp"
+ internal:layout_maxHeight="128dp"/>
+
+ <include
+ android:id="@+id/four_u"
+ layout="@layout/size_adaptive_four_u"
+ android:layout_width="fill_parent"
+ android:layout_height="256dp"
+ internal:layout_minHeight="129dp"
+ internal:layout_maxHeight="unbounded"/>
+
+</com.android.internal.widget.SizeAdaptiveLayout>
diff --git a/core/tests/coretests/res/raw/install b/core/tests/coretests/res/raw/install
deleted file mode 100644
index 06981f4..0000000
--- a/core/tests/coretests/res/raw/install
+++ /dev/null
Binary files differ
diff --git a/core/tests/coretests/res/values/strings.xml b/core/tests/coretests/res/values/strings.xml
index 71f3520..ce0d9a2 100644
--- a/core/tests/coretests/res/values/strings.xml
+++ b/core/tests/coretests/res/values/strings.xml
@@ -131,4 +131,8 @@
<string name="textview_hebrew_text">םמab?!</string>
+ <!-- SizeAdaptiveLayout -->
+ <string name="first">Four score and seven years ago our fathers brought forth on this continent, a new nation, conceived in Liberty, and dedicated to the proposition that all men are created equal.</string>
+ <string name="actor">Abe Lincoln</string>
+ <string name="caption">Lincoln adressing the crowd at Gettysburgh</string>
</resources>
diff --git a/core/tests/coretests/src/android/animation/EventsTest.java b/core/tests/coretests/src/android/animation/EventsTest.java
index 701a3f0..8df711b 100644
--- a/core/tests/coretests/src/android/animation/EventsTest.java
+++ b/core/tests/coretests/src/android/animation/EventsTest.java
@@ -173,8 +173,7 @@
// This should only be called on an animation that has been started and not
// yet canceled or ended
assertFalse(mCanceled);
- assertTrue(mRunning);
- assertTrue(mStarted);
+ assertTrue(mRunning || mStarted);
mCanceled = true;
}
@@ -182,8 +181,7 @@
public void onAnimationEnd(Animator animation) {
// This should only be called on an animation that has been started and not
// yet ended
- assertTrue(mRunning);
- assertTrue(mStarted);
+ assertTrue(mRunning || mStarted);
mRunning = false;
mStarted = false;
super.onAnimationEnd(animation);
@@ -210,11 +208,12 @@
}
/**
- * Verify that calling end on an unstarted animator does nothing.
+ * Verify that calling end on an unstarted animator starts/ends an animator.
*/
@UiThreadTest
@SmallTest
public void testEnd() throws Exception {
+ mRunning = true; // end() implicitly starts an unstarted animator
mAnimator.end();
}
@@ -496,6 +495,7 @@
mRunning = true;
mAnimator.start();
mAnimator.end();
+ mRunning = true; // end() implicitly starts an unstarted animator
mAnimator.end();
mFuture.release();
} catch (junit.framework.AssertionFailedError e) {
@@ -544,6 +544,7 @@
mRunning = true;
mAnimator.start();
mAnimator.end();
+ mRunning = true; // end() implicitly starts an unstarted animator
mAnimator.end();
mFuture.release();
} catch (junit.framework.AssertionFailedError e) {
diff --git a/core/tests/coretests/src/android/content/pm/PackageManagerTests.java b/core/tests/coretests/src/android/content/pm/PackageManagerTests.java
index 9575ced..580b4da 100755
--- a/core/tests/coretests/src/android/content/pm/PackageManagerTests.java
+++ b/core/tests/coretests/src/android/content/pm/PackageManagerTests.java
@@ -170,11 +170,10 @@
return ipm;
}
- public boolean invokeInstallPackage(Uri packageURI, int flags, GenericReceiver receiver) {
+ public void invokeInstallPackage(Uri packageURI, int flags, GenericReceiver receiver,
+ boolean shouldSucceed) {
PackageInstallObserver observer = new PackageInstallObserver();
- final boolean received = false;
mContext.registerReceiver(receiver, receiver.filter);
- final boolean DEBUG = true;
try {
// Wait on observer
synchronized(observer) {
@@ -192,10 +191,24 @@
if(!observer.isDone()) {
fail("Timed out waiting for packageInstalled callback");
}
- if (observer.returnCode != PackageManager.INSTALL_SUCCEEDED) {
- Log.i(TAG, "Failed to install with error code = " + observer.returnCode);
- return false;
+
+ if (shouldSucceed) {
+ if (observer.returnCode != PackageManager.INSTALL_SUCCEEDED) {
+ fail("Package installation should have succeeded, but got code "
+ + observer.returnCode);
+ }
+ } else {
+ if (observer.returnCode == PackageManager.INSTALL_SUCCEEDED) {
+ fail("Package installation should fail");
+ }
+
+ /*
+ * We'll never expect get a notification since we
+ * shouldn't succeed.
+ */
+ return;
}
+
// Verify we received the broadcast
waitTime = 0;
while((!receiver.isDone()) && (waitTime < MAX_WAIT_TIME) ) {
@@ -209,7 +222,6 @@
if(!receiver.isDone()) {
fail("Timed out waiting for PACKAGE_ADDED notification");
}
- return receiver.received;
}
}
} finally {
@@ -588,7 +600,7 @@
}
} else {
InstallReceiver receiver = new InstallReceiver(pkg.packageName);
- assertTrue(invokeInstallPackage(packageURI, flags, receiver));
+ invokeInstallPackage(packageURI, flags, receiver, true);
// Verify installed information
assertInstall(pkg, flags, expInstallLocation);
}
@@ -705,13 +717,9 @@
receiver = new InstallReceiver(ip.pkg.packageName);
}
try {
- try {
- assertEquals(invokeInstallPackage(ip.packageURI, flags, receiver), replace);
- if (replace) {
- assertInstall(ip.pkg, flags, ip.pkg.installLocation);
- }
- } catch (Exception e) {
- failStr("Failed with exception : " + e);
+ invokeInstallPackage(ip.packageURI, flags, receiver, replace);
+ if (replace) {
+ assertInstall(ip.pkg, flags, ip.pkg.installLocation);
}
} finally {
cleanUpInstall(ip);
@@ -1244,7 +1252,7 @@
GenericReceiver receiver = new ReplaceReceiver(ip.pkg.packageName);
int replaceFlags = rFlags | PackageManager.INSTALL_REPLACE_EXISTING;
try {
- assertEquals(invokeInstallPackage(ip.packageURI, replaceFlags, receiver), true);
+ invokeInstallPackage(ip.packageURI, replaceFlags, receiver, true);
assertInstall(ip.pkg, rFlags, ip.pkg.installLocation);
} catch (Exception e) {
failStr("Failed with exception : " + e);
@@ -1271,7 +1279,7 @@
GenericReceiver receiver = new ReplaceReceiver(ip.pkg.packageName);
int replaceFlags = rFlags | PackageManager.INSTALL_REPLACE_EXISTING;
try {
- assertEquals(invokeInstallPackage(ip.packageURI, replaceFlags, receiver), true);
+ invokeInstallPackage(ip.packageURI, replaceFlags, receiver, true);
assertInstall(ip.pkg, iFlags, ip.pkg.installLocation);
} catch (Exception e) {
failStr("Failed with exception : " + e);
diff --git a/core/tests/coretests/src/com/android/internal/os/DebugTest.java b/core/tests/coretests/src/com/android/internal/os/DebugTest.java
new file mode 100644
index 0000000..88c7d1b
--- /dev/null
+++ b/core/tests/coretests/src/com/android/internal/os/DebugTest.java
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2012 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.os;
+
+import android.os.Debug;
+
+import android.test.suitebuilder.annotation.SmallTest;
+import junit.framework.TestCase;
+
+@SmallTest
+public class DebugTest extends TestCase {
+
+ private final static String EXPECTED_GET_CALLER =
+ "com\\.android\\.internal\\.os\\.DebugTest\\.testGetCaller:\\d\\d";
+ private final static String EXPECTED_GET_CALLERS =
+ "com\\.android\\.internal\\.os\\.DebugTest.callDepth3:\\d\\d " +
+ "com\\.android\\.internal\\.os\\.DebugTest.callDepth2:\\d\\d " +
+ "com\\.android\\.internal\\.os\\.DebugTest.callDepth1:\\d\\d ";
+
+ /**
+ * @return String consisting of the caller to this method.
+ */
+ private String callDepth0() {
+ return Debug.getCaller();
+ }
+
+ public void testGetCaller() {
+ assertTrue(callDepth0().matches(EXPECTED_GET_CALLER));
+ }
+
+ /**
+ * @return String consisting of the callers to this method.
+ */
+ private String callDepth4() {
+ return Debug.getCallers(3);
+ }
+
+ private String callDepth3() {
+ return callDepth4();
+ }
+
+ private String callDepth2() {
+ return callDepth3();
+ }
+
+ private String callDepth1() {
+ return callDepth2();
+ }
+
+ public void testGetCallers() {
+ assertTrue(callDepth1().matches(EXPECTED_GET_CALLERS));
+ }
+}
diff --git a/core/tests/coretests/src/com/android/internal/widget/SizeAdaptiveLayoutTest.java b/core/tests/coretests/src/com/android/internal/widget/SizeAdaptiveLayoutTest.java
new file mode 100644
index 0000000..fc83e4a
--- /dev/null
+++ b/core/tests/coretests/src/com/android/internal/widget/SizeAdaptiveLayoutTest.java
@@ -0,0 +1,446 @@
+/*
+ * Copyright (C) 2012 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.widget;
+
+import com.android.frameworks.coretests.R;
+
+import android.content.Context;
+import android.graphics.drawable.ColorDrawable;
+import android.test.AndroidTestCase;
+import android.test.suitebuilder.annotation.SmallTest;
+import android.view.LayoutInflater;
+import android.view.View;
+
+import com.android.internal.widget.SizeAdaptiveLayout;
+
+
+public class SizeAdaptiveLayoutTest extends AndroidTestCase {
+
+ private LayoutInflater mInflater;
+ private int mOneU;
+ private int mFourU;
+ private SizeAdaptiveLayout mSizeAdaptiveLayout;
+ private View mSmallView;
+ private View mMediumView;
+ private View mLargeView;
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+
+ // inflate the layout
+ final Context context = getContext();
+ mInflater = LayoutInflater.from(context);
+ mOneU = 64;
+ mFourU = 4 * mOneU;
+ }
+
+ private void inflate(int resource){
+ mSizeAdaptiveLayout = (SizeAdaptiveLayout) mInflater.inflate(resource, null);
+ mSizeAdaptiveLayout.onAttachedToWindow();
+
+ mSmallView = mSizeAdaptiveLayout.findViewById(R.id.one_u);
+ mMediumView = mSizeAdaptiveLayout.findViewById(R.id.two_u);
+ mLargeView = mSizeAdaptiveLayout.findViewById(R.id.four_u);
+ }
+
+ /**
+ * The name 'test preconditions' is a convention to signal that if this
+ * test doesn't pass, the test case was not set up properly and it might
+ * explain any and all failures in other tests. This is not guaranteed
+ * to run before other tests, as junit uses reflection to find the tests.
+ */
+ @SmallTest
+ public void testPreconditions() {
+ assertNotNull(mInflater);
+
+ inflate(R.layout.size_adaptive);
+ assertNotNull(mSizeAdaptiveLayout);
+ assertNotNull(mSmallView);
+ assertNotNull(mLargeView);
+ }
+
+ @SmallTest
+ public void testOpenLarge() {
+ inflate(R.layout.size_adaptive);
+ SizeAdaptiveLayout.LayoutParams lp =
+ (SizeAdaptiveLayout.LayoutParams) mLargeView.getLayoutParams();
+ int height = (int) lp.minHeight + 10;
+
+ measureAndLayout(height);
+
+ assertEquals("4U should be visible",
+ View.VISIBLE,
+ mLargeView.getVisibility());
+ assertEquals("1U should be gone",
+ View.GONE,
+ mSmallView.getVisibility());
+ }
+
+ @SmallTest
+ public void testOpenSmall() {
+ inflate(R.layout.size_adaptive);
+ SizeAdaptiveLayout.LayoutParams lp =
+ (SizeAdaptiveLayout.LayoutParams) mSmallView.getLayoutParams();
+ int height = (int) lp.minHeight;
+
+ measureAndLayout(height);
+
+ assertEquals("1U should be visible",
+ View.VISIBLE,
+ mSmallView.getVisibility());
+ assertEquals("4U should be gone",
+ View.GONE,
+ mLargeView.getVisibility());
+ }
+
+ @SmallTest
+ public void testOpenTooSmall() {
+ inflate(R.layout.size_adaptive);
+ SizeAdaptiveLayout.LayoutParams lp =
+ (SizeAdaptiveLayout.LayoutParams) mSmallView.getLayoutParams();
+ int height = (int) lp.minHeight - 10;
+
+ measureAndLayout(height);
+
+ assertEquals("1U should be visible",
+ View.VISIBLE,
+ mSmallView.getVisibility());
+ assertEquals("4U should be gone",
+ View.GONE,
+ mLargeView.getVisibility());
+ }
+
+ @SmallTest
+ public void testOpenTooBig() {
+ inflate(R.layout.size_adaptive);
+ SizeAdaptiveLayout.LayoutParams lp =
+ (SizeAdaptiveLayout.LayoutParams) mLargeView.getLayoutParams();
+ lp.maxHeight = 500;
+ mLargeView.setLayoutParams(lp);
+ int height = (int) (lp.minHeight + 10);
+
+ measureAndLayout(height);
+
+ assertEquals("4U should be visible",
+ View.VISIBLE,
+ mLargeView.getVisibility());
+ assertEquals("1U should be gone",
+ View.GONE,
+ mSmallView.getVisibility());
+ }
+
+ @SmallTest
+ public void testOpenWrapContent() {
+ inflate(R.layout.size_adaptive_text);
+ SizeAdaptiveLayout.LayoutParams lp =
+ (SizeAdaptiveLayout.LayoutParams) mLargeView.getLayoutParams();
+ int height = (int) lp.minHeight + 10;
+
+ // manually measure it, and lay it out
+ int measureSpec = View.MeasureSpec.makeMeasureSpec(height, View.MeasureSpec.AT_MOST);
+ mSizeAdaptiveLayout.measure(500, measureSpec);
+ assertTrue("should not be forced to 4U",
+ mSizeAdaptiveLayout.getMeasuredHeight() < mFourU);
+ }
+
+ @SmallTest
+ public void testOpenOneUOnlySmall() {
+ inflate(R.layout.size_adaptive_singleton);
+ assertNull("largeView should be NULL in the singleton layout", mLargeView);
+
+ SizeAdaptiveLayout.LayoutParams lp =
+ (SizeAdaptiveLayout.LayoutParams) mSmallView.getLayoutParams();
+ int height = (int) lp.minHeight - 10;
+
+ measureAndLayout(height);
+
+ assertEquals("1U should be visible",
+ View.VISIBLE,
+ mSmallView.getVisibility());
+ }
+
+ @SmallTest
+ public void testOpenOneUOnlyLarge() {
+ inflate(R.layout.size_adaptive_singleton);
+ assertNull("largeView should be NULL in the singleton layout", mLargeView);
+
+ SizeAdaptiveLayout.LayoutParams lp =
+ (SizeAdaptiveLayout.LayoutParams) mSmallView.getLayoutParams();
+ int height = (int) lp.maxHeight + 10;
+
+ measureAndLayout(height);
+
+ assertEquals("1U should be visible",
+ View.VISIBLE,
+ mSmallView.getVisibility());
+ }
+
+ @SmallTest
+ public void testOpenOneUOnlyJustRight() {
+ inflate(R.layout.size_adaptive_singleton);
+ assertNull("largeView should be NULL in the singleton layout", mLargeView);
+
+ SizeAdaptiveLayout.LayoutParams lp =
+ (SizeAdaptiveLayout.LayoutParams) mSmallView.getLayoutParams();
+ int height = (int) lp.minHeight;
+
+ measureAndLayout(height);
+
+ assertEquals("1U should be visible",
+ View.VISIBLE,
+ mSmallView.getVisibility());
+ }
+
+ @SmallTest
+ public void testOpenFourUOnlySmall() {
+ inflate(R.layout.size_adaptive_large_only);
+ assertNull("smallView should be NULL in the singleton layout", mSmallView);
+
+ SizeAdaptiveLayout.LayoutParams lp =
+ (SizeAdaptiveLayout.LayoutParams) mLargeView.getLayoutParams();
+ int height = (int) lp.minHeight - 10;
+
+ measureAndLayout(height);
+
+ assertEquals("4U should be visible",
+ View.VISIBLE,
+ mLargeView.getVisibility());
+ }
+
+ @SmallTest
+ public void testOpenFourUOnlyLarge() {
+ inflate(R.layout.size_adaptive_large_only);
+ assertNull("smallView should be NULL in the singleton layout", mSmallView);
+
+ SizeAdaptiveLayout.LayoutParams lp =
+ (SizeAdaptiveLayout.LayoutParams) mLargeView.getLayoutParams();
+ int height = (int) lp.maxHeight + 10;
+
+ measureAndLayout(height);
+
+ assertEquals("4U should be visible",
+ View.VISIBLE,
+ mLargeView.getVisibility());
+ }
+
+ @SmallTest
+ public void testOpenFourUOnlyJustRight() {
+ inflate(R.layout.size_adaptive_large_only);
+ assertNull("smallView should be NULL in the singleton layout", mSmallView);
+
+ SizeAdaptiveLayout.LayoutParams lp =
+ (SizeAdaptiveLayout.LayoutParams) mLargeView.getLayoutParams();
+ int height = (int) lp.minHeight;
+
+ measureAndLayout(height);
+
+ assertEquals("4U should be visible",
+ View.VISIBLE,
+ mLargeView.getVisibility());
+ }
+
+ @SmallTest
+ public void testOpenIntoAGap() {
+ inflate(R.layout.size_adaptive_gappy);
+
+ SizeAdaptiveLayout.LayoutParams smallParams =
+ (SizeAdaptiveLayout.LayoutParams) mSmallView.getLayoutParams();
+ SizeAdaptiveLayout.LayoutParams largeParams =
+ (SizeAdaptiveLayout.LayoutParams) mLargeView.getLayoutParams();
+ assertTrue("gappy layout should have a gap",
+ smallParams.maxHeight + 10 < largeParams.minHeight);
+ int height = (int) smallParams.maxHeight + 10;
+
+ measureAndLayout(height);
+
+ assertTrue("one and only one view should be visible",
+ mLargeView.getVisibility() != mSmallView.getVisibility());
+ // behavior is undefined in this case.
+ }
+
+ @SmallTest
+ public void testOpenIntoAnOverlap() {
+ inflate(R.layout.size_adaptive_overlapping);
+
+ SizeAdaptiveLayout.LayoutParams smallParams =
+ (SizeAdaptiveLayout.LayoutParams) mSmallView.getLayoutParams();
+ SizeAdaptiveLayout.LayoutParams largeParams =
+ (SizeAdaptiveLayout.LayoutParams) mLargeView.getLayoutParams();
+ assertEquals("overlapping layout should overlap",
+ smallParams.minHeight,
+ largeParams.minHeight);
+ int height = (int) smallParams.maxHeight;
+
+ measureAndLayout(height);
+
+ assertTrue("one and only one view should be visible",
+ mLargeView.getVisibility() != mSmallView.getVisibility());
+ assertEquals("1U should get priority in an overlap because it is first",
+ View.VISIBLE,
+ mSmallView.getVisibility());
+ }
+
+ @SmallTest
+ public void testOpenThreeWayViewSmall() {
+ inflate(R.layout.size_adaptive_three_way);
+ assertNotNull("mMediumView should not be NULL in the three view layout", mMediumView);
+
+ SizeAdaptiveLayout.LayoutParams lp =
+ (SizeAdaptiveLayout.LayoutParams) mSmallView.getLayoutParams();
+ int height = (int) lp.minHeight;
+
+ measureAndLayout(height);
+
+ assertEquals("1U should be visible",
+ View.VISIBLE,
+ mSmallView.getVisibility());
+ assertEquals("2U should be gone",
+ View.GONE,
+ mMediumView.getVisibility());
+ assertEquals("4U should be gone",
+ View.GONE,
+ mLargeView.getVisibility());
+ }
+
+ @SmallTest
+ public void testOpenThreeWayViewMedium() {
+ inflate(R.layout.size_adaptive_three_way);
+ assertNotNull("mMediumView should not be NULL in the three view layout", mMediumView);
+
+ SizeAdaptiveLayout.LayoutParams lp =
+ (SizeAdaptiveLayout.LayoutParams) mMediumView.getLayoutParams();
+ int height = (int) lp.minHeight;
+
+ measureAndLayout(height);
+
+ assertEquals("1U should be gone",
+ View.GONE,
+ mSmallView.getVisibility());
+ assertEquals("2U should be visible",
+ View.VISIBLE,
+ mMediumView.getVisibility());
+ assertEquals("4U should be gone",
+ View.GONE,
+ mLargeView.getVisibility());
+ }
+
+ @SmallTest
+ public void testOpenThreeWayViewLarge() {
+ inflate(R.layout.size_adaptive_three_way);
+ assertNotNull("mMediumView should not be NULL in the three view layout", mMediumView);
+
+ SizeAdaptiveLayout.LayoutParams lp =
+ (SizeAdaptiveLayout.LayoutParams) mLargeView.getLayoutParams();
+ int height = (int) lp.minHeight;
+
+ measureAndLayout(height);
+
+ assertEquals("1U should be gone",
+ View.GONE,
+ mSmallView.getVisibility());
+ assertEquals("2U should be gone",
+ View.GONE,
+ mMediumView.getVisibility());
+ assertEquals("4U should be visible",
+ View.VISIBLE,
+ mLargeView.getVisibility());
+ }
+
+ @SmallTest
+ public void testResizeWithoutAnimation() {
+ inflate(R.layout.size_adaptive);
+
+ SizeAdaptiveLayout.LayoutParams largeParams =
+ (SizeAdaptiveLayout.LayoutParams) mLargeView.getLayoutParams();
+ int startHeight = (int) largeParams.minHeight + 10;
+ int endHeight = (int) largeParams.minHeight + 10;
+
+ measureAndLayout(startHeight);
+
+ assertEquals("4U should be visible",
+ View.VISIBLE,
+ mLargeView.getVisibility());
+ assertFalse("There should be no animation on initial rendering.",
+ mSizeAdaptiveLayout.getTransitionAnimation().isRunning());
+
+ measureAndLayout(endHeight);
+
+ assertEquals("4U should still be visible",
+ View.VISIBLE,
+ mLargeView.getVisibility());
+ assertFalse("There should be no animation on scale within a view.",
+ mSizeAdaptiveLayout.getTransitionAnimation().isRunning());
+ }
+
+ @SmallTest
+ public void testResizeWithAnimation() {
+ inflate(R.layout.size_adaptive);
+
+ SizeAdaptiveLayout.LayoutParams smallParams =
+ (SizeAdaptiveLayout.LayoutParams) mSmallView.getLayoutParams();
+ SizeAdaptiveLayout.LayoutParams largeParams =
+ (SizeAdaptiveLayout.LayoutParams) mLargeView.getLayoutParams();
+ int startHeight = (int) largeParams.minHeight + 10;
+ int endHeight = (int) smallParams.maxHeight;
+
+ measureAndLayout(startHeight);
+
+ assertEquals("4U should be visible",
+ View.VISIBLE,
+ mLargeView.getVisibility());
+ assertFalse("There should be no animation on initial rendering.",
+ mSizeAdaptiveLayout.getTransitionAnimation().isRunning());
+
+ measureAndLayout(endHeight);
+
+ assertEquals("1U should now be visible",
+ View.VISIBLE,
+ mSmallView.getVisibility());
+ assertTrue("There should be an animation on scale between views.",
+ mSizeAdaptiveLayout.getTransitionAnimation().isRunning());
+ }
+
+ @SmallTest
+ public void testModestyPanelChangesColorWhite() {
+ inflate(R.layout.size_adaptive_color);
+ View panel = mSizeAdaptiveLayout.getModestyPanel();
+ assertTrue("ModestyPanel should have a ColorDrawable background",
+ panel.getBackground() instanceof ColorDrawable);
+ ColorDrawable panelColor = (ColorDrawable) panel.getBackground();
+ ColorDrawable salColor = (ColorDrawable) mSizeAdaptiveLayout.getBackground();
+ assertEquals("ModestyPanel color should match the SizeAdaptiveLayout",
+ panelColor.getColor(), salColor.getColor());
+ }
+
+ @SmallTest
+ public void testModestyPanelHasDefault() {
+ inflate(R.layout.size_adaptive);
+ View panel = mSizeAdaptiveLayout.getModestyPanel();
+ assertNull("SizeAdaptiveLayout should have no background for this test",
+ mSizeAdaptiveLayout.getBackground());
+ assertTrue("ModestyPanel should have a ColorDrawable background",
+ panel.getBackground() instanceof ColorDrawable);
+ }
+
+ private void measureAndLayout(int height) {
+ // manually measure it, and lay it out
+ int measureSpec = View.MeasureSpec.makeMeasureSpec(height, View.MeasureSpec.AT_MOST);
+ mSizeAdaptiveLayout.measure(500, measureSpec);
+ mSizeAdaptiveLayout.layout(0, 0, 500, height);
+ }
+}
diff --git a/data/fonts/DroidNaskh-Regular-Shift.ttf b/data/fonts/DroidNaskh-Regular-Shift.ttf
index 0cb843d..bb9c70c 100644
--- a/data/fonts/DroidNaskh-Regular-Shift.ttf
+++ b/data/fonts/DroidNaskh-Regular-Shift.ttf
Binary files differ
diff --git a/docs/html/shareables/training/LocationAware.zip b/docs/html/shareables/training/LocationAware.zip
index 46970cd..8ed97cb 100644
--- a/docs/html/shareables/training/LocationAware.zip
+++ b/docs/html/shareables/training/LocationAware.zip
Binary files differ
diff --git a/docs/html/training/location/locationmanager.jd b/docs/html/training/location/locationmanager.jd
index 5da1205..61abcbd 100644
--- a/docs/html/training/location/locationmanager.jd
+++ b/docs/html/training/location/locationmanager.jd
@@ -18,6 +18,7 @@
<li><a href="locationmanager.html#TaskDeclarePermissions">Declare Proper Permissions in Android Manifest</a></li>
<li><a href="locationmanager.html#TaskGetLocationManagerRef">Get a Reference to LocationManager</a></li>
<li><a href="locationmanager.html#TaskPickLocationProvider">Pick a Location Provider</a></li>
+ <li><a href="locationmanager.html#TaskVerifyProvider">Verify the Location Provider is Enabled</a></li>
</ol>
<h2>You should also read</h2>
@@ -88,3 +89,32 @@
...
}
</pre>
+
+<h2 id="TaskVerifyProvider">Verify the Location Provider is Enabled</h2>
+
+<p>Some location providers such as the GPS can be disabled in Settings. It is good practice to check whether the desired location provider is currently enabled by calling the {@link android.location.LocationManager#isProviderEnabled(java.lang.String) isProviderEnabled()} method. If the location provider is disabled, you can offer the user an opportunity to enable it in Settings by firing an {@link android.content.Intent} with the {@link android.provider.Settings#ACTION_LOCATION_SOURCE_SETTINGS} action.</p>
+
+<pre>
+@Override
+protected void onStart() {
+ super.onStart();
+
+ // This verification should be done during onStart() because the system calls
+ // this method when the user returns to the activity, which ensures the desired
+ // location provider is enabled each time the activity resumes from the stopped state.
+ LocationManager locationManager =
+ (LocationManager) getSystemService(Context.LOCATION_SERVICE);
+ final boolean gpsEnabled = locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER);
+
+ if (!gpsEnabled) {
+ // Build an alert dialog here that requests that the user enable
+ // the location services, then when the user clicks the "OK" button,
+ // call enableLocationSettings()
+ }
+}
+
+private void enableLocationSettings() {
+ Intent settingsIntent = new Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS);
+ startActivity(settingsIntent);
+}
+</pre>
diff --git a/graphics/java/android/graphics/Insets.java b/graphics/java/android/graphics/Insets.java
new file mode 100644
index 0000000..c570cd4
--- /dev/null
+++ b/graphics/java/android/graphics/Insets.java
@@ -0,0 +1,114 @@
+/*
+ * 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.graphics;
+
+/**
+ * An Insets instance holds four integer offsets which describe changes to the four
+ * edges of a Rectangle. By convention, positive values move edges towards the
+ * centre of the rectangle.
+ * <p>
+ * Insets are immutable so may be treated as values.
+ *
+ * @hide
+ */
+public class Insets {
+ public static final Insets NONE = new Insets(0, 0, 0, 0);
+
+ public final int left;
+ public final int top;
+ public final int right;
+ public final int bottom;
+
+ private Insets(int left, int top, int right, int bottom) {
+ this.left = left;
+ this.top = top;
+ this.right = right;
+ this.bottom = bottom;
+ }
+
+ // Factory methods
+
+ /**
+ * Return an Insets instance with the appropriate values.
+ *
+ * @param left the left inset
+ * @param top the top inset
+ * @param right the right inset
+ * @param bottom the bottom inset
+ *
+ * @return Insets instance with the appropriate values
+ */
+ public static Insets of(int left, int top, int right, int bottom) {
+ if (left == 0 && top == 0 && right == 0 && bottom == 0) {
+ return NONE;
+ }
+ return new Insets(left, top, right, bottom);
+ }
+
+ /**
+ * Return an Insets instance with the appropriate values.
+ *
+ * @param r the rectangle from which to take the values
+ *
+ * @return an Insets instance with the appropriate values
+ */
+ public static Insets of(Rect r) {
+ return of(r.left, r.top, r.right, r.bottom);
+ }
+
+ /**
+ * Two Insets instances are equal iff they belong to the same class and their fields are
+ * pairwise equal.
+ *
+ * @param o the object to compare this instance with.
+ *
+ * @return true iff this object is equal {@code o}
+ */
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+
+ Insets insets = (Insets) o;
+
+ if (bottom != insets.bottom) return false;
+ if (left != insets.left) return false;
+ if (right != insets.right) return false;
+ if (top != insets.top) return false;
+
+ return true;
+ }
+
+ @Override
+ public int hashCode() {
+ int result = left;
+ result = 31 * result + top;
+ result = 31 * result + right;
+ result = 31 * result + bottom;
+ return result;
+ }
+
+ @Override
+ public String toString() {
+ return "Insets{" +
+ "left=" + left +
+ ", top=" + top +
+ ", right=" + right +
+ ", bottom=" + bottom +
+ '}';
+ }
+}
diff --git a/graphics/java/android/graphics/SurfaceTexture.java b/graphics/java/android/graphics/SurfaceTexture.java
index 3fc20b5..4beaecd 100644
--- a/graphics/java/android/graphics/SurfaceTexture.java
+++ b/graphics/java/android/graphics/SurfaceTexture.java
@@ -159,7 +159,7 @@
* It will implicitly bind its texture to the GL_TEXTURE_EXTERNAL_OES texture target.
*/
public void updateTexImage() {
- nativeUpdateTexImage();
+ nativeUpdateTexImage();
}
/**
@@ -172,8 +172,6 @@
* This can be used to access the SurfaceTexture image contents from multiple OpenGL ES
* contexts. Note, however, that the image contents are only accessible from one OpenGL ES
* context at a time.
- *
- * @hide
*/
public void detachFromGLContext() {
int err = nativeDetachFromGLContext();
@@ -194,8 +192,6 @@
*
* @param texName The name of the OpenGL ES texture that will be created. This texture name
* must be unusued in the OpenGL ES context that is current on the calling thread.
- *
- * @hide
*/
public void attachToGLContext(int texName) {
int err = nativeAttachToGLContext(texName);
diff --git a/graphics/java/android/graphics/drawable/Drawable.java b/graphics/java/android/graphics/drawable/Drawable.java
index 86e824b..7d1942a 100644
--- a/graphics/java/android/graphics/drawable/Drawable.java
+++ b/graphics/java/android/graphics/drawable/Drawable.java
@@ -705,6 +705,20 @@
}
/**
+ * Return in insets the layout insets suggested by this Drawable for use with alignment
+ * operations during layout. Positive values move toward the
+ * center of the Drawable. Returns true if this drawable
+ * actually has a layout insets, else false. When false is returned, the padding
+ * is always set to 0.
+ *
+ * @hide
+ */
+ public boolean getLayoutInsets(Rect insets) {
+ insets.set(0, 0, 0, 0);
+ return false;
+ }
+
+ /**
* Make this drawable mutable. This operation cannot be reversed. A mutable
* drawable is guaranteed to not share its state with any other drawable.
* This is especially useful when you need to modify properties of drawables
@@ -965,9 +979,7 @@
Rect pad, Rect layoutBounds, String srcName) {
if (np != null) {
- NinePatchDrawable npd = new NinePatchDrawable(res, bm, np, pad, srcName);
- npd.setLayoutBounds(layoutBounds);
- return npd;
+ return new NinePatchDrawable(res, bm, np, pad, layoutBounds, srcName);
}
return new BitmapDrawable(res, bm);
diff --git a/graphics/java/android/graphics/drawable/DrawableContainer.java b/graphics/java/android/graphics/drawable/DrawableContainer.java
index b0f7fd3..e10f9e8 100644
--- a/graphics/java/android/graphics/drawable/DrawableContainer.java
+++ b/graphics/java/android/graphics/drawable/DrawableContainer.java
@@ -90,6 +90,18 @@
}
}
+ /**
+ * @hide
+ */
+ @Override
+ public boolean getLayoutInsets(Rect insets) {
+ if (mCurrDrawable != null) {
+ return mCurrDrawable.getLayoutInsets(insets);
+ } else {
+ return super.getLayoutInsets(insets);
+ }
+ }
+
@Override
public void setAlpha(int alpha) {
if (mAlpha != alpha) {
diff --git a/graphics/java/android/graphics/drawable/NinePatchDrawable.java b/graphics/java/android/graphics/drawable/NinePatchDrawable.java
index 1272071..e502b7a 100644
--- a/graphics/java/android/graphics/drawable/NinePatchDrawable.java
+++ b/graphics/java/android/graphics/drawable/NinePatchDrawable.java
@@ -16,9 +16,17 @@
package android.graphics.drawable;
-import android.graphics.*;
import android.content.res.Resources;
import android.content.res.TypedArray;
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+import android.graphics.Canvas;
+import android.graphics.ColorFilter;
+import android.graphics.NinePatch;
+import android.graphics.Paint;
+import android.graphics.PixelFormat;
+import android.graphics.Rect;
+import android.graphics.Region;
import android.util.AttributeSet;
import android.util.DisplayMetrics;
import android.util.TypedValue;
@@ -29,7 +37,7 @@
import java.io.InputStream;
/**
- *
+ *
* A resizeable bitmap, with stretchable areas that you define. This type of image
* is defined in a .png file with a special format.
*
@@ -47,7 +55,6 @@
private NinePatchState mNinePatchState;
private NinePatch mNinePatch;
private Rect mPadding;
- private Rect mLayoutBounds;
private Paint mPaint;
private boolean mMutated;
@@ -56,7 +63,7 @@
// These are scaled to match the target density.
private int mBitmapWidth;
private int mBitmapHeight;
-
+
NinePatchDrawable() {
}
@@ -69,7 +76,7 @@
public NinePatchDrawable(Bitmap bitmap, byte[] chunk, Rect padding, String srcName) {
this(new NinePatchState(new NinePatch(bitmap, chunk, srcName), padding), null);
}
-
+
/**
* Create drawable from raw nine-patch data, setting initial target density
* based on the display metrics of the resources.
@@ -79,7 +86,19 @@
this(new NinePatchState(new NinePatch(bitmap, chunk, srcName), padding), res);
mNinePatchState.mTargetDensity = mTargetDensity;
}
-
+
+ /**
+ * Create drawable from raw nine-patch data, setting initial target density
+ * based on the display metrics of the resources.
+ *
+ * @hide
+ */
+ public NinePatchDrawable(Resources res, Bitmap bitmap, byte[] chunk,
+ Rect padding, Rect layoutInsets, String srcName) {
+ this(new NinePatchState(new NinePatch(bitmap, chunk, srcName), padding, layoutInsets), res);
+ mNinePatchState.mTargetDensity = mTargetDensity;
+ }
+
/**
* Create drawable from existing nine-patch, not dealing with density.
* @deprecated Use {@link #NinePatchDrawable(Resources, NinePatch)}
@@ -99,13 +118,6 @@
mNinePatchState.mTargetDensity = mTargetDensity;
}
- /**
- * @hide
- */
- void setLayoutBounds(Rect layoutBounds) {
- mLayoutBounds = layoutBounds;
- }
-
private void setNinePatchState(NinePatchState state, Resources res) {
mNinePatchState = state;
mNinePatch = state.mNinePatch;
@@ -201,13 +213,26 @@
public int getChangingConfigurations() {
return super.getChangingConfigurations() | mNinePatchState.mChangingConfigurations;
}
-
+
@Override
public boolean getPadding(Rect padding) {
padding.set(mPadding);
return true;
}
+ /**
+ * @hide
+ */
+ @Override
+ public boolean getLayoutInsets(Rect insets) {
+ Rect layoutInsets = mNinePatchState.mLayoutInsets;
+ if (layoutInsets == null) {
+ return super.getLayoutInsets(insets);
+ }
+ insets.set(layoutInsets);
+ return true;
+ }
+
@Override
public void setAlpha(int alpha) {
if (mPaint == null && alpha == 0xFF) {
@@ -217,7 +242,7 @@
getPaint().setAlpha(alpha);
invalidateSelf();
}
-
+
@Override
public void setColorFilter(ColorFilter cf) {
if (mPaint == null && cf == null) {
@@ -267,6 +292,7 @@
options.inScreenDensity = DisplayMetrics.DENSITY_DEVICE;
final Rect padding = new Rect();
+ final Rect layoutInsets = new Rect();
Bitmap bitmap = null;
try {
@@ -290,7 +316,7 @@
setNinePatchState(new NinePatchState(
new NinePatch(bitmap, bitmap.getNinePatchChunk(), "XML 9-patch"),
- padding, dither), r);
+ padding, layoutInsets, dither), r);
mNinePatchState.mTargetDensity = mTargetDensity;
a.recycle();
@@ -344,7 +370,7 @@
public Region getTransparentRegion() {
return mNinePatch.getTransparentRegion(getBounds());
}
-
+
@Override
public ConstantState getConstantState() {
mNinePatchState.mChangingConfigurations = getChangingConfigurations();
@@ -361,27 +387,36 @@
return this;
}
- final static class NinePatchState extends ConstantState {
+ private final static class NinePatchState extends ConstantState {
final NinePatch mNinePatch;
final Rect mPadding;
+ final Rect mLayoutInsets;
final boolean mDither;
int mChangingConfigurations;
int mTargetDensity = DisplayMetrics.DENSITY_DEFAULT;
NinePatchState(NinePatch ninePatch, Rect padding) {
- this(ninePatch, padding, DEFAULT_DITHER);
+ this(ninePatch, padding, new Rect(), DEFAULT_DITHER);
}
- NinePatchState(NinePatch ninePatch, Rect rect, boolean dither) {
+ NinePatchState(NinePatch ninePatch, Rect padding, Rect layoutInsets) {
+ this(ninePatch, padding, layoutInsets, DEFAULT_DITHER);
+ }
+
+ NinePatchState(NinePatch ninePatch, Rect rect, Rect layoutInsets, boolean dither) {
mNinePatch = ninePatch;
mPadding = rect;
+ mLayoutInsets = layoutInsets;
mDither = dither;
}
+ // Copy constructor
+
NinePatchState(NinePatchState state) {
mNinePatch = new NinePatch(state.mNinePatch);
// Note we don't copy the padding because it is immutable.
mPadding = state.mPadding;
+ mLayoutInsets = state.mLayoutInsets;
mDither = state.mDither;
mChangingConfigurations = state.mChangingConfigurations;
mTargetDensity = state.mTargetDensity;
@@ -391,12 +426,12 @@
public Drawable newDrawable() {
return new NinePatchDrawable(this, null);
}
-
+
@Override
public Drawable newDrawable(Resources res) {
return new NinePatchDrawable(this, res);
}
-
+
@Override
public int getChangingConfigurations() {
return mChangingConfigurations;
diff --git a/include/androidfw/KeyCharacterMap.h b/include/androidfw/KeyCharacterMap.h
index 3cc1cb2..8db5781 100644
--- a/include/androidfw/KeyCharacterMap.h
+++ b/include/androidfw/KeyCharacterMap.h
@@ -49,6 +49,17 @@
KEYBOARD_TYPE_ALPHA = 3,
KEYBOARD_TYPE_FULL = 4,
KEYBOARD_TYPE_SPECIAL_FUNCTION = 5,
+ KEYBOARD_TYPE_OVERLAY = 6,
+ };
+
+ enum Format {
+ // Base keyboard layout, may contain device-specific options, such as "type" declaration.
+ FORMAT_BASE = 0,
+ // Overlay keyboard layout, more restrictive, may be published by applications,
+ // cannot override device-specific options.
+ FORMAT_OVERLAY = 1,
+ // Either base or overlay layout ok.
+ FORMAT_ANY = 2,
};
// Substitute key code and meta state for fallback action.
@@ -58,7 +69,15 @@
};
/* Loads a key character map from a file. */
- static status_t load(const String8& filename, sp<KeyCharacterMap>* outMap);
+ static status_t load(const String8& filename, Format format, sp<KeyCharacterMap>* outMap);
+
+ /* Loads a key character map from its string contents. */
+ static status_t loadContents(const String8& filename,
+ const char* contents, Format format, sp<KeyCharacterMap>* outMap);
+
+ /* Combines a base key character map and an overlay. */
+ static sp<KeyCharacterMap> combine(const sp<KeyCharacterMap>& base,
+ const sp<KeyCharacterMap>& overlay);
/* Returns an empty key character map. */
static sp<KeyCharacterMap> empty();
@@ -101,6 +120,10 @@
bool getEvents(int32_t deviceId, const char16_t* chars, size_t numChars,
Vector<KeyEvent>& outEvents) const;
+ /* Maps a scan code and usage code to a key code, in case this key map overrides
+ * the mapping in some way. */
+ status_t mapKey(int32_t scanCode, int32_t usageCode, int32_t* outKeyCode) const;
+
#if HAVE_ANDROID_OS
/* Reads a key map from a parcel. */
static sp<KeyCharacterMap> readFromParcel(Parcel* parcel);
@@ -115,6 +138,7 @@
private:
struct Behavior {
Behavior();
+ Behavior(const Behavior& other);
/* The next behavior in the list, or NULL if none. */
Behavior* next;
@@ -131,6 +155,7 @@
struct Key {
Key();
+ Key(const Key& other);
~Key();
/* The single character label printed on the key, or 0 if none. */
@@ -166,16 +191,19 @@
KeyCharacterMap* mMap;
Tokenizer* mTokenizer;
+ Format mFormat;
State mState;
int32_t mKeyCode;
public:
- Parser(KeyCharacterMap* map, Tokenizer* tokenizer);
+ Parser(KeyCharacterMap* map, Tokenizer* tokenizer, Format format);
~Parser();
status_t parse();
private:
status_t parseType();
+ status_t parseMap();
+ status_t parseMapKey();
status_t parseKey();
status_t parseKeyProperty();
status_t parseModifier(const String8& token, int32_t* outMetaState);
@@ -187,7 +215,11 @@
KeyedVector<int32_t, Key*> mKeys;
int mType;
+ KeyedVector<int32_t, int32_t> mKeysByScanCode;
+ KeyedVector<int32_t, int32_t> mKeysByUsageCode;
+
KeyCharacterMap();
+ KeyCharacterMap(const KeyCharacterMap& other);
bool getKey(int32_t keyCode, const Key** outKey) const;
bool getKeyBehavior(int32_t keyCode, int32_t metaState,
@@ -195,6 +227,8 @@
bool findKey(char16_t ch, int32_t* outKeyCode, int32_t* outMetaState) const;
+ static status_t load(Tokenizer* tokenizer, Format format, sp<KeyCharacterMap>* outMap);
+
static void addKey(Vector<KeyEvent>& outEvents,
int32_t deviceId, int32_t keyCode, int32_t metaState, bool down, nsecs_t time);
static void addMetaKeys(Vector<KeyEvent>& outEvents,
diff --git a/include/utils/Trace.h b/include/utils/Trace.h
new file mode 100644
index 0000000..a0112d0
--- /dev/null
+++ b/include/utils/Trace.h
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_TRACE_H
+#define ANDROID_TRACE_H
+
+#define ATRACE_TAG_NEVER 0 // The "never" tag is never enabled.
+#define ATRACE_TAG_ALWAYS (1<<0) // The "always" tag is always enabled.
+#define ATRACE_TAG_GRAPHICS (1<<1)
+#define ATRACE_TAG_INPUT (1<<2)
+#define ATRACE_TAG_VIEW (1<<3)
+#define ATRACE_TAG_WEBVIEW (1<<4)
+
+#define ATRACE_CALL()
+
+#define ATRACE_INT(name, value)
+
+#define ATRACE_ENABLED() false
+
+namespace android {
+
+class ScopedTrace {
+
+public:
+ inline ScopedTrace(uint64_t tag, const char* name) {}
+};
+
+}; // namespace android
+
+#endif // ANDROID_TRACE_H
diff --git a/libs/androidfw/KeyCharacterMap.cpp b/libs/androidfw/KeyCharacterMap.cpp
index 9abbf38..c8f9439 100644
--- a/libs/androidfw/KeyCharacterMap.cpp
+++ b/libs/androidfw/KeyCharacterMap.cpp
@@ -89,6 +89,14 @@
mType(KEYBOARD_TYPE_UNKNOWN) {
}
+KeyCharacterMap::KeyCharacterMap(const KeyCharacterMap& other) :
+ RefBase(), mType(other.mType), mKeysByScanCode(other.mKeysByScanCode),
+ mKeysByUsageCode(other.mKeysByUsageCode) {
+ for (size_t i = 0; i < other.mKeys.size(); i++) {
+ mKeys.add(other.mKeys.keyAt(i), new Key(*other.mKeys.valueAt(i)));
+ }
+}
+
KeyCharacterMap::~KeyCharacterMap() {
for (size_t i = 0; i < mKeys.size(); i++) {
Key* key = mKeys.editValueAt(i);
@@ -96,7 +104,8 @@
}
}
-status_t KeyCharacterMap::load(const String8& filename, sp<KeyCharacterMap>* outMap) {
+status_t KeyCharacterMap::load(const String8& filename,
+ Format format, sp<KeyCharacterMap>* outMap) {
outMap->clear();
Tokenizer* tokenizer;
@@ -104,31 +113,87 @@
if (status) {
ALOGE("Error %d opening key character map file %s.", status, filename.string());
} else {
- sp<KeyCharacterMap> map = new KeyCharacterMap();
- if (!map.get()) {
- ALOGE("Error allocating key character map.");
- status = NO_MEMORY;
- } else {
-#if DEBUG_PARSER_PERFORMANCE
- nsecs_t startTime = systemTime(SYSTEM_TIME_MONOTONIC);
-#endif
- Parser parser(map.get(), tokenizer);
- status = parser.parse();
-#if DEBUG_PARSER_PERFORMANCE
- nsecs_t elapsedTime = systemTime(SYSTEM_TIME_MONOTONIC) - startTime;
- ALOGD("Parsed key character map file '%s' %d lines in %0.3fms.",
- tokenizer->getFilename().string(), tokenizer->getLineNumber(),
- elapsedTime / 1000000.0);
-#endif
- if (!status) {
- *outMap = map;
- }
- }
+ status = load(tokenizer, format, outMap);
delete tokenizer;
}
return status;
}
+status_t KeyCharacterMap::loadContents(const String8& filename, const char* contents,
+ Format format, sp<KeyCharacterMap>* outMap) {
+ outMap->clear();
+
+ Tokenizer* tokenizer;
+ status_t status = Tokenizer::fromContents(filename, contents, &tokenizer);
+ if (status) {
+ ALOGE("Error %d opening key character map.", status);
+ } else {
+ status = load(tokenizer, format, outMap);
+ delete tokenizer;
+ }
+ return status;
+}
+
+status_t KeyCharacterMap::load(Tokenizer* tokenizer,
+ Format format, sp<KeyCharacterMap>* outMap) {
+ status_t status = OK;
+ sp<KeyCharacterMap> map = new KeyCharacterMap();
+ if (!map.get()) {
+ ALOGE("Error allocating key character map.");
+ status = NO_MEMORY;
+ } else {
+#if DEBUG_PARSER_PERFORMANCE
+ nsecs_t startTime = systemTime(SYSTEM_TIME_MONOTONIC);
+#endif
+ Parser parser(map.get(), tokenizer, format);
+ status = parser.parse();
+#if DEBUG_PARSER_PERFORMANCE
+ nsecs_t elapsedTime = systemTime(SYSTEM_TIME_MONOTONIC) - startTime;
+ ALOGD("Parsed key character map file '%s' %d lines in %0.3fms.",
+ tokenizer->getFilename().string(), tokenizer->getLineNumber(),
+ elapsedTime / 1000000.0);
+#endif
+ if (!status) {
+ *outMap = map;
+ }
+ }
+ return status;
+}
+
+sp<KeyCharacterMap> KeyCharacterMap::combine(const sp<KeyCharacterMap>& base,
+ const sp<KeyCharacterMap>& overlay) {
+ if (overlay == NULL) {
+ return base;
+ }
+ if (base == NULL) {
+ return overlay;
+ }
+
+ sp<KeyCharacterMap> map = new KeyCharacterMap(*base.get());
+ for (size_t i = 0; i < overlay->mKeys.size(); i++) {
+ int32_t keyCode = overlay->mKeys.keyAt(i);
+ Key* key = overlay->mKeys.valueAt(i);
+ ssize_t oldIndex = map->mKeys.indexOfKey(keyCode);
+ if (oldIndex >= 0) {
+ delete map->mKeys.valueAt(oldIndex);
+ map->mKeys.editValueAt(oldIndex) = new Key(*key);
+ } else {
+ map->mKeys.add(keyCode, new Key(*key));
+ }
+ }
+
+ for (size_t i = 0; i < overlay->mKeysByScanCode.size(); i++) {
+ map->mKeysByScanCode.replaceValueFor(overlay->mKeysByScanCode.keyAt(i),
+ overlay->mKeysByScanCode.valueAt(i));
+ }
+
+ for (size_t i = 0; i < overlay->mKeysByUsageCode.size(); i++) {
+ map->mKeysByUsageCode.replaceValueFor(overlay->mKeysByUsageCode.keyAt(i),
+ overlay->mKeysByUsageCode.valueAt(i));
+ }
+ return map;
+}
+
sp<KeyCharacterMap> KeyCharacterMap::empty() {
return sEmpty;
}
@@ -261,6 +326,37 @@
return true;
}
+status_t KeyCharacterMap::mapKey(int32_t scanCode, int32_t usageCode, int32_t* outKeyCode) const {
+ if (usageCode) {
+ ssize_t index = mKeysByUsageCode.indexOfKey(usageCode);
+ if (index >= 0) {
+#if DEBUG_MAPPING
+ ALOGD("mapKey: scanCode=%d, usageCode=0x%08x ~ Result keyCode=%d.",
+ scanCode, usageCode, *outKeyCode);
+#endif
+ *outKeyCode = mKeysByUsageCode.valueAt(index);
+ return OK;
+ }
+ }
+ if (scanCode) {
+ ssize_t index = mKeysByScanCode.indexOfKey(scanCode);
+ if (index >= 0) {
+#if DEBUG_MAPPING
+ ALOGD("mapKey: scanCode=%d, usageCode=0x%08x ~ Result keyCode=%d.",
+ scanCode, usageCode, *outKeyCode);
+#endif
+ *outKeyCode = mKeysByScanCode.valueAt(index);
+ return OK;
+ }
+ }
+
+#if DEBUG_MAPPING
+ ALOGD("mapKey: scanCode=%d, usageCode=0x%08x ~ Failed.", scanCode, usageCode);
+#endif
+ *outKeyCode = AKEYCODE_UNKNOWN;
+ return NAME_NOT_FOUND;
+}
+
bool KeyCharacterMap::getKey(int32_t keyCode, const Key** outKey) const {
ssize_t index = mKeys.indexOfKey(keyCode);
if (index >= 0) {
@@ -508,6 +604,11 @@
label(0), number(0), firstBehavior(NULL) {
}
+KeyCharacterMap::Key::Key(const Key& other) :
+ label(other.label), number(other.number),
+ firstBehavior(other.firstBehavior ? new Behavior(*other.firstBehavior) : NULL) {
+}
+
KeyCharacterMap::Key::~Key() {
Behavior* behavior = firstBehavior;
while (behavior) {
@@ -524,11 +625,17 @@
next(NULL), metaState(0), character(0), fallbackKeyCode(0) {
}
+KeyCharacterMap::Behavior::Behavior(const Behavior& other) :
+ next(other.next ? new Behavior(*other.next) : NULL),
+ metaState(other.metaState), character(other.character),
+ fallbackKeyCode(other.fallbackKeyCode) {
+}
+
// --- KeyCharacterMap::Parser ---
-KeyCharacterMap::Parser::Parser(KeyCharacterMap* map, Tokenizer* tokenizer) :
- mMap(map), mTokenizer(tokenizer), mState(STATE_TOP) {
+KeyCharacterMap::Parser::Parser(KeyCharacterMap* map, Tokenizer* tokenizer, Format format) :
+ mMap(map), mTokenizer(tokenizer), mFormat(format), mState(STATE_TOP) {
}
KeyCharacterMap::Parser::~Parser() {
@@ -551,6 +658,10 @@
mTokenizer->skipDelimiters(WHITESPACE);
status_t status = parseType();
if (status) return status;
+ } else if (keywordToken == "map") {
+ mTokenizer->skipDelimiters(WHITESPACE);
+ status_t status = parseMap();
+ if (status) return status;
} else if (keywordToken == "key") {
mTokenizer->skipDelimiters(WHITESPACE);
status_t status = parseKey();
@@ -588,10 +699,24 @@
return BAD_VALUE;
}
- if (mMap->mType == KEYBOARD_TYPE_UNKNOWN) {
- ALOGE("%s: Missing required keyboard 'type' declaration.",
- mTokenizer->getLocation().string());
- return BAD_VALUE;
+ if (mFormat == FORMAT_BASE) {
+ if (mMap->mType == KEYBOARD_TYPE_UNKNOWN) {
+ ALOGE("%s: Base keyboard layout missing required keyboard 'type' declaration.",
+ mTokenizer->getLocation().string());
+ return BAD_VALUE;
+ }
+ if (mMap->mType == KEYBOARD_TYPE_OVERLAY) {
+ ALOGE("%s: Base keyboard layout must specify a keyboard 'type' other than 'OVERLAY'.",
+ mTokenizer->getLocation().string());
+ return BAD_VALUE;
+ }
+ } else if (mFormat == FORMAT_OVERLAY) {
+ if (mMap->mType != KEYBOARD_TYPE_OVERLAY) {
+ ALOGE("%s: Overlay keyboard layout missing required keyboard "
+ "'type OVERLAY' declaration.",
+ mTokenizer->getLocation().string());
+ return BAD_VALUE;
+ }
}
return NO_ERROR;
@@ -616,6 +741,8 @@
type = KEYBOARD_TYPE_FULL;
} else if (typeToken == "SPECIAL_FUNCTION") {
type = KEYBOARD_TYPE_SPECIAL_FUNCTION;
+ } else if (typeToken == "OVERLAY") {
+ type = KEYBOARD_TYPE_OVERLAY;
} else {
ALOGE("%s: Expected keyboard type label, got '%s'.", mTokenizer->getLocation().string(),
typeToken.string());
@@ -629,6 +756,58 @@
return NO_ERROR;
}
+status_t KeyCharacterMap::Parser::parseMap() {
+ String8 keywordToken = mTokenizer->nextToken(WHITESPACE);
+ if (keywordToken == "key") {
+ mTokenizer->skipDelimiters(WHITESPACE);
+ return parseMapKey();
+ }
+ ALOGE("%s: Expected keyword after 'map', got '%s'.", mTokenizer->getLocation().string(),
+ keywordToken.string());
+ return BAD_VALUE;
+}
+
+status_t KeyCharacterMap::Parser::parseMapKey() {
+ String8 codeToken = mTokenizer->nextToken(WHITESPACE);
+ bool mapUsage = false;
+ if (codeToken == "usage") {
+ mapUsage = true;
+ mTokenizer->skipDelimiters(WHITESPACE);
+ codeToken = mTokenizer->nextToken(WHITESPACE);
+ }
+
+ char* end;
+ int32_t code = int32_t(strtol(codeToken.string(), &end, 0));
+ if (*end) {
+ ALOGE("%s: Expected key %s number, got '%s'.", mTokenizer->getLocation().string(),
+ mapUsage ? "usage" : "scan code", codeToken.string());
+ return BAD_VALUE;
+ }
+ KeyedVector<int32_t, int32_t>& map =
+ mapUsage ? mMap->mKeysByUsageCode : mMap->mKeysByScanCode;
+ if (map.indexOfKey(code) >= 0) {
+ ALOGE("%s: Duplicate entry for key %s '%s'.", mTokenizer->getLocation().string(),
+ mapUsage ? "usage" : "scan code", codeToken.string());
+ return BAD_VALUE;
+ }
+
+ mTokenizer->skipDelimiters(WHITESPACE);
+ String8 keyCodeToken = mTokenizer->nextToken(WHITESPACE);
+ int32_t keyCode = getKeyCodeByLabel(keyCodeToken.string());
+ if (!keyCode) {
+ ALOGE("%s: Expected key code label, got '%s'.", mTokenizer->getLocation().string(),
+ keyCodeToken.string());
+ return BAD_VALUE;
+ }
+
+#if DEBUG_PARSER
+ ALOGD("Parsed map key %s: code=%d, keyCode=%d.",
+ mapUsage ? "usage" : "scan code", code, keyCode);
+#endif
+ map.add(code, keyCode);
+ return NO_ERROR;
+}
+
status_t KeyCharacterMap::Parser::parseKey() {
String8 keyCodeToken = mTokenizer->nextToken(WHITESPACE);
int32_t keyCode = getKeyCodeByLabel(keyCodeToken.string());
diff --git a/libs/androidfw/KeyLayoutMap.cpp b/libs/androidfw/KeyLayoutMap.cpp
index a7c2199..2db19c5 100644
--- a/libs/androidfw/KeyLayoutMap.cpp
+++ b/libs/androidfw/KeyLayoutMap.cpp
@@ -199,17 +199,26 @@
}
status_t KeyLayoutMap::Parser::parseKey() {
- String8 scanCodeToken = mTokenizer->nextToken(WHITESPACE);
+ String8 codeToken = mTokenizer->nextToken(WHITESPACE);
+ bool mapUsage = false;
+ if (codeToken == "usage") {
+ mapUsage = true;
+ mTokenizer->skipDelimiters(WHITESPACE);
+ codeToken = mTokenizer->nextToken(WHITESPACE);
+ }
+
char* end;
- int32_t scanCode = int32_t(strtol(scanCodeToken.string(), &end, 0));
+ int32_t code = int32_t(strtol(codeToken.string(), &end, 0));
if (*end) {
- ALOGE("%s: Expected key scan code number, got '%s'.", mTokenizer->getLocation().string(),
- scanCodeToken.string());
+ ALOGE("%s: Expected key %s number, got '%s'.", mTokenizer->getLocation().string(),
+ mapUsage ? "usage" : "scan code", codeToken.string());
return BAD_VALUE;
}
- if (mMap->mKeysByScanCode.indexOfKey(scanCode) >= 0) {
- ALOGE("%s: Duplicate entry for key scan code '%s'.", mTokenizer->getLocation().string(),
- scanCodeToken.string());
+ KeyedVector<int32_t, Key>& map =
+ mapUsage ? mMap->mKeysByUsageCode : mMap->mKeysByScanCode;
+ if (map.indexOfKey(code) >= 0) {
+ ALOGE("%s: Duplicate entry for key %s '%s'.", mTokenizer->getLocation().string(),
+ mapUsage ? "usage" : "scan code", codeToken.string());
return BAD_VALUE;
}
@@ -243,12 +252,13 @@
}
#if DEBUG_PARSER
- ALOGD("Parsed key: scanCode=%d, keyCode=%d, flags=0x%08x.", scanCode, keyCode, flags);
+ ALOGD("Parsed key %s: code=%d, keyCode=%d, flags=0x%08x.",
+ mapUsage ? "usage" : "scan code", code, keyCode, flags);
#endif
Key key;
key.keyCode = keyCode;
key.flags = flags;
- mMap->mKeysByScanCode.add(scanCode, key);
+ map.add(code, key);
return NO_ERROR;
}
diff --git a/libs/androidfw/Keyboard.cpp b/libs/androidfw/Keyboard.cpp
index a84a8c7..4ddbeab 100644
--- a/libs/androidfw/Keyboard.cpp
+++ b/libs/androidfw/Keyboard.cpp
@@ -129,7 +129,8 @@
return NAME_NOT_FOUND;
}
- status_t status = KeyCharacterMap::load(path, &keyCharacterMap);
+ status_t status = KeyCharacterMap::load(path,
+ KeyCharacterMap::FORMAT_BASE, &keyCharacterMap);
if (status) {
return status;
}
diff --git a/media/java/android/media/Crypto.java b/media/java/android/media/Crypto.java
deleted file mode 100644
index 43e34fb..0000000
--- a/media/java/android/media/Crypto.java
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- * Copyright (C) 2012 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.media;
-
-/**
- * Crypto class can be used in conjunction with MediaCodec to decode
- * encrypted media data.
- * @hide
-*/
-public final class Crypto {
- public static final native boolean isCryptoSchemeSupported(byte[] uuid);
-
- public Crypto(byte[] uuid, byte[] initData) {
- native_setup(uuid, initData);
- }
-
- public final native boolean requiresSecureDecoderComponent(String mime);
-
- @Override
- protected void finalize() {
- native_finalize();
- }
-
- public native final void release();
- private static native final void native_init();
- private native final void native_setup(byte[] uuid, byte[] initData);
- private native final void native_finalize();
-
- static {
- System.loadLibrary("media_jni");
- native_init();
- }
-
- private int mNativeContext;
-}
diff --git a/media/java/android/media/MediaCodec.java b/media/java/android/media/MediaCodec.java
index 410383d..2efacd8 100644
--- a/media/java/android/media/MediaCodec.java
+++ b/media/java/android/media/MediaCodec.java
@@ -16,7 +16,7 @@
package android.media;
-import android.media.Crypto;
+import android.media.MediaCrypto;
import android.view.Surface;
import java.nio.ByteBuffer;
import java.util.Map;
@@ -24,7 +24,122 @@
/**
* MediaCodec class can be used to access low-level media codec, i.e.
* encoder/decoder components.
- * @hide
+ *
+ * <p>MediaCodec is generally used like this:
+ * <pre>
+ * MediaCodec codec = MediaCodec.createDecoderByType(type);
+ * codec.configure(format, ...);
+ * codec.start();
+ * ByteBuffer[] inputBuffers = codec.getInputBuffers();
+ * ByteBuffer[] outputBuffers = codec.getOutputBuffers();
+ * Map<String, Object> format = codec.getOutputFormat();
+ * for (;;) {
+ * int inputBufferIndex = codec.dequeueInputBuffer(timeoutUs);
+ * if (inputBufferIndex >= 0) {
+ * // fill inputBuffers[inputBufferIndex] with valid data
+ * ...
+ * codec.queueInputBuffer(inputBufferIndex, ...);
+ * }
+ *
+ * int outputBufferIndex = codec.dequeueOutputBuffer(timeoutUs);
+ * if (outputBufferIndex >= 0) {
+ * // outputBuffer is ready to be processed or rendered.
+ * ...
+ * codec.releaseOutputBuffer(outputBufferIndex, ...);
+ * } else if (outputBufferIndex == MediaCodec.INFO_OUTPUT_BUFFERS_CHANGED) {
+ * outputBuffers = codec.getOutputBuffers();
+ * } else if (outputBufferIndex == MediaCodec.INFO_OUTPUT_FORMAT_CHANGED) {
+ * // Subsequent data will conform to new format.
+ * format = codec.getOutputFormat();
+ * ...
+ * }
+ * }
+ * codec.stop();
+ * codec.release();
+ * codec = null;
+ * </pre>
+ *
+ * Each codec maintains a number of input and output buffers that are
+ * referred to by index in API calls.
+ * The contents of these buffers is represented by the ByteBuffer[] arrays
+ * accessible through getInputBuffers() and getOutputBuffers().
+ *
+ * After a successful call to {@link #start} the client "owns" neither
+ * input nor output buffers, subsequent calls to {@link #dequeueInputBuffer}
+ * and {@link #dequeueOutputBuffer} then transfer ownership from the codec
+ * to the client.<p>
+ * The client is not required to resubmit/release buffers immediately
+ * to the codec, the sample code above simply does this for simplicity's sake.<p>
+ * Once the client has an input buffer available it can fill it with data
+ * and submit it it to the codec via a call to {@link #queueInputBuffer}.<p>
+ * The codec in turn will return an output buffer to the client in response
+ * to {@link #dequeueOutputBuffer}. After the output buffer has been processed
+ * a call to {@link #releaseOutputBuffer} will return it to the codec.
+ * If a video surface has been provided in the call to {@link #configure},
+ * {@link #releaseOutputBuffer} optionally allows rendering of the buffer
+ * to the surface.<p>
+ *
+ * Input buffers (for decoders) and Output buffers (for encoders) contain
+ * encoded data according to the format's type. For video types this data
+ * is all the encoded data representing a single moment in time, for audio
+ * data this is slightly relaxed in that a buffer may contain multiple
+ * encoded frames of audio. In either case, buffers do not start and end on
+ * arbitrary byte boundaries, this is not a stream of bytes, it's a stream
+ * of access units.<p>
+ *
+ * Most formats also require the actual data to be prefixed by a number
+ * of buffers containing setup data, or codec specific data, i.e. the
+ * first few buffers submitted to the codec object after starting it must
+ * be codec specific data marked as such using the flag {@link #FLAG_CODECCONFIG}
+ * in a call to {@link #queueInputBuffer}.
+ *
+ * Once the client reaches the end of the input data it signals the end of
+ * the input stream by specifying a flag of {@link #FLAG_EOS} in the call to
+ * {@link #queueInputBuffer}. The codec will continue to return output buffers
+ * until it eventually signals the end of the output stream by specifying
+ * the same flag ({@link #FLAG_EOS}) on the BufferInfo returned in
+ * {@link #dequeueOutputBuffer}.
+ *
+ * In order to start decoding data that's not adjacent to previously submitted
+ * data (i.e. after a seek) it is necessary to {@link #flush} the decoder.
+ * Any input or output buffers the client may own at the point of the flush are
+ * immediately revoked, i.e. after a call to {@link #flush} the client does not
+ * own any buffers anymore.
+ * Note that the format of the data submitted after a flush must not change,
+ * flush does not support format discontinuities,
+ * for this a full stop(), configure(), start() cycle is necessary.
+ *
+ * The format of the media data is specified as string/value pairs represented
+ * as a Map<String, Object>.<p>
+ *
+ * Fields common to all formats:
+ *
+ * <table>
+ * <tr><th>Name</th><th>Value Type</th><th>Description</th></tr>
+ * <tr><td>mime</td><td>String</td><td>The type of the format.</td></tr>
+ * <tr><td>max-input-size</td><td>Integer</td><td>optional, maximum size of a buffer of input data</td></tr>
+ * <tr><td>bitrate</td><td>Integer</td><td><b>encoder-only</b>, desired bitrate in bits/second</td></tr>
+ * </table>
+ *
+ * Video formats have the following fields:
+ * <table>
+ * <tr><th>Name</th><th>Value Type</th><th>Description</th></tr>
+ * <tr><td>width</td><td>Integer</td><td></td></tr>
+ * <tr><td>height</td><td>Integer</td><td></td></tr>
+ * <tr><td>color-format</td><td>Integer</td><td><b>encoder-only</b></td></tr>
+ * <tr><td>frame-rate</td><td>Integer or Float</td><td><b>encoder-only</b></td></tr>
+ * <tr><td>i-frame-interval</td><td>Integer</td><td><b>encoder-only</b></td></tr>
+ * <tr><td>stride</td><td>Integer</td><td><b>encoder-only</b>, optional, defaults to width</td></tr>
+ * <tr><td>slice-height</td><td>Integer</td><td><b>encoder-only</b>, optional, defaults to height</td></tr>
+ * </table>
+ *
+ * Audio formats have the following fields:
+ * <table>
+ * <tr><th>Name</th><th>Value Type</th><th>Description</th></tr>
+ * <tr><td>channel-count</td><td>Integer</td><td></td></tr>
+ * <tr><td>sample-rate</td><td>Integer</td><td></td></tr>
+ * </table>
+ *
*/
final public class MediaCodec {
/** Per buffer metadata includes an offset and size specifying
@@ -32,43 +147,62 @@
*/
public final static class BufferInfo {
public void set(
- int offset, int size, long timeUs, int flags) {
- mOffset = offset;
- mSize = size;
- mPresentationTimeUs = timeUs;
- mFlags = flags;
+ int newOffset, int newSize, long newTimeUs, int newFlags) {
+ offset = newOffset;
+ size = newSize;
+ presentationTimeUs = newTimeUs;
+ flags = newFlags;
}
- public int mOffset;
- public int mSize;
- public long mPresentationTimeUs;
- public int mFlags;
+ public int offset;
+ public int size;
+ public long presentationTimeUs;
+ public int flags;
};
// The follow flag constants MUST stay in sync with their equivalents
// in MediaCodec.h !
- public static int FLAG_SYNCFRAME = 1;
- public static int FLAG_CODECCONFIG = 2;
- public static int FLAG_EOS = 4;
+
+ /** This indicates that the buffer marked as such contains the data
+ for a sync frame.
+ */
+ public static final int FLAG_SYNCFRAME = 1;
+
+ /** This indicated that the buffer marked as such contains codec
+ initialization / codec specific data instead of media data.
+ */
+ public static final int FLAG_CODECCONFIG = 2;
+
+ /** This signals the end of stream, i.e. no buffers will be available
+ after this, unless of course, {@link #flush} follows.
+ */
+ public static final int FLAG_EOS = 4;
// The following mode constants MUST stay in sync with their equivalents
// in media/hardware/CryptoAPI.h !
- public static int MODE_UNENCRYPTED = 0;
- public static int MODE_AES_CTR = 1;
+ public static final int MODE_UNENCRYPTED = 0;
+ public static final int MODE_AES_CTR = 1;
- /** Instantiate a codec component by mime type. For decoder components
- this is the mime type of media that this decoder should be able to
- decoder, for encoder components it's the type of media this encoder
- should encode _to_.
+ /** Instantiate a decoder supporting input data of the given mime type.
+ * @param type The mime type of the input data.
*/
- public static MediaCodec CreateByType(String type, boolean encoder) {
- return new MediaCodec(type, true /* nameIsType */, encoder);
+ public static MediaCodec createDecoderByType(String type) {
+ return new MediaCodec(type, true /* nameIsType */, false /* encoder */);
+ }
+
+ /** Instantiate an encoder supporting output data of the given mime type.
+ * @param type The desired mime type of the output data.
+ */
+ public static MediaCodec createEncoderByType(String type) {
+ return new MediaCodec(type, true /* nameIsType */, true /* encoder */);
}
/** If you know the exact name of the component you want to instantiate
use this method to instantiate it. Use with caution.
+ Likely to be used with information obtained from {@link android.media.MediaCodecList}
+ @param name The name of the codec to be instantiated.
*/
- public static MediaCodec CreateByComponentName(String name) {
+ public static MediaCodec createByCodecName(String name) {
return new MediaCodec(
name, false /* nameIsType */, false /* unused */);
}
@@ -88,35 +222,14 @@
// to do this for you at some point in the future.
public native final void release();
+ /** If this codec is to be used as an encoder, pass this flag.
+ */
public static int CONFIGURE_FLAG_ENCODE = 1;
/** Configures a component.
- * @param format A map of string/value pairs describing the input format
- * (decoder) or the desired output format.
*
- * Video formats have the following fields:
- * "mime" - String
- * "width" - Integer
- * "height" - Integer
- * optional "max-input-size" - Integer
- *
- * Audio formats have the following fields:
- * "mime" - String
- * "channel-count" - Integer
- * "sample-rate" - Integer
- * optional "max-input-size" - Integer
- *
- * If the format is used to configure an encoder, additional
- * fields must be included:
- * "bitrate" - Integer (in bits/sec)
- *
- * for video formats:
- * "color-format" - Integer
- * "frame-rate" - Integer or Float
- * "i-frame-interval" - Integer
- * optional "stride" - Integer, defaults to "width"
- * optional "slice-height" - Integer, defaults to "height"
- *
+ * @param format The format of the input data (decoder) or the desired
+ * format of the output data (encoder).
* @param surface Specify a surface on which to render the output of this
* decoder.
* @param crypto Specify a crypto object to facilitate secure decryption
@@ -126,7 +239,7 @@
*/
public void configure(
Map<String, Object> format,
- Surface surface, Crypto crypto, int flags) {
+ Surface surface, MediaCrypto crypto, int flags) {
String[] keys = null;
Object[] values = null;
@@ -147,18 +260,23 @@
private native final void native_configure(
String[] keys, Object[] values,
- Surface surface, Crypto crypto, int flags);
+ Surface surface, MediaCrypto crypto, int flags);
/** After successfully configuring the component, call start. On return
* you can query the component for its input/output buffers.
*/
public native final void start();
+ /** Finish the decode/encode session, note that the codec instance
+ * remains active and ready to be {@link #start}ed again.
+ * To ensure that it is available to other client call {@link #release}
+ * and don't just rely on garbage collection to eventually do this for you.
+ */
public native final void stop();
/** Flush both input and output ports of the component, all indices
- * previously returned in calls to dequeueInputBuffer and
- * dequeueOutputBuffer become invalid.
+ * previously returned in calls to {@link #dequeueInputBuffer} and
+ * {@link #dequeueOutputBuffer} become invalid.
*/
public native final void flush();
@@ -169,70 +287,124 @@
* preceded by "codec specific data", i.e. setup data used to initialize
* the codec such as PPS/SPS in the case of AVC video or code tables
* in the case of vorbis audio.
- * The class MediaExtractor provides codec specific data as part of
+ * The class {@link android.media.MediaExtractor} provides codec
+ * specific data as part of
* the returned track format in entries named "csd-0", "csd-1" ...
*
* These buffers should be submitted using the flag {@link #FLAG_CODECCONFIG}.
*
* To indicate that this is the final piece of input data (or rather that
* no more input data follows unless the decoder is subsequently flushed)
- * specify the flag {@link FLAG_EOS}.
+ * specify the flag {@link #FLAG_EOS}.
+ *
+ * @param index The index of a client-owned input buffer previously returned
+ * in a call to {@link #dequeueInputBuffer}.
+ * @param offset The byte offset into the input buffer at which the data starts.
+ * @param size The number of bytes of valid input data.
+ * @param presentationTimeUs The time at which this buffer should be rendered.
+ * @param flags A bitmask of flags {@link #FLAG_SYNCFRAME},
+ * {@link #FLAG_CODECCONFIG} or {@link #FLAG_EOS}.
*/
public native final void queueInputBuffer(
int index,
int offset, int size, long presentationTimeUs, int flags);
- /** Similar to {@link queueInputBuffer} but submits a buffer that is
- * potentially encrypted. The buffer's data is considered to be
- * partitioned into "subSamples", each subSample starts with a
- * (potentially empty) run of plain, unencrypted bytes followed
- * by a (also potentially empty) run of encrypted bytes.
- * @param numBytesOfClearData The number of leading unencrypted bytes in
- * each subSample.
- * @param numBytesOfEncryptedData The number of trailing encrypted bytes
- * in each subSample.
- * @param numSubSamples The number of subSamples that make up the
- * buffer's contents.
- * @param key A 16-byte opaque key
- * @param iv A 16-byte initialization vector
- * @param mode The type of encryption that has been applied
- *
- * Either numBytesOfClearData or numBytesOfEncryptedData (but not both)
- * can be null to indicate that all respective sizes are 0.
+ /** Metadata describing the structure of a (at least partially) encrypted
+ * input sample.
+ * A buffer's data is considered to be partitioned into "subSamples",
+ * each subSample starts with a (potentially empty) run of plain,
+ * unencrypted bytes followed by a (also potentially empty) run of
+ * encrypted bytes.
+ * numBytesOfClearData can be null to indicate that all data is encrypted.
+ */
+ public final static class CryptoInfo {
+ public void set(
+ int newNumSubSamples,
+ int[] newNumBytesOfClearData,
+ int[] newNumBytesOfEncryptedData,
+ byte[] newKey,
+ byte[] newIV,
+ int newMode) {
+ numSubSamples = newNumSubSamples;
+ numBytesOfClearData = newNumBytesOfClearData;
+ numBytesOfEncryptedData = newNumBytesOfEncryptedData;
+ key = newKey;
+ iv = newIV;
+ mode = newMode;
+ }
+
+ /** The number of subSamples that make up the buffer's contents. */
+ public int numSubSamples;
+ /** The number of leading unencrypted bytes in each subSample. */
+ public int[] numBytesOfClearData;
+ /** The number of trailing encrypted bytes in each subSample. */
+ public int[] numBytesOfEncryptedData;
+ /** A 16-byte opaque key */
+ public byte[] key;
+ /** A 16-byte initialization vector */
+ public byte[] iv;
+ /** The type of encryption that has been applied */
+ public int mode;
+ };
+
+ /** Similar to {@link #queueInputBuffer} but submits a buffer that is
+ * potentially encrypted.
+ * @param index The index of a client-owned input buffer previously returned
+ * in a call to {@link #dequeueInputBuffer}.
+ * @param offset The byte offset into the input buffer at which the data starts.
+ * @param presentationTimeUs The time at which this buffer should be rendered.
+ * @param flags A bitmask of flags {@link #FLAG_SYNCFRAME},
+ * {@link #FLAG_CODECCONFIG} or {@link #FLAG_EOS}.
*/
public native final void queueSecureInputBuffer(
int index,
int offset,
- int[] numBytesOfClearData,
- int[] numBytesOfEncryptedData,
- int numSubSamples,
- byte[] key,
- byte[] iv,
- int mode,
+ CryptoInfo info,
long presentationTimeUs,
int flags);
- // Returns the index of an input buffer to be filled with valid data
- // or -1 if no such buffer is currently available.
- // This method will return immediately if timeoutUs == 0, wait indefinitely
- // for the availability of an input buffer if timeoutUs < 0 or wait up
- // to "timeoutUs" microseconds if timeoutUs > 0.
+ /** Returns the index of an input buffer to be filled with valid data
+ * or -1 if no such buffer is currently available.
+ * This method will return immediately if timeoutUs == 0, wait indefinitely
+ * for the availability of an input buffer if timeoutUs < 0 or wait up
+ * to "timeoutUs" microseconds if timeoutUs > 0.
+ * @param timeoutUs The timeout in microseconds, a negative timeout indicates "infinite".
+ */
public native final int dequeueInputBuffer(long timeoutUs);
- // Returns the index of an output buffer that has been successfully
- // decoded or one of the INFO_* constants below.
- // The provided "info" will be filled with buffer meta data.
+ /** If a non-negative timeout had been specified in the call
+ * to {@link #dequeueOutputBuffer}, indicates that the call timed out.
+ */
public static final int INFO_TRY_AGAIN_LATER = -1;
+
+ /** The output format has changed, subsequent data will follow the new
+ * format. {@link #getOutputFormat} returns the new format.
+ */
public static final int INFO_OUTPUT_FORMAT_CHANGED = -2;
+
+ /** The output buffers have changed, the client must refer to the new
+ * set of output buffers returned by {@link #getOutputBuffers} from
+ * this point on.
+ */
public static final int INFO_OUTPUT_BUFFERS_CHANGED = -3;
- /** Dequeue an output buffer, block at most "timeoutUs" microseconds. */
+ /** Dequeue an output buffer, block at most "timeoutUs" microseconds.
+ * Returns the index of an output buffer that has been successfully
+ * decoded or one of the INFO_* constants below.
+ * @param info Will be filled with buffer meta data.
+ * @param timeoutUs The timeout in microseconds, a negative timeout indicates "infinite".
+ */
public native final int dequeueOutputBuffer(
BufferInfo info, long timeoutUs);
- // If you are done with a buffer, use this call to return the buffer to
- // the codec. If you previously specified a surface when configuring this
- // video decoder you can optionally render the buffer.
+ /** If you are done with a buffer, use this call to return the buffer to
+ * the codec. If you previously specified a surface when configuring this
+ * video decoder you can optionally render the buffer.
+ * @param index The index of a client-owned output buffer previously returned
+ * in a call to {@link #dequeueOutputBuffer}.
+ * @param render If a valid surface was specified when configuring the codec,
+ * passing true renders this output buffer to the surface.
+ */
public native final void releaseOutputBuffer(int index, boolean render);
/** Call this after dequeueOutputBuffer signals a format change by returning
diff --git a/media/java/android/media/MediaCodecList.java b/media/java/android/media/MediaCodecList.java
index b46ce96..1772e9c 100644
--- a/media/java/android/media/MediaCodecList.java
+++ b/media/java/android/media/MediaCodecList.java
@@ -20,22 +20,42 @@
* MediaCodecList class can be used to enumerate available codecs,
* find a codec supporting a given format and query the capabilities
* of a given codec.
- * @hide
*/
final public class MediaCodecList {
+ /** Count the number of available codecs.
+ */
public static native final int countCodecs();
+
+ /** Retrieve the codec name at the specified index. */
public static native final String getCodecName(int index);
+
+ /** Query if the codec at the specified index is an encoder. */
public static native final boolean isEncoder(int index);
+
+ /** Query the media types supported by the codec at the specified index */
public static native final String[] getSupportedTypes(int index);
public static final class CodecProfileLevel {
- public int mProfile;
- public int mLevel;
+ /** Defined in the OpenMAX IL specs, depending on the type of media
+ * this can be OMX_VIDEO_AVCPROFILETYPE, OMX_VIDEO_H263PROFILETYPE
+ * or OMX_VIDEO_MPEG4PROFILETYPE.
+ */
+ public int profile;
+
+ /** Defined in the OpenMAX IL specs, depending on the type of media
+ * this can be OMX_VIDEO_AVCLEVELTYPE, OMX_VIDEO_H263LEVELTYPE
+ * or OMX_VIDEO_MPEG4LEVELTYPE.
+ */
+ public int level;
};
public static final class CodecCapabilities {
- public CodecProfileLevel[] mProfileLevels;
- public int[] mColorFormats;
+ public CodecProfileLevel[] profileLevels;
+
+ /** Defined in the OpenMAX IL specs, color format values are drawn from
+ * OMX_COLOR_FORMATTYPE.
+ */
+ public int[] colorFormats;
};
public static native final CodecCapabilities getCodecCapabilities(
int index, String type);
diff --git a/media/java/android/media/MediaCrypto.java b/media/java/android/media/MediaCrypto.java
new file mode 100644
index 0000000..b84ed72
--- /dev/null
+++ b/media/java/android/media/MediaCrypto.java
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2012 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.media;
+
+/**
+ * MediaCrypto class can be used in conjunction with {@link android.media.MediaCodec}
+ * to decode encrypted media data.
+ *
+ * Crypto schemes are assigned 16 byte UUIDs,
+ * the method {@link #isCryptoSchemeSupported} can be used to query if a given
+ * scheme is supported on the device.
+ *
+*/
+public final class MediaCrypto {
+ /** Query if the given scheme identified by its UUID is supported on
+ * this device.
+ * @param uuid The UUID of the crypto scheme.
+ */
+ public static final native boolean isCryptoSchemeSupported(byte[] uuid);
+
+ /** Instantiate a MediaCrypto object using opaque, crypto scheme specific
+ * data.
+ * @param uuid The UUID of the crypto scheme.
+ * @param initData Opaque initialization data specific to the crypto scheme.
+ */
+ public MediaCrypto(byte[] uuid, byte[] initData) throws RuntimeException {
+ native_setup(uuid, initData);
+ }
+
+ /** Query if the crypto scheme requires the use of a secure decoder
+ * to decode data of the given mime type.
+ * @param mime The mime type of the media data
+ */
+ public final native boolean requiresSecureDecoderComponent(String mime);
+
+ @Override
+ protected void finalize() {
+ native_finalize();
+ }
+
+ public native final void release();
+ private static native final void native_init();
+ private native final void native_setup(byte[] uuid, byte[] initData);
+ private native final void native_finalize();
+
+ static {
+ System.loadLibrary("media_jni");
+ native_init();
+ }
+
+ private int mNativeContext;
+}
diff --git a/media/java/android/media/MediaExtractor.java b/media/java/android/media/MediaExtractor.java
index 9c3b6a7..3b17a7d 100644
--- a/media/java/android/media/MediaExtractor.java
+++ b/media/java/android/media/MediaExtractor.java
@@ -16,63 +16,237 @@
package android.media;
+import android.content.ContentResolver;
+import android.content.Context;
+import android.content.res.AssetFileDescriptor;
+import android.media.MediaCodec;
+import android.net.Uri;
+import java.io.FileDescriptor;
+import java.io.IOException;
import java.nio.ByteBuffer;
import java.util.Map;
/**
- * MediaExtractor
- * @hide
+ * MediaExtractor facilitates extraction of demuxed, typically encoded, media data
+ * from a data source.
+ * <p>It is generally used like this:
+ * <pre>
+ * MediaExtractor extractor = new MediaExtractor();
+ * extractor.setDataSource(...);
+ * int numTracks = extractor.countTracks();
+ * for (int i = 0; i < numTracks; ++i) {
+ * Map%lt;String, Object> format = extractor.getTrackFormat(i);
+ * String mime = (String)format.get("mime");
+ * if (weAreInterestedInThisTrack) {
+ * extractor.selectTrack(i);
+ * }
+ * }
+ * ByteBuffer inputBuffer = ByteBuffer.allocate(...)
+ * while (extractor.readSampleData(inputBuffer, ...) >= 0) {
+ * int trackIndex = extractor.getTrackIndex();
+ * long presentationTimeUs = extractor.getSampleTime();
+ * ...
+ * extractor.advance();
+ * }
+ *
+ * extractor.release();
+ * extractor = null;
+ * </pre>
*/
final public class MediaExtractor {
- public MediaExtractor(String path) {
- native_setup(path);
+ public MediaExtractor() {
+ native_setup();
}
+ /**
+ * Sets the data source as a content Uri.
+ *
+ * @param context the Context to use when resolving the Uri
+ * @param uri the Content URI of the data you want to extract from.
+ * @param headers the headers to be sent together with the request for the data
+ */
+ public final void setDataSource(
+ Context context, Uri uri, Map<String, String> headers)
+ throws IOException {
+ String scheme = uri.getScheme();
+ if(scheme == null || scheme.equals("file")) {
+ setDataSource(uri.getPath());
+ return;
+ }
+
+ AssetFileDescriptor fd = null;
+ try {
+ ContentResolver resolver = context.getContentResolver();
+ fd = resolver.openAssetFileDescriptor(uri, "r");
+ if (fd == null) {
+ return;
+ }
+ // Note: using getDeclaredLength so that our behavior is the same
+ // as previous versions when the content provider is returning
+ // a full file.
+ if (fd.getDeclaredLength() < 0) {
+ setDataSource(fd.getFileDescriptor());
+ } else {
+ setDataSource(
+ fd.getFileDescriptor(),
+ fd.getStartOffset(),
+ fd.getDeclaredLength());
+ }
+ return;
+ } catch (SecurityException ex) {
+ } catch (IOException ex) {
+ } finally {
+ if (fd != null) {
+ fd.close();
+ }
+ }
+
+ setDataSource(uri.toString(), headers);
+ }
+
+ /**
+ * Sets the data source (file-path or http URL) to use.
+ *
+ * @param path the path of the file, or the http URL
+ * @param headers the headers associated with the http request for the stream you want to play
+ */
+ public final void setDataSource(String path, Map<String, String> headers) {
+ String[] keys = null;
+ String[] values = null;
+
+ if (headers != null) {
+ keys = new String[headers.size()];
+ values = new String[headers.size()];
+
+ int i = 0;
+ for (Map.Entry<String, String> entry: headers.entrySet()) {
+ keys[i] = entry.getKey();
+ values[i] = entry.getValue();
+ ++i;
+ }
+ }
+ setDataSource(path, keys, values);
+ }
+
+ private native final void setDataSource(
+ String path, String[] keys, String[] values);
+
+ /**
+ * Sets the data source (file-path or http URL) to use.
+ *
+ * @param path the path of the file, or the http URL of the stream
+ *
+ * <p>When <code>path</code> refers to a local file, the file may actually be opened by a
+ * process other than the calling application. This implies that the pathname
+ * should be an absolute path (as any other process runs with unspecified current working
+ * directory), and that the pathname should reference a world-readable file.
+ * As an alternative, the application could first open the file for reading,
+ * and then use the file descriptor form {@link #setDataSource(FileDescriptor)}.
+ */
+ public final void setDataSource(String path) {
+ setDataSource(path, null, null);
+ }
+
+ /**
+ * Sets the data source (FileDescriptor) to use. It is the caller's responsibility
+ * to close the file descriptor. It is safe to do so as soon as this call returns.
+ *
+ * @param fd the FileDescriptor for the file you want to extract from.
+ */
+ public final void setDataSource(FileDescriptor fd) {
+ setDataSource(fd, 0, 0x7ffffffffffffffL);
+ }
+
+ /**
+ * Sets the data source (FileDescriptor) to use. The FileDescriptor must be
+ * seekable (N.B. a LocalSocket is not seekable). It is the caller's responsibility
+ * to close the file descriptor. It is safe to do so as soon as this call returns.
+ *
+ * @param fd the FileDescriptor for the file you want to extract from.
+ * @param offset the offset into the file where the data to be extracted starts, in bytes
+ * @param length the length in bytes of the data to be extracted
+ */
+ public native final void setDataSource(
+ FileDescriptor fd, long offset, long length);
+
@Override
protected void finalize() {
native_finalize();
}
- // Make sure you call this when you're done to free up any resources
- // instead of relying on the garbage collector to do this for you at
- // some point in the future.
+ /** Make sure you call this when you're done to free up any resources
+ * instead of relying on the garbage collector to do this for you at
+ * some point in the future.
+ */
public native final void release();
+ /** Count the number of tracks found in the data source.
+ */
public native int countTracks();
+
+ /** Get the track format at the specified index.
+ * More detail on the representation can be found at {@link android.media.MediaCodec}
+ */
public native Map<String, Object> getTrackFormat(int index);
- // Subsequent calls to "readSampleData", "getSampleTrackIndex" and
- // "getSampleTime" only retrieve information for the subset of tracks
- // selected by the call below.
- // Selecting the same track multiple times has no effect, the track
- // is only selected once.
+ /** Subsequent calls to {@link #readSampleData}, {@link #getSampleTrackIndex} and
+ * {@link #getSampleTime} only retrieve information for the subset of tracks
+ * selected by the call below.
+ * Selecting the same track multiple times has no effect, the track
+ * only selected once.
+ * Media data will be returned in the order of their timestamps.
+ */
public native void selectTrack(int index);
- // All selected tracks seek near the requested time. The next sample
- // returned for each selected track will be a sync sample.
+ /** All selected tracks seek near the requested time. The next sample
+ * returned for each selected track will be a sync sample.
+ */
public native void seekTo(long timeUs);
+ /** Advance to the next sample. Returns false if no more sample data
+ * is available (end of stream).
+ */
public native boolean advance();
- // Retrieve the current encoded sample and store it in the byte buffer
- // starting at the given offset. Returns the sample size.
+ /** Retrieve the current encoded sample and store it in the byte buffer
+ * starting at the given offset. Returns the sample size (or -1 if
+ * no more samples are available).
+ */
public native int readSampleData(ByteBuffer byteBuf, int offset);
- // Returns the track index the current sample originates from.
+ /** Returns the track index the current sample originates from (or -1
+ * if no more samples are available)
+ */
public native int getSampleTrackIndex();
- // Returns the current sample's presentation time in microseconds.
+ /** Returns the current sample's presentation time in microseconds.
+ * or -1 if no more samples are available.
+ */
public native long getSampleTime();
// Keep these in sync with their equivalents in NuMediaExtractor.h
+ /** The sample is a sync sample */
public static final int SAMPLE_FLAG_SYNC = 1;
+
+ /** The sample is (at least partially) encrypted, see also the documentation
+ * for {@link android.media.MediaCodec#queueSecureInputBuffer}
+ */
public static final int SAMPLE_FLAG_ENCRYPTED = 2;
- // Returns the current sample's flags.
+ /** Returns the current sample's flags. */
public native int getSampleFlags();
+ /** If the sample flags indicate that the current sample is at least
+ * partially encrypted, this call returns relevant information about
+ * the structure of the sample data required for decryption.
+ * @param info The android.media.MediaCodec.CryptoInfo structure
+ * to be filled in.
+ * @return true iff the sample flags contain {@link #SAMPLE_FLAG_ENCRYPTED}
+ */
+ public native boolean getSampleCryptoInfo(MediaCodec.CryptoInfo info);
+
private static native final void native_init();
- private native final void native_setup(String path);
+ private native final void native_setup();
private native final void native_finalize();
static {
diff --git a/media/java/android/media/MediaPlayer.java b/media/java/android/media/MediaPlayer.java
index dd01db6..545752c 100644
--- a/media/java/android/media/MediaPlayer.java
+++ b/media/java/android/media/MediaPlayer.java
@@ -1619,18 +1619,22 @@
// FIXME: define error codes and throws exceptions according to the error codes.
// (IllegalStateException, IOException).
public void addExternalSource(String path, String mimeType)
- throws IllegalArgumentException {
+ throws IOException, IllegalArgumentException {
if (!availableMimeTypeForExternalSource(mimeType)) {
- throw new IllegalArgumentException("Illegal mimeType for external source: " + mimeType);
+ final String msg = "Illegal mimeType for external source: " + mimeType;
+ throw new IllegalArgumentException(msg);
}
- Parcel request = Parcel.obtain();
- Parcel reply = Parcel.obtain();
- request.writeInterfaceToken(IMEDIA_PLAYER);
- request.writeInt(INVOKE_ID_ADD_EXTERNAL_SOURCE);
- request.writeString(path);
- request.writeString(mimeType);
- invoke(request, reply);
+ File file = new File(path);
+ if (file.exists()) {
+ FileInputStream is = new FileInputStream(file);
+ FileDescriptor fd = is.getFD();
+ addExternalSource(fd, mimeType);
+ is.close();
+ } else {
+ // We do not support the case where the path is not a file.
+ throw new IOException(path);
+ }
}
/**
@@ -1671,8 +1675,6 @@
fd.close();
}
}
-
- // TODO: try server side.
}
/* Do not change these values without updating their counterparts
@@ -1732,6 +1734,7 @@
if (!availableMimeTypeForExternalSource(mimeType)) {
throw new IllegalArgumentException("Illegal mimeType for external source: " + mimeType);
}
+
Parcel request = Parcel.obtain();
Parcel reply = Parcel.obtain();
request.writeInterfaceToken(IMEDIA_PLAYER);
diff --git a/media/jni/Android.mk b/media/jni/Android.mk
index a3361d4..98e1bc5 100644
--- a/media/jni/Android.mk
+++ b/media/jni/Android.mk
@@ -2,7 +2,7 @@
include $(CLEAR_VARS)
LOCAL_SRC_FILES:= \
- android_media_Crypto.cpp \
+ android_media_MediaCrypto.cpp \
android_media_MediaCodec.cpp \
android_media_MediaCodecList.cpp \
android_media_MediaExtractor.cpp \
diff --git a/media/jni/android_media_MediaCodec.cpp b/media/jni/android_media_MediaCodec.cpp
index 01d3833..a120a2f 100644
--- a/media/jni/android_media_MediaCodec.cpp
+++ b/media/jni/android_media_MediaCodec.cpp
@@ -20,7 +20,7 @@
#include "android_media_MediaCodec.h"
-#include "android_media_Crypto.h"
+#include "android_media_MediaCrypto.h"
#include "android_media_Utils.h"
#include "android_runtime/AndroidRuntime.h"
#include "android_runtime/android_view_Surface.h"
@@ -49,6 +49,13 @@
struct fields_t {
jfieldID context;
+
+ jfieldID cryptoInfoNumSubSamplesID;
+ jfieldID cryptoInfoNumBytesOfClearDataID;
+ jfieldID cryptoInfoNumBytesOfEncryptedDataID;
+ jfieldID cryptoInfoKeyID;
+ jfieldID cryptoInfoIVID;
+ jfieldID cryptoInfoModeID;
};
static fields_t gFields;
@@ -387,12 +394,7 @@
jobject thiz,
jint index,
jint offset,
- jintArray numBytesOfClearDataObj,
- jintArray numBytesOfEncryptedDataObj,
- jint numSubSamples,
- jbyteArray keyObj,
- jbyteArray ivObj,
- jint mode,
+ jobject cryptoInfoObj,
jlong timestampUs,
jint flags) {
ALOGV("android_media_MediaCodec_queueSecureInputBuffer");
@@ -404,6 +406,25 @@
return;
}
+ jint numSubSamples =
+ env->GetIntField(cryptoInfoObj, gFields.cryptoInfoNumSubSamplesID);
+
+ jintArray numBytesOfClearDataObj =
+ (jintArray)env->GetObjectField(
+ cryptoInfoObj, gFields.cryptoInfoNumBytesOfClearDataID);
+
+ jintArray numBytesOfEncryptedDataObj =
+ (jintArray)env->GetObjectField(
+ cryptoInfoObj, gFields.cryptoInfoNumBytesOfEncryptedDataID);
+
+ jbyteArray keyObj =
+ (jbyteArray)env->GetObjectField(cryptoInfoObj, gFields.cryptoInfoKeyID);
+
+ jbyteArray ivObj =
+ (jbyteArray)env->GetObjectField(cryptoInfoObj, gFields.cryptoInfoIVID);
+
+ jint mode = env->GetIntField(cryptoInfoObj, gFields.cryptoInfoModeID);
+
status_t err = OK;
CryptoPlugin::SubSample *subSamples = NULL;
@@ -612,6 +633,30 @@
gFields.context = env->GetFieldID(clazz, "mNativeContext", "I");
CHECK(gFields.context != NULL);
+
+ clazz = env->FindClass("android/media/MediaCodec$CryptoInfo");
+ CHECK(clazz != NULL);
+
+ gFields.cryptoInfoNumSubSamplesID =
+ env->GetFieldID(clazz, "numSubSamples", "I");
+ CHECK(gFields.cryptoInfoNumSubSamplesID != NULL);
+
+ gFields.cryptoInfoNumBytesOfClearDataID =
+ env->GetFieldID(clazz, "numBytesOfClearData", "[I");
+ CHECK(gFields.cryptoInfoNumBytesOfClearDataID != NULL);
+
+ gFields.cryptoInfoNumBytesOfEncryptedDataID =
+ env->GetFieldID(clazz, "numBytesOfEncryptedData", "[I");
+ CHECK(gFields.cryptoInfoNumBytesOfEncryptedDataID != NULL);
+
+ gFields.cryptoInfoKeyID = env->GetFieldID(clazz, "key", "[B");
+ CHECK(gFields.cryptoInfoKeyID != NULL);
+
+ gFields.cryptoInfoIVID = env->GetFieldID(clazz, "iv", "[B");
+ CHECK(gFields.cryptoInfoIVID != NULL);
+
+ gFields.cryptoInfoModeID = env->GetFieldID(clazz, "mode", "I");
+ CHECK(gFields.cryptoInfoModeID != NULL);
}
static void android_media_MediaCodec_native_setup(
@@ -656,7 +701,7 @@
{ "native_configure",
"([Ljava/lang/String;[Ljava/lang/Object;Landroid/view/Surface;"
- "Landroid/media/Crypto;I)V",
+ "Landroid/media/MediaCrypto;I)V",
(void *)android_media_MediaCodec_native_configure },
{ "start", "()V", (void *)android_media_MediaCodec_start },
@@ -666,7 +711,7 @@
{ "queueInputBuffer", "(IIIJI)V",
(void *)android_media_MediaCodec_queueInputBuffer },
- { "queueSecureInputBuffer", "(II[I[II[B[BIJI)V",
+ { "queueSecureInputBuffer", "(IILandroid/media/MediaCodec$CryptoInfo;JI)V",
(void *)android_media_MediaCodec_queueSecureInputBuffer },
{ "dequeueInputBuffer", "(J)I",
diff --git a/media/jni/android_media_MediaCodecList.cpp b/media/jni/android_media_MediaCodecList.cpp
index 2b8f91e..7139560 100644
--- a/media/jni/android_media_MediaCodecList.cpp
+++ b/media/jni/android_media_MediaCodecList.cpp
@@ -118,10 +118,10 @@
env->NewObjectArray(profileLevels.size(), profileLevelClazz, NULL);
jfieldID profileField =
- env->GetFieldID(profileLevelClazz, "mProfile", "I");
+ env->GetFieldID(profileLevelClazz, "profile", "I");
jfieldID levelField =
- env->GetFieldID(profileLevelClazz, "mLevel", "I");
+ env->GetFieldID(profileLevelClazz, "level", "I");
for (size_t i = 0; i < profileLevels.size(); ++i) {
const MediaCodecList::ProfileLevel &src = profileLevels.itemAt(i);
@@ -139,7 +139,7 @@
jfieldID profileLevelsField = env->GetFieldID(
capsClazz,
- "mProfileLevels",
+ "profileLevels",
"[Landroid/media/MediaCodecList$CodecProfileLevel;");
env->SetObjectField(caps, profileLevelsField, profileLevelArray);
@@ -155,7 +155,7 @@
}
jfieldID colorFormatsField = env->GetFieldID(
- capsClazz, "mColorFormats", "[I");
+ capsClazz, "colorFormats", "[I");
env->SetObjectField(caps, colorFormatsField, colorFormatsArray);
diff --git a/media/jni/android_media_Crypto.cpp b/media/jni/android_media_MediaCrypto.cpp
similarity index 79%
rename from media/jni/android_media_Crypto.cpp
rename to media/jni/android_media_MediaCrypto.cpp
index e1a60a1..f4f0953 100644
--- a/media/jni/android_media_Crypto.cpp
+++ b/media/jni/android_media_MediaCrypto.cpp
@@ -15,10 +15,10 @@
*/
//#define LOG_NDEBUG 0
-#define LOG_TAG "Crypto-JNI"
+#define LOG_TAG "MediaCrypto-JNI"
#include <utils/Log.h>
-#include "android_media_Crypto.h"
+#include "android_media_MediaCrypto.h"
#include "android_runtime/AndroidRuntime.h"
#include "jni.h"
@@ -124,7 +124,7 @@
// static
sp<ICrypto> JCrypto::GetCrypto(JNIEnv *env, jobject obj) {
- jclass clazz = env->FindClass("android/media/Crypto");
+ jclass clazz = env->FindClass("android/media/MediaCrypto");
CHECK(clazz != NULL);
if (!env->IsInstanceOf(obj, clazz)) {
@@ -158,19 +158,19 @@
return old;
}
-static void android_media_Crypto_release(JNIEnv *env, jobject thiz) {
+static void android_media_MediaCrypto_release(JNIEnv *env, jobject thiz) {
setCrypto(env, thiz, NULL);
}
-static void android_media_Crypto_native_init(JNIEnv *env) {
- jclass clazz = env->FindClass("android/media/Crypto");
+static void android_media_MediaCrypto_native_init(JNIEnv *env) {
+ jclass clazz = env->FindClass("android/media/MediaCrypto");
CHECK(clazz != NULL);
gFields.context = env->GetFieldID(clazz, "mNativeContext", "I");
CHECK(gFields.context != NULL);
}
-static void android_media_Crypto_native_setup(
+static void android_media_MediaCrypto_native_setup(
JNIEnv *env, jobject thiz,
jbyteArray uuidObj, jbyteArray initDataObj) {
jsize uuidLength = env->GetArrayLength(uuidObj);
@@ -186,16 +186,23 @@
jboolean isCopy;
jbyte *uuid = env->GetByteArrayElements(uuidObj, &isCopy);
- jsize initDataLength = env->GetArrayLength(initDataObj);
- jbyte *initData = env->GetByteArrayElements(initDataObj, &isCopy);
+ jsize initDataLength = 0;
+ jbyte *initData = NULL;
+
+ if (initDataObj != NULL) {
+ initDataLength = env->GetArrayLength(initDataObj);
+ initData = env->GetByteArrayElements(initDataObj, &isCopy);
+ }
sp<JCrypto> crypto = new JCrypto(
env, thiz, (const uint8_t *)uuid, initData, initDataLength);
status_t err = crypto->initCheck();
- env->ReleaseByteArrayElements(initDataObj, initData, 0);
- initData = NULL;
+ if (initDataObj != NULL) {
+ env->ReleaseByteArrayElements(initDataObj, initData, 0);
+ initData = NULL;
+ }
env->ReleaseByteArrayElements(uuidObj, uuid, 0);
uuid = NULL;
@@ -203,7 +210,7 @@
if (err != OK) {
jniThrowException(
env,
- "java/io/IOException",
+ "java/lang/RuntimeException",
"Failed to instantiate crypto object.");
return;
}
@@ -211,12 +218,12 @@
setCrypto(env,thiz, crypto);
}
-static void android_media_Crypto_native_finalize(
+static void android_media_MediaCrypto_native_finalize(
JNIEnv *env, jobject thiz) {
- android_media_Crypto_release(env, thiz);
+ android_media_MediaCrypto_release(env, thiz);
}
-static jboolean android_media_Crypto_isCryptoSchemeSupported(
+static jboolean android_media_MediaCrypto_isCryptoSchemeSupported(
JNIEnv *env, jobject thiz, jbyteArray uuidObj) {
jsize uuidLength = env->GetArrayLength(uuidObj);
@@ -239,7 +246,7 @@
return result;
}
-static jboolean android_media_Crypto_requiresSecureDecoderComponent(
+static jboolean android_media_MediaCrypto_requiresSecureDecoderComponent(
JNIEnv *env, jobject thiz, jstring mimeObj) {
if (mimeObj == NULL) {
jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
@@ -268,24 +275,24 @@
}
static JNINativeMethod gMethods[] = {
- { "release", "()V", (void *)android_media_Crypto_release },
- { "native_init", "()V", (void *)android_media_Crypto_native_init },
+ { "release", "()V", (void *)android_media_MediaCrypto_release },
+ { "native_init", "()V", (void *)android_media_MediaCrypto_native_init },
{ "native_setup", "([B[B)V",
- (void *)android_media_Crypto_native_setup },
+ (void *)android_media_MediaCrypto_native_setup },
{ "native_finalize", "()V",
- (void *)android_media_Crypto_native_finalize },
+ (void *)android_media_MediaCrypto_native_finalize },
{ "isCryptoSchemeSupported", "([B)Z",
- (void *)android_media_Crypto_isCryptoSchemeSupported },
+ (void *)android_media_MediaCrypto_isCryptoSchemeSupported },
{ "requiresSecureDecoderComponent", "(Ljava/lang/String;)Z",
- (void *)android_media_Crypto_requiresSecureDecoderComponent },
+ (void *)android_media_MediaCrypto_requiresSecureDecoderComponent },
};
int register_android_media_Crypto(JNIEnv *env) {
return AndroidRuntime::registerNativeMethods(env,
- "android/media/Crypto", gMethods, NELEM(gMethods));
+ "android/media/MediaCrypto", gMethods, NELEM(gMethods));
}
diff --git a/media/jni/android_media_Crypto.h b/media/jni/android_media_MediaCrypto.h
similarity index 100%
rename from media/jni/android_media_Crypto.h
rename to media/jni/android_media_MediaCrypto.h
diff --git a/media/jni/android_media_MediaExtractor.cpp b/media/jni/android_media_MediaExtractor.cpp
index 8c661b7..adf0e66 100644
--- a/media/jni/android_media_MediaExtractor.cpp
+++ b/media/jni/android_media_MediaExtractor.cpp
@@ -30,12 +30,15 @@
#include <media/stagefright/foundation/AMessage.h>
#include <media/stagefright/DataSource.h>
#include <media/stagefright/MediaErrors.h>
+#include <media/stagefright/MetaData.h>
#include <media/stagefright/NuMediaExtractor.h>
namespace android {
struct fields_t {
jfieldID context;
+
+ jmethodID cryptoInfoSetID;
};
static fields_t gFields;
@@ -63,8 +66,13 @@
mClass = NULL;
}
-status_t JMediaExtractor::setDataSource(const char *path) {
- return mImpl->setDataSource(path);
+status_t JMediaExtractor::setDataSource(
+ const char *path, const KeyedVector<String8, String8> *headers) {
+ return mImpl->setDataSource(path, headers);
+}
+
+status_t JMediaExtractor::setDataSource(int fd, off64_t offset, off64_t size) {
+ return mImpl->setDataSource(fd, offset, size);
}
size_t JMediaExtractor::countTracks() const {
@@ -161,7 +169,32 @@
}
status_t JMediaExtractor::getSampleFlags(uint32_t *sampleFlags) {
- return mImpl->getSampleFlags(sampleFlags);
+ *sampleFlags = 0;
+
+ sp<MetaData> meta;
+ status_t err = mImpl->getSampleMeta(&meta);
+
+ if (err != OK) {
+ return err;
+ }
+
+ int32_t val;
+ if (meta->findInt32(kKeyIsSyncFrame, &val) && val != 0) {
+ (*sampleFlags) |= NuMediaExtractor::SAMPLE_FLAG_SYNC;
+ }
+
+ uint32_t type;
+ const void *data;
+ size_t size;
+ if (meta->findData(kKeyEncryptedSizes, &type, &data, &size)) {
+ (*sampleFlags) |= NuMediaExtractor::SAMPLE_FLAG_ENCRYPTED;
+ }
+
+ return OK;
+}
+
+status_t JMediaExtractor::getSampleMeta(sp<MetaData> *sampleMeta) {
+ return mImpl->getSampleMeta(sampleMeta);
}
} // namespace android
@@ -200,7 +233,7 @@
if (extractor == NULL) {
jniThrowException(env, "java/lang/IllegalStateException", NULL);
- return NULL;
+ return -1;
}
return extractor->countTracks();
@@ -252,12 +285,7 @@
return;
}
- status_t err = extractor->seekTo(timeUs);
-
- if (err != OK) {
- jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
- return;
- }
+ extractor->seekTo(timeUs);
}
static jboolean android_media_MediaExtractor_advance(
@@ -369,6 +397,110 @@
return sampleFlags;
}
+static jboolean android_media_MediaExtractor_getSampleCryptoInfo(
+ JNIEnv *env, jobject thiz, jobject cryptoInfoObj) {
+ sp<JMediaExtractor> extractor = getMediaExtractor(env, thiz);
+
+ if (extractor == NULL) {
+ jniThrowException(env, "java/lang/IllegalStateException", NULL);
+ return -1ll;
+ }
+
+ sp<MetaData> meta;
+ status_t err = extractor->getSampleMeta(&meta);
+
+ if (err != OK) {
+ return false;
+ }
+
+ uint32_t type;
+ const void *data;
+ size_t size;
+ if (!meta->findData(kKeyEncryptedSizes, &type, &data, &size)) {
+ return false;
+ }
+
+ size_t numSubSamples = size / sizeof(size_t);
+
+ if (numSubSamples == 0) {
+ return false;
+ }
+
+ jintArray numBytesOfEncryptedDataObj = env->NewIntArray(numSubSamples);
+ jboolean isCopy;
+ jint *dst = env->GetIntArrayElements(numBytesOfEncryptedDataObj, &isCopy);
+ for (size_t i = 0; i < numSubSamples; ++i) {
+ dst[i] = ((const size_t *)data)[i];
+ }
+ env->ReleaseIntArrayElements(numBytesOfEncryptedDataObj, dst, 0);
+ dst = NULL;
+
+ size_t encSize = size;
+ jintArray numBytesOfPlainDataObj = NULL;
+ if (meta->findData(kKeyEncryptedSizes, &type, &data, &size)) {
+ if (size != encSize) {
+ // The two must be of the same length.
+ return false;
+ }
+
+ numBytesOfPlainDataObj = env->NewIntArray(numSubSamples);
+ jboolean isCopy;
+ jint *dst = env->GetIntArrayElements(numBytesOfPlainDataObj, &isCopy);
+ for (size_t i = 0; i < numSubSamples; ++i) {
+ dst[i] = ((const size_t *)data)[i];
+ }
+ env->ReleaseIntArrayElements(numBytesOfPlainDataObj, dst, 0);
+ dst = NULL;
+ }
+
+ jbyteArray keyObj = NULL;
+ if (meta->findData(kKeyCryptoKey, &type, &data, &size)) {
+ if (size != 16) {
+ // Keys must be 16 bytes in length.
+ return false;
+ }
+
+ keyObj = env->NewByteArray(size);
+ jboolean isCopy;
+ jbyte *dst = env->GetByteArrayElements(keyObj, &isCopy);
+ memcpy(dst, data, size);
+ env->ReleaseByteArrayElements(keyObj, dst, 0);
+ dst = NULL;
+ }
+
+ jbyteArray ivObj = NULL;
+ if (meta->findData(kKeyCryptoIV, &type, &data, &size)) {
+ if (size != 16) {
+ // IVs must be 16 bytes in length.
+ return false;
+ }
+
+ ivObj = env->NewByteArray(size);
+ jboolean isCopy;
+ jbyte *dst = env->GetByteArrayElements(ivObj, &isCopy);
+ memcpy(dst, data, size);
+ env->ReleaseByteArrayElements(ivObj, dst, 0);
+ dst = NULL;
+ }
+
+ int32_t mode;
+ if (!meta->findInt32(kKeyCryptoMode, &mode)) {
+ mode = 0;
+ }
+
+ env->CallVoidMethod(
+ cryptoInfoObj,
+ gFields.cryptoInfoSetID,
+ numSubSamples,
+ numBytesOfPlainDataObj,
+ numBytesOfEncryptedDataObj,
+ keyObj,
+ ivObj,
+ mode);
+
+ return true;
+}
+
static void android_media_MediaExtractor_native_init(JNIEnv *env) {
jclass clazz = env->FindClass("android/media/MediaExtractor");
CHECK(clazz != NULL);
@@ -376,28 +508,52 @@
gFields.context = env->GetFieldID(clazz, "mNativeContext", "I");
CHECK(gFields.context != NULL);
+ clazz = env->FindClass("android/media/MediaCodec$CryptoInfo");
+ CHECK(clazz != NULL);
+
+ gFields.cryptoInfoSetID =
+ env->GetMethodID(clazz, "set", "(I[I[I[B[BI)V");
+
DataSource::RegisterDefaultSniffers();
}
static void android_media_MediaExtractor_native_setup(
- JNIEnv *env, jobject thiz, jstring path) {
+ JNIEnv *env, jobject thiz) {
sp<JMediaExtractor> extractor = new JMediaExtractor(env, thiz);
+ setMediaExtractor(env,thiz, extractor);
+}
- if (path == NULL) {
+static void android_media_MediaExtractor_setDataSource(
+ JNIEnv *env, jobject thiz,
+ jstring pathObj, jobjectArray keysArray, jobjectArray valuesArray) {
+ sp<JMediaExtractor> extractor = getMediaExtractor(env, thiz);
+
+ if (extractor == NULL) {
+ jniThrowException(env, "java/lang/IllegalStateException", NULL);
+ return;
+ }
+
+ if (pathObj == NULL) {
jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
return;
}
- const char *tmp = env->GetStringUTFChars(path, NULL);
-
- if (tmp == NULL) {
+ KeyedVector<String8, String8> headers;
+ if (!ConvertKeyValueArraysToKeyedVector(
+ env, keysArray, valuesArray, &headers)) {
return;
}
- status_t err = extractor->setDataSource(tmp);
+ const char *path = env->GetStringUTFChars(pathObj, NULL);
- env->ReleaseStringUTFChars(path, tmp);
- tmp = NULL;
+ if (path == NULL) {
+ return;
+ }
+
+ status_t err = extractor->setDataSource(path, &headers);
+
+ env->ReleaseStringUTFChars(pathObj, path);
+ path = NULL;
if (err != OK) {
jniThrowException(
@@ -406,8 +562,34 @@
"Failed to instantiate extractor.");
return;
}
+}
- setMediaExtractor(env,thiz, extractor);
+static void android_media_MediaExtractor_setDataSourceFd(
+ JNIEnv *env, jobject thiz,
+ jobject fileDescObj, jlong offset, jlong length) {
+ sp<JMediaExtractor> extractor = getMediaExtractor(env, thiz);
+
+ if (extractor == NULL) {
+ jniThrowException(env, "java/lang/IllegalStateException", NULL);
+ return;
+ }
+
+ if (fileDescObj == NULL) {
+ jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
+ return;
+ }
+
+ int fd = jniGetFDFromFileDescriptor(env, fileDescObj);
+
+ status_t err = extractor->setDataSource(fd, offset, length);
+
+ if (err != OK) {
+ jniThrowException(
+ env,
+ "java/io/IOException",
+ "Failed to instantiate extractor.");
+ return;
+ }
}
static void android_media_MediaExtractor_native_finalize(
@@ -441,13 +623,23 @@
{ "getSampleFlags", "()I",
(void *)android_media_MediaExtractor_getSampleFlags },
+ { "getSampleCryptoInfo", "(Landroid/media/MediaCodec$CryptoInfo;)Z",
+ (void *)android_media_MediaExtractor_getSampleCryptoInfo },
+
{ "native_init", "()V", (void *)android_media_MediaExtractor_native_init },
- { "native_setup", "(Ljava/lang/String;)V",
+ { "native_setup", "()V",
(void *)android_media_MediaExtractor_native_setup },
{ "native_finalize", "()V",
(void *)android_media_MediaExtractor_native_finalize },
+
+ { "setDataSource", "(Ljava/lang/String;[Ljava/lang/String;"
+ "[Ljava/lang/String;)V",
+ (void *)android_media_MediaExtractor_setDataSource },
+
+ { "setDataSource", "(Ljava/io/FileDescriptor;JJ)V",
+ (void *)android_media_MediaExtractor_setDataSourceFd },
};
int register_android_media_MediaExtractor(JNIEnv *env) {
diff --git a/media/jni/android_media_MediaExtractor.h b/media/jni/android_media_MediaExtractor.h
index 49a64d6..f7ce2ff 100644
--- a/media/jni/android_media_MediaExtractor.h
+++ b/media/jni/android_media_MediaExtractor.h
@@ -19,18 +19,25 @@
#include <media/stagefright/foundation/ABase.h>
#include <utils/Errors.h>
+#include <utils/KeyedVector.h>
#include <utils/RefBase.h>
+#include <utils/String8.h>
#include "jni.h"
namespace android {
+struct MetaData;
struct NuMediaExtractor;
struct JMediaExtractor : public RefBase {
JMediaExtractor(JNIEnv *env, jobject thiz);
- status_t setDataSource(const char *path);
+ status_t setDataSource(
+ const char *path,
+ const KeyedVector<String8, String8> *headers);
+
+ status_t setDataSource(int fd, off64_t offset, off64_t size);
size_t countTracks() const;
status_t getTrackFormat(size_t index, jobject *format) const;
@@ -44,6 +51,7 @@
status_t getSampleTrackIndex(size_t *trackIndex);
status_t getSampleTime(int64_t *sampleTimeUs);
status_t getSampleFlags(uint32_t *sampleFlags);
+ status_t getSampleMeta(sp<MetaData> *sampleMeta);
protected:
virtual ~JMediaExtractor();
diff --git a/media/jni/android_media_Utils.cpp b/media/jni/android_media_Utils.cpp
index 1190448..a4d88ff 100644
--- a/media/jni/android_media_Utils.cpp
+++ b/media/jni/android_media_Utils.cpp
@@ -85,6 +85,16 @@
return env->NewObject(clazz, integerConstructID, value);
}
+static jobject makeLongObject(JNIEnv *env, int64_t value) {
+ jclass clazz = env->FindClass("java/lang/Long");
+ CHECK(clazz != NULL);
+
+ jmethodID longConstructID = env->GetMethodID(clazz, "<init>", "(J)V");
+ CHECK(longConstructID != NULL);
+
+ return env->NewObject(clazz, longConstructID, value);
+}
+
static jobject makeFloatObject(JNIEnv *env, float value) {
jclass clazz = env->FindClass("java/lang/Float");
CHECK(clazz != NULL);
@@ -158,6 +168,15 @@
break;
}
+ case AMessage::kTypeInt64:
+ {
+ int64_t val;
+ CHECK(msg->findInt64(key, &val));
+
+ valueObj = makeLongObject(env, val);
+ break;
+ }
+
case AMessage::kTypeFloat:
{
float val;
diff --git a/opengl/java/android/opengl/GLSurfaceView.java b/opengl/java/android/opengl/GLSurfaceView.java
index 2a4d59b..8acbae3 100644
--- a/opengl/java/android/opengl/GLSurfaceView.java
+++ b/opengl/java/android/opengl/GLSurfaceView.java
@@ -1298,7 +1298,9 @@
}
// Update the pause state.
+ boolean pausing = false;
if (mPaused != mRequestPaused) {
+ pausing = mRequestPaused;
mPaused = mRequestPaused;
sGLThreadManager.notifyAll();
if (LOG_PAUSE_RESUME) {
@@ -1324,12 +1326,16 @@
lostEglContext = false;
}
- // Do we need to release the EGL surface?
- if (mHaveEglSurface && mPaused) {
+ // When pausing, release the EGL surface:
+ if (pausing && mHaveEglSurface) {
if (LOG_SURFACE) {
Log.i("GLThread", "releasing EGL surface because paused tid=" + getId());
}
stopEglSurfaceLocked();
+ }
+
+ // When pausing, optionally release the EGL Context:
+ if (pausing && mHaveEglContext) {
GLSurfaceView view = mGLSurfaceViewWeakRef.get();
boolean preserveEglContextOnPause = view == null ?
false : view.mPreserveEGLContextOnPause;
@@ -1339,6 +1345,10 @@
Log.i("GLThread", "releasing EGL context because paused tid=" + getId());
}
}
+ }
+
+ // When pausing, optionally terminate EGL:
+ if (pausing) {
if (sGLThreadManager.shouldTerminateEGLWhenPausing()) {
mEglHelper.finish();
if (LOG_SURFACE) {
diff --git a/packages/InputDevices/Android.mk b/packages/InputDevices/Android.mk
index 446b47e..37f2428 100644
--- a/packages/InputDevices/Android.mk
+++ b/packages/InputDevices/Android.mk
@@ -1,3 +1,17 @@
+# Copyright (C) 2012 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.
+
LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)
@@ -12,5 +26,17 @@
include $(BUILD_PACKAGE)
-########################
-include $(call all-makefiles-under,$(LOCAL_PATH))
+# Validate all key maps.
+include $(CLEAR_VARS)
+
+validatekeymaps := $(HOST_OUT_EXECUTABLES)/validatekeymaps$(HOST_EXECUTABLE_SUFFIX)
+files := frameworks/base/packages/InputDevices/res/raw/*.kcm
+
+LOCAL_MODULE := validate_input_devices_keymaps
+LOCAL_MODULE_TAGS := optional
+LOCAL_REQUIRED_MODULES := validatekeymaps
+
+validate_input_devices_keymaps: $(files)
+ $(hide) $(validatekeymaps) $(files)
+
+include $(BUILD_PHONY_PACKAGE)
diff --git a/packages/InputDevices/res/raw/keyboard_layout_english_us.kcm b/packages/InputDevices/res/raw/keyboard_layout_english_us.kcm
index a7823fd..2c663bc 100644
--- a/packages/InputDevices/res/raw/keyboard_layout_english_us.kcm
+++ b/packages/InputDevices/res/raw/keyboard_layout_english_us.kcm
@@ -12,4 +12,9 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-# PLACEHOLDER CONTENT #
+#
+# English (US) keyboard layout.
+# Assumes that the base keyboard layout is already English (US).
+#
+
+type OVERLAY
diff --git a/packages/InputDevices/res/raw/keyboard_layout_english_us_dvorak.kcm b/packages/InputDevices/res/raw/keyboard_layout_english_us_dvorak.kcm
index a7823fd..a2d110e 100644
--- a/packages/InputDevices/res/raw/keyboard_layout_english_us_dvorak.kcm
+++ b/packages/InputDevices/res/raw/keyboard_layout_english_us_dvorak.kcm
@@ -12,4 +12,45 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-# PLACEHOLDER CONTENT #
+#
+# English (US), Dvorak keyboard layout.
+# Assumes that the base keyboard layout is already English (US).
+#
+
+type OVERLAY
+
+map key 12 LEFT_BRACKET
+map key 13 RIGHT_BRACKET
+map key 16 APOSTROPHE
+map key 17 COMMA
+map key 18 PERIOD
+map key 19 P
+map key 20 Y
+map key 21 F
+map key 22 G
+map key 23 C
+map key 24 R
+map key 25 L
+map key 26 SLASH
+map key 27 EQUALS
+map key 30 A
+map key 31 O
+map key 32 E
+map key 33 U
+map key 34 I
+map key 35 D
+map key 36 H
+map key 37 T
+map key 38 N
+map key 39 S
+map key 40 MINUS
+map key 44 SEMICOLON
+map key 45 Q
+map key 46 J
+map key 47 K
+map key 48 X
+map key 49 B
+map key 50 M
+map key 51 W
+map key 52 V
+map key 53 Z
diff --git a/packages/InputDevices/res/raw/keyboard_layout_german.kcm b/packages/InputDevices/res/raw/keyboard_layout_german.kcm
index a7823fd..6b3b3b4 100644
--- a/packages/InputDevices/res/raw/keyboard_layout_german.kcm
+++ b/packages/InputDevices/res/raw/keyboard_layout_german.kcm
@@ -12,4 +12,8 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-# PLACEHOLDER CONTENT #
+#
+# German keyboard layout.
+#
+
+type OVERLAY
diff --git a/packages/SystemUI/res/layout/notification_adaptive_wrapper.xml b/packages/SystemUI/res/layout/notification_adaptive_wrapper.xml
new file mode 100644
index 0000000..15d0890
--- /dev/null
+++ b/packages/SystemUI/res/layout/notification_adaptive_wrapper.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2012 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.
+-->
+<SizeAdaptiveLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:background="@android:color/background_dark"
+ android:id="@+id/notification_adaptive_wrapper"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content" />
diff --git a/packages/SystemUI/res/layout/status_bar_notification_row.xml b/packages/SystemUI/res/layout/status_bar_notification_row.xml
index c307c6e..a0d1b08 100644
--- a/packages/SystemUI/res/layout/status_bar_notification_row.xml
+++ b/packages/SystemUI/res/layout/status_bar_notification_row.xml
@@ -1,6 +1,6 @@
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
- android:layout_height="@dimen/notification_height"
+ android:layout_height="wrap_content"
>
<Button
@@ -21,7 +21,14 @@
android:focusable="true"
android:clickable="true"
android:background="@drawable/notification_row_bg"
- />
+ >
+
+ <com.android.internal.widget.SizeAdaptiveLayout android:id="@+id/adaptive"
+ android:background="@android:color/background_dark"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content" />
+
+ </com.android.systemui.statusbar.LatestItemView>
<View
android:layout_width="match_parent"
diff --git a/packages/SystemUI/res/values-am/strings.xml b/packages/SystemUI/res/values-am/strings.xml
index 7013862..42eef13 100644
--- a/packages/SystemUI/res/values-am/strings.xml
+++ b/packages/SystemUI/res/values-am/strings.xml
@@ -48,8 +48,7 @@
<string name="status_bar_settings_notifications" msgid="397146176280905137">"ማሳወቂያዎች"</string>
<string name="bluetooth_tethered" msgid="7094101612161133267">"ብሉቱዝ አያይዝ"</string>
<string name="status_bar_input_method_settings_configure_input_methods" msgid="3504292471512317827">"የግቤት ስልቶችን አዘጋጅ"</string>
- <!-- no translation found for status_bar_use_physical_keyboard (7551903084416057810) -->
- <skip />
+ <string name="status_bar_use_physical_keyboard" msgid="7551903084416057810">"የሚዳሰስ የቁልፍ ሰሌዳ"</string>
<string name="usb_device_permission_prompt" msgid="834698001271562057">"መተግበሪያ <xliff:g id="APPLICATION">%1$s</xliff:g> የUSB መሣሪያን ለመድረስ ይፍቀድ?"</string>
<string name="usb_accessory_permission_prompt" msgid="5171775411178865750">"መተግበሪያ <xliff:g id="APPLICATION">%1$s</xliff:g> የUSB ተቀጥላ ላይ እንዲደርስ ፍቀድ?"</string>
<string name="usb_device_confirm_prompt" msgid="5161205258635253206">"የዚህ USB ተቀጥላ ሲያያዝ <xliff:g id="ACTIVITY">%1$s</xliff:g>ይከፈት?"</string>
diff --git a/packages/SystemUI/res/values-ar/strings.xml b/packages/SystemUI/res/values-ar/strings.xml
index 201f72c..9d6051e 100644
--- a/packages/SystemUI/res/values-ar/strings.xml
+++ b/packages/SystemUI/res/values-ar/strings.xml
@@ -48,8 +48,7 @@
<string name="status_bar_settings_notifications" msgid="397146176280905137">"التنبيهات"</string>
<string name="bluetooth_tethered" msgid="7094101612161133267">"تم إنشاء الاتصال بالإنترنت عن طريق البلوتوث."</string>
<string name="status_bar_input_method_settings_configure_input_methods" msgid="3504292471512317827">"إعداد أسلوب الإدخال"</string>
- <!-- no translation found for status_bar_use_physical_keyboard (7551903084416057810) -->
- <skip />
+ <string name="status_bar_use_physical_keyboard" msgid="7551903084416057810">"لوحة مفاتيح فعلية"</string>
<string name="usb_device_permission_prompt" msgid="834698001271562057">"هل تريد السماح للتطبيق <xliff:g id="APPLICATION">%1$s</xliff:g> بالدخول إلى جهاز USB؟"</string>
<string name="usb_accessory_permission_prompt" msgid="5171775411178865750">"هل تريد السماح للتطبيق <xliff:g id="APPLICATION">%1$s</xliff:g> بالدخول إلى ملحق USB؟"</string>
<string name="usb_device_confirm_prompt" msgid="5161205258635253206">"هل تريد فتح <xliff:g id="ACTIVITY">%1$s</xliff:g> عند توصيل جهاز USB هذا؟"</string>
diff --git a/packages/SystemUI/res/values-bg/strings.xml b/packages/SystemUI/res/values-bg/strings.xml
index e5167a5..429f246 100644
--- a/packages/SystemUI/res/values-bg/strings.xml
+++ b/packages/SystemUI/res/values-bg/strings.xml
@@ -48,8 +48,7 @@
<string name="status_bar_settings_notifications" msgid="397146176280905137">"Известия"</string>
<string name="bluetooth_tethered" msgid="7094101612161133267">"Bluetooth има връзка с тетъринг"</string>
<string name="status_bar_input_method_settings_configure_input_methods" msgid="3504292471512317827">"Методи на въвеждане: Настройка"</string>
- <!-- no translation found for status_bar_use_physical_keyboard (7551903084416057810) -->
- <skip />
+ <string name="status_bar_use_physical_keyboard" msgid="7551903084416057810">"Физическа клавиатура"</string>
<string name="usb_device_permission_prompt" msgid="834698001271562057">"Да се разреши ли на приложението <xliff:g id="APPLICATION">%1$s</xliff:g> достъп до USB устройството?"</string>
<string name="usb_accessory_permission_prompt" msgid="5171775411178865750">"Да се разреши ли на приложението <xliff:g id="APPLICATION">%1$s</xliff:g> достъп до аксесоара за USB?"</string>
<string name="usb_device_confirm_prompt" msgid="5161205258635253206">"Да се отвори ли <xliff:g id="ACTIVITY">%1$s</xliff:g>, когато това USB устройство е свързано?"</string>
diff --git a/packages/SystemUI/res/values-ca/strings.xml b/packages/SystemUI/res/values-ca/strings.xml
index 0ebced0..427abce 100644
--- a/packages/SystemUI/res/values-ca/strings.xml
+++ b/packages/SystemUI/res/values-ca/strings.xml
@@ -48,8 +48,7 @@
<string name="status_bar_settings_notifications" msgid="397146176280905137">"Notificacions"</string>
<string name="bluetooth_tethered" msgid="7094101612161133267">"Bluetooth sense fil"</string>
<string name="status_bar_input_method_settings_configure_input_methods" msgid="3504292471512317827">"Configura els mètodes d\'entrada"</string>
- <!-- no translation found for status_bar_use_physical_keyboard (7551903084416057810) -->
- <skip />
+ <string name="status_bar_use_physical_keyboard" msgid="7551903084416057810">"Teclat físic"</string>
<string name="usb_device_permission_prompt" msgid="834698001271562057">"Vols permetre que l\'aplicació <xliff:g id="APPLICATION">%1$s</xliff:g> accedeixi al dispositiu USB?"</string>
<string name="usb_accessory_permission_prompt" msgid="5171775411178865750">"Vols permetre que l\'aplicació <xliff:g id="APPLICATION">%1$s</xliff:g> accedeixi a l\'accessori USB?"</string>
<string name="usb_device_confirm_prompt" msgid="5161205258635253206">"Vols que s\'obri <xliff:g id="ACTIVITY">%1$s</xliff:g> quan aquest dispositiu USB estigui connectat?"</string>
diff --git a/packages/SystemUI/res/values-cs/strings.xml b/packages/SystemUI/res/values-cs/strings.xml
index 847bfc4..9c9674a 100644
--- a/packages/SystemUI/res/values-cs/strings.xml
+++ b/packages/SystemUI/res/values-cs/strings.xml
@@ -48,8 +48,7 @@
<string name="status_bar_settings_notifications" msgid="397146176280905137">"Oznámení"</string>
<string name="bluetooth_tethered" msgid="7094101612161133267">"Datové připojení Bluetooth se sdílí"</string>
<string name="status_bar_input_method_settings_configure_input_methods" msgid="3504292471512317827">"Nastavit metody vstupu"</string>
- <!-- no translation found for status_bar_use_physical_keyboard (7551903084416057810) -->
- <skip />
+ <string name="status_bar_use_physical_keyboard" msgid="7551903084416057810">"Fyzická klávesnice"</string>
<string name="usb_device_permission_prompt" msgid="834698001271562057">"Povolit aplikaci <xliff:g id="APPLICATION">%1$s</xliff:g> přístup k zařízení USB?"</string>
<string name="usb_accessory_permission_prompt" msgid="5171775411178865750">"Povolit aplikaci <xliff:g id="APPLICATION">%1$s</xliff:g> přístup k perifernímu zařízení USB?"</string>
<string name="usb_device_confirm_prompt" msgid="5161205258635253206">"Chcete při připojení tohoto zařízení USB otevřít aplikaci <xliff:g id="ACTIVITY">%1$s</xliff:g>?"</string>
diff --git a/packages/SystemUI/res/values-de/strings.xml b/packages/SystemUI/res/values-de/strings.xml
index 39d5c33..e3d82b1 100644
--- a/packages/SystemUI/res/values-de/strings.xml
+++ b/packages/SystemUI/res/values-de/strings.xml
@@ -48,8 +48,7 @@
<string name="status_bar_settings_notifications" msgid="397146176280905137">"Benachrichtigungen"</string>
<string name="bluetooth_tethered" msgid="7094101612161133267">"Bluetooth-Tethering aktiv"</string>
<string name="status_bar_input_method_settings_configure_input_methods" msgid="3504292471512317827">"Eingabemethoden einrichten"</string>
- <!-- no translation found for status_bar_use_physical_keyboard (7551903084416057810) -->
- <skip />
+ <string name="status_bar_use_physical_keyboard" msgid="7551903084416057810">"Physische Tastatur"</string>
<string name="usb_device_permission_prompt" msgid="834698001271562057">"App <xliff:g id="APPLICATION">%1$s</xliff:g> Zugriff auf USB-Gerät gewähren?"</string>
<string name="usb_accessory_permission_prompt" msgid="5171775411178865750">"App <xliff:g id="APPLICATION">%1$s</xliff:g> Zugriff auf USB-Zubehör gewähren?"</string>
<string name="usb_device_confirm_prompt" msgid="5161205258635253206">"<xliff:g id="ACTIVITY">%1$s</xliff:g> öffnen, wenn dieses USB-Gerät verbunden ist?"</string>
diff --git a/packages/SystemUI/res/values-el/strings.xml b/packages/SystemUI/res/values-el/strings.xml
index 48158db..5511b1a 100644
--- a/packages/SystemUI/res/values-el/strings.xml
+++ b/packages/SystemUI/res/values-el/strings.xml
@@ -48,8 +48,7 @@
<string name="status_bar_settings_notifications" msgid="397146176280905137">"Ειδοποιήσεις"</string>
<string name="bluetooth_tethered" msgid="7094101612161133267">"Έγινε σύνδεση μέσω Bluetooth"</string>
<string name="status_bar_input_method_settings_configure_input_methods" msgid="3504292471512317827">"Ρύθμιση μεθόδων εισαγωγής"</string>
- <!-- no translation found for status_bar_use_physical_keyboard (7551903084416057810) -->
- <skip />
+ <string name="status_bar_use_physical_keyboard" msgid="7551903084416057810">"Φυσικό πληκτρολόγιο"</string>
<string name="usb_device_permission_prompt" msgid="834698001271562057">"Να επιτρέπεται στην εφαρμογή <xliff:g id="APPLICATION">%1$s</xliff:g> η πρόσβαση στη συσκευή USB;"</string>
<string name="usb_accessory_permission_prompt" msgid="5171775411178865750">"Να επιτρέπεται στην εφαρμογή <xliff:g id="APPLICATION">%1$s</xliff:g> η πρόσβαση στο αξεσουάρ USB;"</string>
<string name="usb_device_confirm_prompt" msgid="5161205258635253206">"Άνοιγμα του <xliff:g id="ACTIVITY">%1$s</xliff:g> κατά τη σύνδεση αυτής της συσκευής USB;"</string>
diff --git a/packages/SystemUI/res/values-es-rUS/strings.xml b/packages/SystemUI/res/values-es-rUS/strings.xml
index 4db7130..96c8c23 100644
--- a/packages/SystemUI/res/values-es-rUS/strings.xml
+++ b/packages/SystemUI/res/values-es-rUS/strings.xml
@@ -48,8 +48,7 @@
<string name="status_bar_settings_notifications" msgid="397146176280905137">"Notificaciones"</string>
<string name="bluetooth_tethered" msgid="7094101612161133267">"Bluetooth anclado"</string>
<string name="status_bar_input_method_settings_configure_input_methods" msgid="3504292471512317827">"Configurar métodos de intro."</string>
- <!-- no translation found for status_bar_use_physical_keyboard (7551903084416057810) -->
- <skip />
+ <string name="status_bar_use_physical_keyboard" msgid="7551903084416057810">"Teclado físico"</string>
<string name="usb_device_permission_prompt" msgid="834698001271562057">"¿Deseas que la aplicación <xliff:g id="APPLICATION">%1$s</xliff:g> acceda al dispositivo USB?"</string>
<string name="usb_accessory_permission_prompt" msgid="5171775411178865750">"¿Deseas que la aplicación <xliff:g id="APPLICATION">%1$s</xliff:g> acceda al accesorio USB?"</string>
<string name="usb_device_confirm_prompt" msgid="5161205258635253206">"¿Abrir <xliff:g id="ACTIVITY">%1$s</xliff:g> cuando este dispositivo USB esté conectado?"</string>
diff --git a/packages/SystemUI/res/values-es/strings.xml b/packages/SystemUI/res/values-es/strings.xml
index f7f73d7..0b3e4e4 100644
--- a/packages/SystemUI/res/values-es/strings.xml
+++ b/packages/SystemUI/res/values-es/strings.xml
@@ -48,8 +48,7 @@
<string name="status_bar_settings_notifications" msgid="397146176280905137">"Notificaciones"</string>
<string name="bluetooth_tethered" msgid="7094101612161133267">"Bluetooth anclado"</string>
<string name="status_bar_input_method_settings_configure_input_methods" msgid="3504292471512317827">"Configurar métodos de introducción"</string>
- <!-- no translation found for status_bar_use_physical_keyboard (7551903084416057810) -->
- <skip />
+ <string name="status_bar_use_physical_keyboard" msgid="7551903084416057810">"Teclado físico"</string>
<string name="usb_device_permission_prompt" msgid="834698001271562057">"¿Permitir que la aplicación <xliff:g id="APPLICATION">%1$s</xliff:g> acceda al dispositivo USB?"</string>
<string name="usb_accessory_permission_prompt" msgid="5171775411178865750">"¿Permitir que la aplicación <xliff:g id="APPLICATION">%1$s</xliff:g> acceda al accesorio USB?"</string>
<string name="usb_device_confirm_prompt" msgid="5161205258635253206">"¿Quieres abrir <xliff:g id="ACTIVITY">%1$s</xliff:g> al conectar este dispositivo USB?"</string>
diff --git a/packages/SystemUI/res/values-fa/strings.xml b/packages/SystemUI/res/values-fa/strings.xml
index 569e929..df25d5e 100644
--- a/packages/SystemUI/res/values-fa/strings.xml
+++ b/packages/SystemUI/res/values-fa/strings.xml
@@ -48,8 +48,7 @@
<string name="status_bar_settings_notifications" msgid="397146176280905137">"اعلان ها"</string>
<string name="bluetooth_tethered" msgid="7094101612161133267">"اتصال اینترنتی با بلوتوث تلفن همراه"</string>
<string name="status_bar_input_method_settings_configure_input_methods" msgid="3504292471512317827">"تنظیم روشهای ورودی"</string>
- <!-- no translation found for status_bar_use_physical_keyboard (7551903084416057810) -->
- <skip />
+ <string name="status_bar_use_physical_keyboard" msgid="7551903084416057810">"صفحه کلید فیزیکی"</string>
<string name="usb_device_permission_prompt" msgid="834698001271562057">"به برنامه <xliff:g id="APPLICATION">%1$s</xliff:g> اجازه می دهید به دستگاه USB دسترسی داشته باشد؟"</string>
<string name="usb_accessory_permission_prompt" msgid="5171775411178865750">"به برنامه <xliff:g id="APPLICATION">%1$s</xliff:g> اجازه میدهد تا به وسیله جانبی USB دسترسی داشته باشد؟"</string>
<string name="usb_device_confirm_prompt" msgid="5161205258635253206">"وقتی این دستگاه USB وصل است، <xliff:g id="ACTIVITY">%1$s</xliff:g> باز شود؟"</string>
diff --git a/packages/SystemUI/res/values-fi/strings.xml b/packages/SystemUI/res/values-fi/strings.xml
index 93e6b62..370d234 100644
--- a/packages/SystemUI/res/values-fi/strings.xml
+++ b/packages/SystemUI/res/values-fi/strings.xml
@@ -48,8 +48,7 @@
<string name="status_bar_settings_notifications" msgid="397146176280905137">"Ilmoitukset"</string>
<string name="bluetooth_tethered" msgid="7094101612161133267">"Bluetooth yhdistetty"</string>
<string name="status_bar_input_method_settings_configure_input_methods" msgid="3504292471512317827">"Määritä syöttötavat"</string>
- <!-- no translation found for status_bar_use_physical_keyboard (7551903084416057810) -->
- <skip />
+ <string name="status_bar_use_physical_keyboard" msgid="7551903084416057810">"Fyysinen näppäimistö"</string>
<string name="usb_device_permission_prompt" msgid="834698001271562057">"Annetaanko sovellukselle <xliff:g id="APPLICATION">%1$s</xliff:g> lupa käyttää USB-laitetta?"</string>
<string name="usb_accessory_permission_prompt" msgid="5171775411178865750">"Annetaanko sovellukselle <xliff:g id="APPLICATION">%1$s</xliff:g> lupa käyttää USB-lisälaitetta?"</string>
<string name="usb_device_confirm_prompt" msgid="5161205258635253206">"Avataanko <xliff:g id="ACTIVITY">%1$s</xliff:g> tämän USB-laitteen ollessa kytkettynä?"</string>
diff --git a/packages/SystemUI/res/values-hi/strings.xml b/packages/SystemUI/res/values-hi/strings.xml
index 741f1b4..9805f90 100644
--- a/packages/SystemUI/res/values-hi/strings.xml
+++ b/packages/SystemUI/res/values-hi/strings.xml
@@ -48,8 +48,7 @@
<string name="status_bar_settings_notifications" msgid="397146176280905137">"सूचनाएं"</string>
<string name="bluetooth_tethered" msgid="7094101612161133267">"Bluetooth टीदर किया गया"</string>
<string name="status_bar_input_method_settings_configure_input_methods" msgid="3504292471512317827">"इनपुट पद्धति सेट करें"</string>
- <!-- no translation found for status_bar_use_physical_keyboard (7551903084416057810) -->
- <skip />
+ <string name="status_bar_use_physical_keyboard" msgid="7551903084416057810">"भौतिक कीबोर्ड"</string>
<string name="usb_device_permission_prompt" msgid="834698001271562057">"एप्लिकेशन <xliff:g id="APPLICATION">%1$s</xliff:g> को USB उपकरण तक पहुंचने दें?"</string>
<string name="usb_accessory_permission_prompt" msgid="5171775411178865750">"एप्लिकेशन <xliff:g id="APPLICATION">%1$s</xliff:g> को USB सहायक उपकरण तक पहुंचने दें?"</string>
<string name="usb_device_confirm_prompt" msgid="5161205258635253206">"जब यह USB उपकरण कनेक्ट किया जाए, तब <xliff:g id="ACTIVITY">%1$s</xliff:g> को खोलें?"</string>
diff --git a/packages/SystemUI/res/values-hr/strings.xml b/packages/SystemUI/res/values-hr/strings.xml
index f3d4043..2226aa8 100644
--- a/packages/SystemUI/res/values-hr/strings.xml
+++ b/packages/SystemUI/res/values-hr/strings.xml
@@ -48,8 +48,7 @@
<string name="status_bar_settings_notifications" msgid="397146176280905137">"Obavijesti"</string>
<string name="bluetooth_tethered" msgid="7094101612161133267">"Bluetooth posredno povezan"</string>
<string name="status_bar_input_method_settings_configure_input_methods" msgid="3504292471512317827">"Postavljanje načina unosa"</string>
- <!-- no translation found for status_bar_use_physical_keyboard (7551903084416057810) -->
- <skip />
+ <string name="status_bar_use_physical_keyboard" msgid="7551903084416057810">"Fizička tipkovnica"</string>
<string name="usb_device_permission_prompt" msgid="834698001271562057">"Dopustiti aplikaciji <xliff:g id="APPLICATION">%1$s</xliff:g> da pristupi ovom USB uređaju?"</string>
<string name="usb_accessory_permission_prompt" msgid="5171775411178865750">"Dopustiti aplikaciji <xliff:g id="APPLICATION">%1$s</xliff:g> da pristupi ovom USB dodatku?"</string>
<string name="usb_device_confirm_prompt" msgid="5161205258635253206">"Otvoriti <xliff:g id="ACTIVITY">%1$s</xliff:g> kad se spoji ovaj USB uređaj?"</string>
diff --git a/packages/SystemUI/res/values-hu/strings.xml b/packages/SystemUI/res/values-hu/strings.xml
index 1c28b57..87a9d45 100644
--- a/packages/SystemUI/res/values-hu/strings.xml
+++ b/packages/SystemUI/res/values-hu/strings.xml
@@ -48,8 +48,7 @@
<string name="status_bar_settings_notifications" msgid="397146176280905137">"Értesítések"</string>
<string name="bluetooth_tethered" msgid="7094101612161133267">"Bluetooth megosztva"</string>
<string name="status_bar_input_method_settings_configure_input_methods" msgid="3504292471512317827">"Beviteli módok beállítása"</string>
- <!-- no translation found for status_bar_use_physical_keyboard (7551903084416057810) -->
- <skip />
+ <string name="status_bar_use_physical_keyboard" msgid="7551903084416057810">"Fizikai billentyűzet"</string>
<string name="usb_device_permission_prompt" msgid="834698001271562057">"A(z) <xliff:g id="APPLICATION">%1$s</xliff:g> alkalmazás hozzáférhet az USB-eszközhöz?"</string>
<string name="usb_accessory_permission_prompt" msgid="5171775411178865750">"A(z) <xliff:g id="APPLICATION">%1$s</xliff:g> alkalmazás hozzáférhet az USB-kiegészítőhöz?"</string>
<string name="usb_device_confirm_prompt" msgid="5161205258635253206">"<xliff:g id="ACTIVITY">%1$s</xliff:g> megnyitása, ha USB-kiegészítő csatlakoztatva van?"</string>
diff --git a/packages/SystemUI/res/values-in/strings.xml b/packages/SystemUI/res/values-in/strings.xml
index 267f5e7..f246132 100644
--- a/packages/SystemUI/res/values-in/strings.xml
+++ b/packages/SystemUI/res/values-in/strings.xml
@@ -48,8 +48,7 @@
<string name="status_bar_settings_notifications" msgid="397146176280905137">"Pemberitahuan"</string>
<string name="bluetooth_tethered" msgid="7094101612161133267">"Bluetooth tertambat"</string>
<string name="status_bar_input_method_settings_configure_input_methods" msgid="3504292471512317827">"Menyiapkan metode masukan"</string>
- <!-- no translation found for status_bar_use_physical_keyboard (7551903084416057810) -->
- <skip />
+ <string name="status_bar_use_physical_keyboard" msgid="7551903084416057810">"Keyboard fisik"</string>
<string name="usb_device_permission_prompt" msgid="834698001271562057">"Izinkan apl <xliff:g id="APPLICATION">%1$s</xliff:g> mengakses perangkat USB?"</string>
<string name="usb_accessory_permission_prompt" msgid="5171775411178865750">"Izinkan apl <xliff:g id="APPLICATION">%1$s</xliff:g> mengakses aksesori USB?"</string>
<string name="usb_device_confirm_prompt" msgid="5161205258635253206">"Buka <xliff:g id="ACTIVITY">%1$s</xliff:g> ketika perangkat USB ini tersambung?"</string>
diff --git a/packages/SystemUI/res/values-iw/strings.xml b/packages/SystemUI/res/values-iw/strings.xml
index bc5e873..03fba7e 100644
--- a/packages/SystemUI/res/values-iw/strings.xml
+++ b/packages/SystemUI/res/values-iw/strings.xml
@@ -48,8 +48,7 @@
<string name="status_bar_settings_notifications" msgid="397146176280905137">"התראות"</string>
<string name="bluetooth_tethered" msgid="7094101612161133267">"Bluetooth קשור"</string>
<string name="status_bar_input_method_settings_configure_input_methods" msgid="3504292471512317827">"הגדר שיטות קלט"</string>
- <!-- no translation found for status_bar_use_physical_keyboard (7551903084416057810) -->
- <skip />
+ <string name="status_bar_use_physical_keyboard" msgid="7551903084416057810">"מקלדת פיזית"</string>
<string name="usb_device_permission_prompt" msgid="834698001271562057">"לאפשר ליישום <xliff:g id="APPLICATION">%1$s</xliff:g> גישה להתקן ה-USB?"</string>
<string name="usb_accessory_permission_prompt" msgid="5171775411178865750">"לאפשר ליישום <xliff:g id="APPLICATION">%1$s</xliff:g> גישה לאביזר ה-USB?"</string>
<string name="usb_device_confirm_prompt" msgid="5161205258635253206">"האם לפתוח את <xliff:g id="ACTIVITY">%1$s</xliff:g> כאשר מכשיר USB זה מחובר?"</string>
diff --git a/packages/SystemUI/res/values-ja/strings.xml b/packages/SystemUI/res/values-ja/strings.xml
index 01d76eb..4818ca9 100644
--- a/packages/SystemUI/res/values-ja/strings.xml
+++ b/packages/SystemUI/res/values-ja/strings.xml
@@ -48,8 +48,7 @@
<string name="status_bar_settings_notifications" msgid="397146176280905137">"通知"</string>
<string name="bluetooth_tethered" msgid="7094101612161133267">"Bluetoothテザリング接続"</string>
<string name="status_bar_input_method_settings_configure_input_methods" msgid="3504292471512317827">"入力方法をセットアップ"</string>
- <!-- no translation found for status_bar_use_physical_keyboard (7551903084416057810) -->
- <skip />
+ <string name="status_bar_use_physical_keyboard" msgid="7551903084416057810">"物理キーボード"</string>
<string name="usb_device_permission_prompt" msgid="834698001271562057">"アプリ「<xliff:g id="APPLICATION">%1$s</xliff:g>」にUSBデバイスへのアクセスを許可しますか?"</string>
<string name="usb_accessory_permission_prompt" msgid="5171775411178865750">"アプリ「<xliff:g id="APPLICATION">%1$s</xliff:g>」にUSBアクセサリへのアクセスを許可しますか?"</string>
<string name="usb_device_confirm_prompt" msgid="5161205258635253206">"このUSBデバイスが接続されたときに<xliff:g id="ACTIVITY">%1$s</xliff:g>を開きますか?"</string>
diff --git a/packages/SystemUI/res/values-ko/strings.xml b/packages/SystemUI/res/values-ko/strings.xml
index 88194df..3321912 100644
--- a/packages/SystemUI/res/values-ko/strings.xml
+++ b/packages/SystemUI/res/values-ko/strings.xml
@@ -48,8 +48,7 @@
<string name="status_bar_settings_notifications" msgid="397146176280905137">"알림"</string>
<string name="bluetooth_tethered" msgid="7094101612161133267">"블루투스 테더링됨"</string>
<string name="status_bar_input_method_settings_configure_input_methods" msgid="3504292471512317827">"입력 방법 설정"</string>
- <!-- no translation found for status_bar_use_physical_keyboard (7551903084416057810) -->
- <skip />
+ <string name="status_bar_use_physical_keyboard" msgid="7551903084416057810">"물리적 키보드"</string>
<string name="usb_device_permission_prompt" msgid="834698001271562057">"<xliff:g id="APPLICATION">%1$s</xliff:g> 앱이 USB 기기에 액세스하도록 허용하시겠습니까?"</string>
<string name="usb_accessory_permission_prompt" msgid="5171775411178865750">"<xliff:g id="APPLICATION">%1$s</xliff:g> 앱이 USB 액세서리에 액세스하도록 허용하시겠습니까?"</string>
<string name="usb_device_confirm_prompt" msgid="5161205258635253206">"USB 기기가 연결될 때 <xliff:g id="ACTIVITY">%1$s</xliff:g>(을)를 여시겠습니까?"</string>
diff --git a/packages/SystemUI/res/values-lt/strings.xml b/packages/SystemUI/res/values-lt/strings.xml
index 942e159..831fa41 100644
--- a/packages/SystemUI/res/values-lt/strings.xml
+++ b/packages/SystemUI/res/values-lt/strings.xml
@@ -48,8 +48,7 @@
<string name="status_bar_settings_notifications" msgid="397146176280905137">"Pranešimai"</string>
<string name="bluetooth_tethered" msgid="7094101612161133267">"„Bluetooth“ susieta"</string>
<string name="status_bar_input_method_settings_configure_input_methods" msgid="3504292471512317827">"Nustatyti įvesties metodus"</string>
- <!-- no translation found for status_bar_use_physical_keyboard (7551903084416057810) -->
- <skip />
+ <string name="status_bar_use_physical_keyboard" msgid="7551903084416057810">"Fizinė klaviatūra"</string>
<string name="usb_device_permission_prompt" msgid="834698001271562057">"Leisti programai „<xliff:g id="APPLICATION">%1$s</xliff:g>“ pasiekti USB įrenginį?"</string>
<string name="usb_accessory_permission_prompt" msgid="5171775411178865750">"Leisti programai „<xliff:g id="APPLICATION">%1$s</xliff:g>“ pasiekti USB priedą?"</string>
<string name="usb_device_confirm_prompt" msgid="5161205258635253206">"Atidaryti <xliff:g id="ACTIVITY">%1$s</xliff:g>, kai prijungtas šis USB įrenginys?"</string>
diff --git a/packages/SystemUI/res/values-lv/strings.xml b/packages/SystemUI/res/values-lv/strings.xml
index b5c9130..158c850 100644
--- a/packages/SystemUI/res/values-lv/strings.xml
+++ b/packages/SystemUI/res/values-lv/strings.xml
@@ -48,8 +48,7 @@
<string name="status_bar_settings_notifications" msgid="397146176280905137">"Paziņojumi"</string>
<string name="bluetooth_tethered" msgid="7094101612161133267">"Bluetooth piesaiste"</string>
<string name="status_bar_input_method_settings_configure_input_methods" msgid="3504292471512317827">"Iestatīt ievades metodes"</string>
- <!-- no translation found for status_bar_use_physical_keyboard (7551903084416057810) -->
- <skip />
+ <string name="status_bar_use_physical_keyboard" msgid="7551903084416057810">"Fiziskā tastatūra"</string>
<string name="usb_device_permission_prompt" msgid="834698001271562057">"Vai ļaut lietotnei <xliff:g id="APPLICATION">%1$s</xliff:g> piekļūt šai USB ierīcei?"</string>
<string name="usb_accessory_permission_prompt" msgid="5171775411178865750">"Vai ļaut lietotnei <xliff:g id="APPLICATION">%1$s</xliff:g> piekļūt šim USB piederumam?"</string>
<string name="usb_device_confirm_prompt" msgid="5161205258635253206">"Vai atvērt darbību <xliff:g id="ACTIVITY">%1$s</xliff:g>, kad tiek pievienota šī USB ierīce?"</string>
diff --git a/packages/SystemUI/res/values-ms/strings.xml b/packages/SystemUI/res/values-ms/strings.xml
index f08013d..899a204 100644
--- a/packages/SystemUI/res/values-ms/strings.xml
+++ b/packages/SystemUI/res/values-ms/strings.xml
@@ -48,8 +48,7 @@
<string name="status_bar_settings_notifications" msgid="397146176280905137">"Pemberitahuan"</string>
<string name="bluetooth_tethered" msgid="7094101612161133267">"Bluetooth ditambatkan"</string>
<string name="status_bar_input_method_settings_configure_input_methods" msgid="3504292471512317827">"Sediakan kaedah input"</string>
- <!-- no translation found for status_bar_use_physical_keyboard (7551903084416057810) -->
- <skip />
+ <string name="status_bar_use_physical_keyboard" msgid="7551903084416057810">"Papan kekunci fizikal"</string>
<string name="usb_device_permission_prompt" msgid="834698001271562057">"Benarkan aplikasi <xliff:g id="APPLICATION">%1$s</xliff:g> mengakses peranti USB?"</string>
<string name="usb_accessory_permission_prompt" msgid="5171775411178865750">"Benarkan aplikasi <xliff:g id="APPLICATION">%1$s</xliff:g> mengakses aksesori USB?"</string>
<string name="usb_device_confirm_prompt" msgid="5161205258635253206">"Buka <xliff:g id="ACTIVITY">%1$s</xliff:g> apabila peranti USB ini disambungkan?"</string>
diff --git a/packages/SystemUI/res/values-nb/strings.xml b/packages/SystemUI/res/values-nb/strings.xml
index fdd3b10..c7b272a 100644
--- a/packages/SystemUI/res/values-nb/strings.xml
+++ b/packages/SystemUI/res/values-nb/strings.xml
@@ -48,8 +48,7 @@
<string name="status_bar_settings_notifications" msgid="397146176280905137">"Varslinger"</string>
<string name="bluetooth_tethered" msgid="7094101612161133267">"Bluetooth tilknyttet"</string>
<string name="status_bar_input_method_settings_configure_input_methods" msgid="3504292471512317827">"Konfigurer inndatametoder"</string>
- <!-- no translation found for status_bar_use_physical_keyboard (7551903084416057810) -->
- <skip />
+ <string name="status_bar_use_physical_keyboard" msgid="7551903084416057810">"Fysisk tastatur"</string>
<string name="usb_device_permission_prompt" msgid="834698001271562057">"Vil du gi appen <xliff:g id="APPLICATION">%1$s</xliff:g> tilgang til USB-enheten?"</string>
<string name="usb_accessory_permission_prompt" msgid="5171775411178865750">"Vil du gi appen <xliff:g id="APPLICATION">%1$s</xliff:g> tilgang til USB-tilbehøret?"</string>
<string name="usb_device_confirm_prompt" msgid="5161205258635253206">"Vil du åpne <xliff:g id="ACTIVITY">%1$s</xliff:g> når denne USB-enheten er tilkoblet?"</string>
diff --git a/packages/SystemUI/res/values-nl/strings.xml b/packages/SystemUI/res/values-nl/strings.xml
index 5314ba3..e05e2c9 100644
--- a/packages/SystemUI/res/values-nl/strings.xml
+++ b/packages/SystemUI/res/values-nl/strings.xml
@@ -48,8 +48,7 @@
<string name="status_bar_settings_notifications" msgid="397146176280905137">"Meldingen"</string>
<string name="bluetooth_tethered" msgid="7094101612161133267">"Bluetooth getetherd"</string>
<string name="status_bar_input_method_settings_configure_input_methods" msgid="3504292471512317827">"Invoermethoden instellen"</string>
- <!-- no translation found for status_bar_use_physical_keyboard (7551903084416057810) -->
- <skip />
+ <string name="status_bar_use_physical_keyboard" msgid="7551903084416057810">"Fysiek toetsenbord"</string>
<string name="usb_device_permission_prompt" msgid="834698001271562057">"De app <xliff:g id="APPLICATION">%1$s</xliff:g> toegang geven tot het USB-apparaat?"</string>
<string name="usb_accessory_permission_prompt" msgid="5171775411178865750">"De app <xliff:g id="APPLICATION">%1$s</xliff:g> toegang geven tot het USB-accessoire?"</string>
<string name="usb_device_confirm_prompt" msgid="5161205258635253206">"<xliff:g id="ACTIVITY">%1$s</xliff:g> openen wanneer dit USB-apparaat wordt aangesloten?"</string>
diff --git a/packages/SystemUI/res/values-pl/strings.xml b/packages/SystemUI/res/values-pl/strings.xml
index 26e3989..0618eb5 100644
--- a/packages/SystemUI/res/values-pl/strings.xml
+++ b/packages/SystemUI/res/values-pl/strings.xml
@@ -48,8 +48,7 @@
<string name="status_bar_settings_notifications" msgid="397146176280905137">"Powiadomienia"</string>
<string name="bluetooth_tethered" msgid="7094101612161133267">"Bluetooth – podłączono"</string>
<string name="status_bar_input_method_settings_configure_input_methods" msgid="3504292471512317827">"Konfiguruj metody wprowadzania"</string>
- <!-- no translation found for status_bar_use_physical_keyboard (7551903084416057810) -->
- <skip />
+ <string name="status_bar_use_physical_keyboard" msgid="7551903084416057810">"Klawiatura fizyczna"</string>
<string name="usb_device_permission_prompt" msgid="834698001271562057">"Zezwolić aplikacji <xliff:g id="APPLICATION">%1$s</xliff:g> na dostęp do urządzenia USB?"</string>
<string name="usb_accessory_permission_prompt" msgid="5171775411178865750">"Zezwolić aplikacji <xliff:g id="APPLICATION">%1$s</xliff:g> na dostęp do urządzenia USB?"</string>
<string name="usb_device_confirm_prompt" msgid="5161205258635253206">"Czy otworzyć <xliff:g id="ACTIVITY">%1$s</xliff:g> po podłączeniu tego urządzenia USB?"</string>
diff --git a/packages/SystemUI/res/values-pt-rPT/strings.xml b/packages/SystemUI/res/values-pt-rPT/strings.xml
index a5999e3..6a278ba 100644
--- a/packages/SystemUI/res/values-pt-rPT/strings.xml
+++ b/packages/SystemUI/res/values-pt-rPT/strings.xml
@@ -48,8 +48,7 @@
<string name="status_bar_settings_notifications" msgid="397146176280905137">"Notificações"</string>
<string name="bluetooth_tethered" msgid="7094101612161133267">"Bluetooth ligado"</string>
<string name="status_bar_input_method_settings_configure_input_methods" msgid="3504292471512317827">"Configurar métodos introdução"</string>
- <!-- no translation found for status_bar_use_physical_keyboard (7551903084416057810) -->
- <skip />
+ <string name="status_bar_use_physical_keyboard" msgid="7551903084416057810">"Teclado físico"</string>
<string name="usb_device_permission_prompt" msgid="834698001271562057">"Permitir que a aplicação <xliff:g id="APPLICATION">%1$s</xliff:g> aceda ao dispositivo USB?"</string>
<string name="usb_accessory_permission_prompt" msgid="5171775411178865750">"Permitir que a aplicação <xliff:g id="APPLICATION">%1$s</xliff:g> aceda ao acessório USB?"</string>
<string name="usb_device_confirm_prompt" msgid="5161205258635253206">"Abrir <xliff:g id="ACTIVITY">%1$s</xliff:g> quando este dispositivo USB estiver ligado?"</string>
diff --git a/packages/SystemUI/res/values-pt/strings.xml b/packages/SystemUI/res/values-pt/strings.xml
index 02bef77..23a2ba5 100644
--- a/packages/SystemUI/res/values-pt/strings.xml
+++ b/packages/SystemUI/res/values-pt/strings.xml
@@ -48,8 +48,7 @@
<string name="status_bar_settings_notifications" msgid="397146176280905137">"Notificações"</string>
<string name="bluetooth_tethered" msgid="7094101612161133267">"Bluetooth vinculado"</string>
<string name="status_bar_input_method_settings_configure_input_methods" msgid="3504292471512317827">"Configurar métodos de entrada"</string>
- <!-- no translation found for status_bar_use_physical_keyboard (7551903084416057810) -->
- <skip />
+ <string name="status_bar_use_physical_keyboard" msgid="7551903084416057810">"Teclado físico"</string>
<string name="usb_device_permission_prompt" msgid="834698001271562057">"Permitir que o aplicativo <xliff:g id="APPLICATION">%1$s</xliff:g> acesse o dispositivo USB?"</string>
<string name="usb_accessory_permission_prompt" msgid="5171775411178865750">"Permitir que o aplicativo <xliff:g id="APPLICATION">%1$s</xliff:g> acesse o acessório USB?"</string>
<string name="usb_device_confirm_prompt" msgid="5161205258635253206">"Abrir <xliff:g id="ACTIVITY">%1$s</xliff:g> quando este dispositivo USB estiver conectado?"</string>
diff --git a/packages/SystemUI/res/values-ro/strings.xml b/packages/SystemUI/res/values-ro/strings.xml
index ff6ca3d..b778e4d 100644
--- a/packages/SystemUI/res/values-ro/strings.xml
+++ b/packages/SystemUI/res/values-ro/strings.xml
@@ -48,8 +48,7 @@
<string name="status_bar_settings_notifications" msgid="397146176280905137">"Notificări"</string>
<string name="bluetooth_tethered" msgid="7094101612161133267">"Conectat prin tethering prin Bluetooth"</string>
<string name="status_bar_input_method_settings_configure_input_methods" msgid="3504292471512317827">"Configuraţi metode de intrare"</string>
- <!-- no translation found for status_bar_use_physical_keyboard (7551903084416057810) -->
- <skip />
+ <string name="status_bar_use_physical_keyboard" msgid="7551903084416057810">"Tastatură fizică"</string>
<string name="usb_device_permission_prompt" msgid="834698001271562057">"Permiteţi aplicaţiei <xliff:g id="APPLICATION">%1$s</xliff:g> să acceseze dispozitivul USB?"</string>
<string name="usb_accessory_permission_prompt" msgid="5171775411178865750">"Permiteţi aplicaţiei <xliff:g id="APPLICATION">%1$s</xliff:g> să acceseze accesoriul USB?"</string>
<string name="usb_device_confirm_prompt" msgid="5161205258635253206">"Deschideţi <xliff:g id="ACTIVITY">%1$s</xliff:g> la conectarea acestui dispozitiv USB?"</string>
diff --git a/packages/SystemUI/res/values-ru/strings.xml b/packages/SystemUI/res/values-ru/strings.xml
index 4057599..3753309 100644
--- a/packages/SystemUI/res/values-ru/strings.xml
+++ b/packages/SystemUI/res/values-ru/strings.xml
@@ -48,8 +48,7 @@
<string name="status_bar_settings_notifications" msgid="397146176280905137">"Уведомления"</string>
<string name="bluetooth_tethered" msgid="7094101612161133267">"Общий модем доступен через Bluetooth"</string>
<string name="status_bar_input_method_settings_configure_input_methods" msgid="3504292471512317827">"Настройка способов ввода"</string>
- <!-- no translation found for status_bar_use_physical_keyboard (7551903084416057810) -->
- <skip />
+ <string name="status_bar_use_physical_keyboard" msgid="7551903084416057810">"Физическая клавиатура"</string>
<string name="usb_device_permission_prompt" msgid="834698001271562057">"Открыть приложению \"<xliff:g id="APPLICATION">%1$s</xliff:g>\" доступ к USB-устройству?"</string>
<string name="usb_accessory_permission_prompt" msgid="5171775411178865750">"Открыть приложению \"<xliff:g id="APPLICATION">%1$s</xliff:g>\" доступ к USB-устройству?"</string>
<string name="usb_device_confirm_prompt" msgid="5161205258635253206">"Запускать <xliff:g id="ACTIVITY">%1$s</xliff:g> при подключении этого USB-устройства?"</string>
diff --git a/packages/SystemUI/res/values-sk/strings.xml b/packages/SystemUI/res/values-sk/strings.xml
index 67368ac..599f99c 100644
--- a/packages/SystemUI/res/values-sk/strings.xml
+++ b/packages/SystemUI/res/values-sk/strings.xml
@@ -48,8 +48,7 @@
<string name="status_bar_settings_notifications" msgid="397146176280905137">"Upozornenia"</string>
<string name="bluetooth_tethered" msgid="7094101612161133267">"Zdieľané dátové pripojenie cez Bluetooth"</string>
<string name="status_bar_input_method_settings_configure_input_methods" msgid="3504292471512317827">"Nastavenie metód vstupu"</string>
- <!-- no translation found for status_bar_use_physical_keyboard (7551903084416057810) -->
- <skip />
+ <string name="status_bar_use_physical_keyboard" msgid="7551903084416057810">"Fyzická klávesnica"</string>
<string name="usb_device_permission_prompt" msgid="834698001271562057">"Povoliť aplikácii <xliff:g id="APPLICATION">%1$s</xliff:g> prístup k zariadeniu USB?"</string>
<string name="usb_accessory_permission_prompt" msgid="5171775411178865750">"Povoliť aplikácii <xliff:g id="APPLICATION">%1$s</xliff:g> prístup k periférnemu zariadeniu USB?"</string>
<string name="usb_device_confirm_prompt" msgid="5161205258635253206">"Chcete pri pripojení tohto zariadenia USB otvoriť aplikáciu <xliff:g id="ACTIVITY">%1$s</xliff:g>?"</string>
diff --git a/packages/SystemUI/res/values-sl/strings.xml b/packages/SystemUI/res/values-sl/strings.xml
index 77aef3d..fb229e2 100644
--- a/packages/SystemUI/res/values-sl/strings.xml
+++ b/packages/SystemUI/res/values-sl/strings.xml
@@ -48,8 +48,7 @@
<string name="status_bar_settings_notifications" msgid="397146176280905137">"Obvestila"</string>
<string name="bluetooth_tethered" msgid="7094101612161133267">"Internetna povezava prek Bluetootha"</string>
<string name="status_bar_input_method_settings_configure_input_methods" msgid="3504292471512317827">"Nastavi načine vnosa"</string>
- <!-- no translation found for status_bar_use_physical_keyboard (7551903084416057810) -->
- <skip />
+ <string name="status_bar_use_physical_keyboard" msgid="7551903084416057810">"Fizična tipkovnica"</string>
<string name="usb_device_permission_prompt" msgid="834698001271562057">"Želite programu <xliff:g id="APPLICATION">%1$s</xliff:g> dovoliti dostop do naprave USB?"</string>
<string name="usb_accessory_permission_prompt" msgid="5171775411178865750">"Želite dovoliti programu <xliff:g id="APPLICATION">%1$s</xliff:g> dostop do dodatka USB?"</string>
<string name="usb_device_confirm_prompt" msgid="5161205258635253206">"Želite, da se odpre <xliff:g id="ACTIVITY">%1$s</xliff:g>, ko priključite to napravo USB?"</string>
diff --git a/packages/SystemUI/res/values-sr/strings.xml b/packages/SystemUI/res/values-sr/strings.xml
index 3268544..fb7c21a 100644
--- a/packages/SystemUI/res/values-sr/strings.xml
+++ b/packages/SystemUI/res/values-sr/strings.xml
@@ -48,8 +48,7 @@
<string name="status_bar_settings_notifications" msgid="397146176280905137">"Обавештења"</string>
<string name="bluetooth_tethered" msgid="7094101612161133267">"Веза преко Bluetooth-а"</string>
<string name="status_bar_input_method_settings_configure_input_methods" msgid="3504292471512317827">"Подеси методе уноса"</string>
- <!-- no translation found for status_bar_use_physical_keyboard (7551903084416057810) -->
- <skip />
+ <string name="status_bar_use_physical_keyboard" msgid="7551903084416057810">"Физичка тастатура"</string>
<string name="usb_device_permission_prompt" msgid="834698001271562057">"Желите ли да дозволите апликацији <xliff:g id="APPLICATION">%1$s</xliff:g> да приступа USB уређају?"</string>
<string name="usb_accessory_permission_prompt" msgid="5171775411178865750">"Желите ли да дозволите апликацији <xliff:g id="APPLICATION">%1$s</xliff:g> да приступа USB помоћном уређају?"</string>
<string name="usb_device_confirm_prompt" msgid="5161205258635253206">"Желите ли да се отвори <xliff:g id="ACTIVITY">%1$s</xliff:g> када се прикључи овај USB уређај?"</string>
diff --git a/packages/SystemUI/res/values-sv/strings.xml b/packages/SystemUI/res/values-sv/strings.xml
index ba4edea..8eaa126 100644
--- a/packages/SystemUI/res/values-sv/strings.xml
+++ b/packages/SystemUI/res/values-sv/strings.xml
@@ -48,8 +48,7 @@
<string name="status_bar_settings_notifications" msgid="397146176280905137">"Aviseringar"</string>
<string name="bluetooth_tethered" msgid="7094101612161133267">"Internetdelning via Bluetooth"</string>
<string name="status_bar_input_method_settings_configure_input_methods" msgid="3504292471512317827">"Konfigurera inmatningsmetoder"</string>
- <!-- no translation found for status_bar_use_physical_keyboard (7551903084416057810) -->
- <skip />
+ <string name="status_bar_use_physical_keyboard" msgid="7551903084416057810">"Fysiskt tangentbord"</string>
<string name="usb_device_permission_prompt" msgid="834698001271562057">"Vill du tillåta att appen <xliff:g id="APPLICATION">%1$s</xliff:g> använder USB-enheten?"</string>
<string name="usb_accessory_permission_prompt" msgid="5171775411178865750">"Vill du tillåta att appen <xliff:g id="APPLICATION">%1$s</xliff:g> använder USB-tillbehöret?"</string>
<string name="usb_device_confirm_prompt" msgid="5161205258635253206">"Vill du öppna <xliff:g id="ACTIVITY">%1$s</xliff:g> när den här USB-enheten ansluts?"</string>
diff --git a/packages/SystemUI/res/values-sw/strings.xml b/packages/SystemUI/res/values-sw/strings.xml
index 8a6b050..19bd4ab 100644
--- a/packages/SystemUI/res/values-sw/strings.xml
+++ b/packages/SystemUI/res/values-sw/strings.xml
@@ -46,8 +46,7 @@
<string name="status_bar_settings_notifications" msgid="397146176280905137">"Arifa"</string>
<string name="bluetooth_tethered" msgid="7094101612161133267">"Bluetooth imefungwa"</string>
<string name="status_bar_input_method_settings_configure_input_methods" msgid="3504292471512317827">"Weka mbinu za ingizo"</string>
- <!-- no translation found for status_bar_use_physical_keyboard (7551903084416057810) -->
- <skip />
+ <string name="status_bar_use_physical_keyboard" msgid="7551903084416057810">"Kibodi halisi"</string>
<string name="usb_device_permission_prompt" msgid="834698001271562057">"Ruhusu programu <xliff:g id="APPLICATION">%1$s</xliff:g> kufikia kifaa cha USB?"</string>
<string name="usb_accessory_permission_prompt" msgid="5171775411178865750">"Ruhusu programu <xliff:g id="APPLICATION">%1$s</xliff:g> kufikia kifaa cha ziada cha USB?"</string>
<string name="usb_device_confirm_prompt" msgid="5161205258635253206">"Je, ungetaka kufungua <xliff:g id="ACTIVITY">%1$s</xliff:g>wakati kifaa cha USB kimeunganishwa?"</string>
diff --git a/packages/SystemUI/res/values-th/strings.xml b/packages/SystemUI/res/values-th/strings.xml
index 42c4721..82c5dd7 100644
--- a/packages/SystemUI/res/values-th/strings.xml
+++ b/packages/SystemUI/res/values-th/strings.xml
@@ -48,8 +48,7 @@
<string name="status_bar_settings_notifications" msgid="397146176280905137">"การแจ้งเตือน"</string>
<string name="bluetooth_tethered" msgid="7094101612161133267">"บลูทูธที่ปล่อยสัญญาณ"</string>
<string name="status_bar_input_method_settings_configure_input_methods" msgid="3504292471512317827">"ตั้งค่าวิธีการป้อนข้อมูล"</string>
- <!-- no translation found for status_bar_use_physical_keyboard (7551903084416057810) -->
- <skip />
+ <string name="status_bar_use_physical_keyboard" msgid="7551903084416057810">"แป้นพิมพ์บนเครื่อง"</string>
<string name="usb_device_permission_prompt" msgid="834698001271562057">"อนุญาตให้แอปพลิเคชัน <xliff:g id="APPLICATION">%1$s</xliff:g> เข้าถึงอุปกรณ์ USB นี้หรือไม่"</string>
<string name="usb_accessory_permission_prompt" msgid="5171775411178865750">"อนุญาตให้แอปพลิเคชัน <xliff:g id="APPLICATION">%1$s</xliff:g> เข้าถึงอุปกรณ์เสริม USB นี้หรือไม่"</string>
<string name="usb_device_confirm_prompt" msgid="5161205258635253206">"เปิด <xliff:g id="ACTIVITY">%1$s</xliff:g> เมื่อมีการเชื่อมต่ออุปกรณ์ USB นี้หรือไม่"</string>
diff --git a/packages/SystemUI/res/values-tl/strings.xml b/packages/SystemUI/res/values-tl/strings.xml
index 55ecfae..2054121 100644
--- a/packages/SystemUI/res/values-tl/strings.xml
+++ b/packages/SystemUI/res/values-tl/strings.xml
@@ -48,8 +48,7 @@
<string name="status_bar_settings_notifications" msgid="397146176280905137">"Mga Notification"</string>
<string name="bluetooth_tethered" msgid="7094101612161133267">"Na-tether ang bluetooth"</string>
<string name="status_bar_input_method_settings_configure_input_methods" msgid="3504292471512317827">"I-set up paraan ng pag-input"</string>
- <!-- no translation found for status_bar_use_physical_keyboard (7551903084416057810) -->
- <skip />
+ <string name="status_bar_use_physical_keyboard" msgid="7551903084416057810">"Aktwal na keyboard"</string>
<string name="usb_device_permission_prompt" msgid="834698001271562057">"Payagan ang app na <xliff:g id="APPLICATION">%1$s</xliff:g> na i-access ang USB device?"</string>
<string name="usb_accessory_permission_prompt" msgid="5171775411178865750">"Payagan ang app na <xliff:g id="APPLICATION">%1$s</xliff:g> na i-access ang USB accessory?"</string>
<string name="usb_device_confirm_prompt" msgid="5161205258635253206">"Buksan ang <xliff:g id="ACTIVITY">%1$s</xliff:g> kapag nakakonekta ang USB device na ito?"</string>
diff --git a/packages/SystemUI/res/values-tr/strings.xml b/packages/SystemUI/res/values-tr/strings.xml
index f0aa516..ca422f7 100644
--- a/packages/SystemUI/res/values-tr/strings.xml
+++ b/packages/SystemUI/res/values-tr/strings.xml
@@ -48,8 +48,7 @@
<string name="status_bar_settings_notifications" msgid="397146176280905137">"Bildirimler"</string>
<string name="bluetooth_tethered" msgid="7094101612161133267">"Bluetooth paylaşımı tamam"</string>
<string name="status_bar_input_method_settings_configure_input_methods" msgid="3504292471512317827">"Giriş yöntemlerini ayarla"</string>
- <!-- no translation found for status_bar_use_physical_keyboard (7551903084416057810) -->
- <skip />
+ <string name="status_bar_use_physical_keyboard" msgid="7551903084416057810">"Fiziksel klavye"</string>
<string name="usb_device_permission_prompt" msgid="834698001271562057">"<xliff:g id="APPLICATION">%1$s</xliff:g> uygulamasının USB cihazına erişmesine izin verilsin mi?"</string>
<string name="usb_accessory_permission_prompt" msgid="5171775411178865750">"<xliff:g id="APPLICATION">%1$s</xliff:g> uygulamasının USB aksesuarına erişmesine izin verilsin mi?"</string>
<string name="usb_device_confirm_prompt" msgid="5161205258635253206">"Bu USB cihaz bağlandığında <xliff:g id="ACTIVITY">%1$s</xliff:g> açılsın mı?"</string>
diff --git a/packages/SystemUI/res/values-uk/strings.xml b/packages/SystemUI/res/values-uk/strings.xml
index 9a05919..8a13400 100644
--- a/packages/SystemUI/res/values-uk/strings.xml
+++ b/packages/SystemUI/res/values-uk/strings.xml
@@ -48,8 +48,7 @@
<string name="status_bar_settings_notifications" msgid="397146176280905137">"Сповіщення"</string>
<string name="bluetooth_tethered" msgid="7094101612161133267">"Створено прив\'язку Bluetooth"</string>
<string name="status_bar_input_method_settings_configure_input_methods" msgid="3504292471512317827">"Налаштувати методи введення"</string>
- <!-- no translation found for status_bar_use_physical_keyboard (7551903084416057810) -->
- <skip />
+ <string name="status_bar_use_physical_keyboard" msgid="7551903084416057810">"Фізична клавіатура"</string>
<string name="usb_device_permission_prompt" msgid="834698001271562057">"Надати програмі <xliff:g id="APPLICATION">%1$s</xliff:g> доступ до пристрою USB?"</string>
<string name="usb_accessory_permission_prompt" msgid="5171775411178865750">"Надати програмі <xliff:g id="APPLICATION">%1$s</xliff:g> доступ до аксесуара USB?"</string>
<string name="usb_device_confirm_prompt" msgid="5161205258635253206">"Відкривати \"<xliff:g id="ACTIVITY">%1$s</xliff:g>\", коли під’єднано пристрій USB?"</string>
diff --git a/packages/SystemUI/res/values-vi/strings.xml b/packages/SystemUI/res/values-vi/strings.xml
index abd024a..05ab87c 100644
--- a/packages/SystemUI/res/values-vi/strings.xml
+++ b/packages/SystemUI/res/values-vi/strings.xml
@@ -48,8 +48,7 @@
<string name="status_bar_settings_notifications" msgid="397146176280905137">"Thông báo"</string>
<string name="bluetooth_tethered" msgid="7094101612161133267">"Bluetooth được dùng làm điểm truy cập Internet"</string>
<string name="status_bar_input_method_settings_configure_input_methods" msgid="3504292471512317827">"Thiết lập phương thức nhập"</string>
- <!-- no translation found for status_bar_use_physical_keyboard (7551903084416057810) -->
- <skip />
+ <string name="status_bar_use_physical_keyboard" msgid="7551903084416057810">"Bàn phím thực"</string>
<string name="usb_device_permission_prompt" msgid="834698001271562057">"Cho phép ứng dụng <xliff:g id="APPLICATION">%1$s</xliff:g> truy cập thiết bị USB?"</string>
<string name="usb_accessory_permission_prompt" msgid="5171775411178865750">"Cho phép ứng dụng <xliff:g id="APPLICATION">%1$s</xliff:g> truy cập phụ kiện USB?"</string>
<string name="usb_device_confirm_prompt" msgid="5161205258635253206">"Mở <xliff:g id="ACTIVITY">%1$s</xliff:g> khi thiết bị USB này được kết nối?"</string>
diff --git a/packages/SystemUI/res/values-zh-rCN/strings.xml b/packages/SystemUI/res/values-zh-rCN/strings.xml
index ec92713c..c862d74 100644
--- a/packages/SystemUI/res/values-zh-rCN/strings.xml
+++ b/packages/SystemUI/res/values-zh-rCN/strings.xml
@@ -48,8 +48,7 @@
<string name="status_bar_settings_notifications" msgid="397146176280905137">"通知"</string>
<string name="bluetooth_tethered" msgid="7094101612161133267">"已通过蓝牙共享网络"</string>
<string name="status_bar_input_method_settings_configure_input_methods" msgid="3504292471512317827">"设置输入法"</string>
- <!-- no translation found for status_bar_use_physical_keyboard (7551903084416057810) -->
- <skip />
+ <string name="status_bar_use_physical_keyboard" msgid="7551903084416057810">"物理键盘"</string>
<string name="usb_device_permission_prompt" msgid="834698001271562057">"允许应用“<xliff:g id="APPLICATION">%1$s</xliff:g>”访问该 USB 设备吗?"</string>
<string name="usb_accessory_permission_prompt" msgid="5171775411178865750">"允许应用“<xliff:g id="APPLICATION">%1$s</xliff:g>”访问该 USB 配件吗?"</string>
<string name="usb_device_confirm_prompt" msgid="5161205258635253206">"要在连接此 USB 设备时打开<xliff:g id="ACTIVITY">%1$s</xliff:g>吗?"</string>
diff --git a/packages/SystemUI/res/values-zh-rTW/strings.xml b/packages/SystemUI/res/values-zh-rTW/strings.xml
index cabc243..399890b 100644
--- a/packages/SystemUI/res/values-zh-rTW/strings.xml
+++ b/packages/SystemUI/res/values-zh-rTW/strings.xml
@@ -48,8 +48,7 @@
<string name="status_bar_settings_notifications" msgid="397146176280905137">"通知"</string>
<string name="bluetooth_tethered" msgid="7094101612161133267">"藍牙網路共用已開"</string>
<string name="status_bar_input_method_settings_configure_input_methods" msgid="3504292471512317827">"設定輸入法"</string>
- <!-- no translation found for status_bar_use_physical_keyboard (7551903084416057810) -->
- <skip />
+ <string name="status_bar_use_physical_keyboard" msgid="7551903084416057810">"實體鍵盤"</string>
<string name="usb_device_permission_prompt" msgid="834698001271562057">"允許 <xliff:g id="APPLICATION">%1$s</xliff:g> 應用程式存取 USB 裝置嗎?"</string>
<string name="usb_accessory_permission_prompt" msgid="5171775411178865750">"允許 <xliff:g id="APPLICATION">%1$s</xliff:g> 應用程式存取 USB 配件嗎?"</string>
<string name="usb_device_confirm_prompt" msgid="5161205258635253206">"連接這個 USB 裝置時啟用 <xliff:g id="ACTIVITY">%1$s</xliff:g> 嗎?"</string>
diff --git a/packages/SystemUI/res/values-zu/strings.xml b/packages/SystemUI/res/values-zu/strings.xml
index 27dd8fd..91f6566 100644
--- a/packages/SystemUI/res/values-zu/strings.xml
+++ b/packages/SystemUI/res/values-zu/strings.xml
@@ -48,8 +48,7 @@
<string name="status_bar_settings_notifications" msgid="397146176280905137">"Izaziso"</string>
<string name="bluetooth_tethered" msgid="7094101612161133267">"Ukusebenzisa i-Bluetooth njengemodemu"</string>
<string name="status_bar_input_method_settings_configure_input_methods" msgid="3504292471512317827">"Izilungiselelo zezindlela zokufakwayo"</string>
- <!-- no translation found for status_bar_use_physical_keyboard (7551903084416057810) -->
- <skip />
+ <string name="status_bar_use_physical_keyboard" msgid="7551903084416057810">"Ukwakheka kwekhibhodi"</string>
<string name="usb_device_permission_prompt" msgid="834698001271562057">"Vumela insiza <xliff:g id="APPLICATION">%1$s</xliff:g> ukuthi ufinyelele ezintweni eziphuma ne-USB?"</string>
<string name="usb_accessory_permission_prompt" msgid="5171775411178865750">"Vumela insiza <xliff:g id="APPLICATION">%1$s</xliff:g> ukuthi ufinyelele ezintweni eziphuma ne-USB?"</string>
<string name="usb_device_confirm_prompt" msgid="5161205258635253206">"Vula <xliff:g id="ACTIVITY">%1$s</xliff:g> uma ledivayisi ye-USB ixhunyiwe?"</string>
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index 4441ca6..f786e86 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -55,6 +55,13 @@
<!-- Height of notification icons in the status bar -->
<dimen name="status_bar_icon_size">@*android:dimen/status_bar_icon_size</dimen>
+ <!-- Height of a small notification in the status bar -->
+ <dimen name="notification_min_height">@android:dimen/notification_large_icon_height</dimen>
+
+ <!-- Height of a small notification in the status bar -->
+ <!-- TODO: change this back to 256dp once we deal with actions. -->
+ <dimen name="notification_max_height">320dp</dimen>
+
<!-- size at which Notification icons will be drawn in the status bar -->
<dimen name="status_bar_icon_drawing_size">18dip</dimen>
diff --git a/packages/SystemUI/src/com/android/systemui/ExpandHelper.java b/packages/SystemUI/src/com/android/systemui/ExpandHelper.java
new file mode 100644
index 0000000..aa289da
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/ExpandHelper.java
@@ -0,0 +1,199 @@
+/*
+ * Copyright (C) 2012 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.systemui;
+
+import android.animation.ObjectAnimator;
+import android.content.Context;
+import android.graphics.RectF;
+import android.util.Log;
+import android.view.MotionEvent;
+import android.view.ScaleGestureDetector;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.View.OnClickListener;
+import com.android.internal.widget.SizeAdaptiveLayout;
+
+public class ExpandHelper implements Gefingerpoken, OnClickListener {
+ public interface Callback {
+ View getChildAtPosition(MotionEvent ev);
+ View getChildAtPosition(float x, float y);
+ }
+
+ private static final String TAG = "ExpandHelper";
+ protected static final boolean DEBUG = false;
+ private static final long EXPAND_DURATION = 250;
+
+ @SuppressWarnings("unused")
+ private Context mContext;
+
+ private boolean mStretching;
+ private View mCurrView;
+ private float mOldHeight;
+ private float mNaturalHeight;
+ private float mInitialTouchSpan;
+ private Callback mCallback;
+ private ScaleGestureDetector mDetector;
+ private ViewScaler mScaler;
+ private ObjectAnimator mAnimation;
+
+ private int mSmallSize;
+ private int mLargeSize;
+
+
+ private class ViewScaler {
+ View mView;
+ public ViewScaler() {}
+ public void setView(View v) {
+ mView = v;
+ }
+ public void setHeight(float h) {
+ Log.v(TAG, "SetHeight: setting to " + h);
+ ViewGroup.LayoutParams lp = mView.getLayoutParams();
+ lp.height = (int)h;
+ mView.setLayoutParams(lp);
+ mView.requestLayout();
+ }
+ public float getHeight() {
+ int height = mView.getLayoutParams().height;
+ if (height < 0) {
+ height = mView.getMeasuredHeight();
+ }
+ return (float) height;
+ }
+ public int getNaturalHeight(int maximum) {
+ ViewGroup.LayoutParams lp = mView.getLayoutParams();
+ if (DEBUG) Log.v(TAG, "Inspecting a child of type: " + mView.getClass().getName());
+ int oldHeight = lp.height;
+ lp.height = ViewGroup.LayoutParams.WRAP_CONTENT;
+ mView.setLayoutParams(lp);
+ mView.measure(
+ View.MeasureSpec.makeMeasureSpec(mView.getMeasuredWidth(),
+ View.MeasureSpec.EXACTLY),
+ View.MeasureSpec.makeMeasureSpec(maximum,
+ View.MeasureSpec.AT_MOST));
+ lp.height = oldHeight;
+ mView.setLayoutParams(lp);
+ return mView.getMeasuredHeight();
+ }
+ }
+
+ public ExpandHelper(Context context, Callback callback, int small, int large) {
+ mSmallSize = small;
+ mLargeSize = large;
+ mContext = context;
+ mCallback = callback;
+ mScaler = new ViewScaler();
+ mDetector =
+ new ScaleGestureDetector(context,
+ new ScaleGestureDetector.SimpleOnScaleGestureListener() {
+ @Override
+ public boolean onScaleBegin(ScaleGestureDetector detector) {
+ if (DEBUG) Log.v(TAG, "onscalebegin()");
+ View v = mCallback.getChildAtPosition(detector.getFocusX(), detector.getFocusY());
+
+ // your fingers have to be somewhat close to the bounds of the view in question
+ mInitialTouchSpan = Math.abs(detector.getCurrentSpanY());
+ if (DEBUG) Log.d(TAG, "got mInitialTouchSpan: " + mInitialTouchSpan);
+
+ mStretching = initScale(v);
+ return mStretching;
+ }
+
+ @Override
+ public boolean onScale(ScaleGestureDetector detector) {
+ if (DEBUG) Log.v(TAG, "onscale() on " + mCurrView);
+ float h = Math.abs(detector.getCurrentSpanY());
+ if (DEBUG) Log.d(TAG, "current span is: " + h);
+ h = h + mOldHeight - mInitialTouchSpan;
+ h = h<mSmallSize?mSmallSize:(h>mLargeSize?mLargeSize:h);
+ h = h>mNaturalHeight?mNaturalHeight:h;
+ if (DEBUG) Log.d(TAG, "scale continues: h=" + h);
+ mScaler.setHeight(h);
+ return true;
+ }
+
+ @Override
+ public void onScaleEnd(ScaleGestureDetector detector) {
+ if (DEBUG) Log.v(TAG, "onscaleend()");
+ // I guess we're alone now
+ if (DEBUG) Log.d(TAG, "scale end");
+ finishScale(false);
+ }
+ });
+ }
+
+ public boolean onInterceptTouchEvent(MotionEvent ev) {
+ if (DEBUG) Log.d(TAG, "interceptTouch: act=" + (ev.getAction()) +
+ " stretching=" + mStretching);
+ mDetector.onTouchEvent(ev);
+ return mStretching;
+ }
+
+ public boolean onTouchEvent(MotionEvent ev) {
+ final int action = ev.getAction();
+ if (DEBUG) Log.d(TAG, "touch: act=" + (action) + " stretching=" + mStretching);
+ if (mStretching) {
+ mDetector.onTouchEvent(ev);
+ }
+ switch (action) {
+ case MotionEvent.ACTION_UP:
+ case MotionEvent.ACTION_CANCEL:
+ mStretching = false;
+ mCurrView = null;
+ break;
+ }
+ return true;
+ }
+ private boolean initScale(View v) {
+ if (v != null) {
+ if (DEBUG) Log.d(TAG, "scale begins on view: " + v);
+ mStretching = true;
+ mCurrView = v;
+ mScaler.setView(v);
+ mOldHeight = mScaler.getHeight();
+ mNaturalHeight = mScaler.getNaturalHeight(mLargeSize);
+ if (DEBUG) Log.d(TAG, "got mOldHeight: " + mOldHeight +
+ " mNaturalHeight: " + mNaturalHeight);
+ v.getParent().requestDisallowInterceptTouchEvent(true);
+ if (DEBUG) v.setBackgroundColor(0xFFFFFF00);
+ }
+ return mStretching;
+ }
+
+ private void finishScale(boolean force) {
+ float h = mScaler.getHeight();
+ final boolean wasClosed = (mOldHeight == mSmallSize);
+ if (wasClosed) {
+ h = (force || h > mSmallSize) ? mNaturalHeight : mSmallSize;
+ } else {
+ h = (force || h < mNaturalHeight) ? mSmallSize : mNaturalHeight;
+ }
+ if (DEBUG) mCurrView.setBackgroundColor(0);
+ mAnimation = ObjectAnimator.ofFloat(mScaler, "height", h).setDuration(EXPAND_DURATION);
+ mAnimation.start();
+ mStretching = false;
+ mCurrView = null;
+ }
+
+ @Override
+ public void onClick(View v) {
+ initScale(v);
+ finishScale(true);
+
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/Gefingerpoken.java b/packages/SystemUI/src/com/android/systemui/Gefingerpoken.java
new file mode 100644
index 0000000..b2d5c21
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/Gefingerpoken.java
@@ -0,0 +1,25 @@
+/*
+ * Copyright (C) 2012 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.systemui;
+
+import android.view.MotionEvent;
+
+// ACHTUNG!
+public interface Gefingerpoken {
+ boolean onInterceptTouchEvent(MotionEvent ev);
+ boolean onTouchEvent(MotionEvent ev);
+}
diff --git a/packages/SystemUI/src/com/android/systemui/SwipeHelper.java b/packages/SystemUI/src/com/android/systemui/SwipeHelper.java
index 276ca21..19657a9 100644
--- a/packages/SystemUI/src/com/android/systemui/SwipeHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/SwipeHelper.java
@@ -29,7 +29,7 @@
import android.view.VelocityTracker;
import android.view.View;
-public class SwipeHelper {
+public class SwipeHelper implements Gefingerpoken {
static final String TAG = "com.android.systemui.SwipeHelper";
private static final boolean DEBUG = false;
private static final boolean DEBUG_INVALIDATE = false;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
index 8d7afc8..ede8e7a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
@@ -18,9 +18,14 @@
import java.util.ArrayList;
+import android.app.ActivityManagerNative;
+import android.app.KeyguardManager;
+import android.app.PendingIntent;
import android.content.Context;
+import android.content.Intent;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager.NameNotFoundException;
+import android.graphics.Rect;
import android.os.Build;
import android.os.Handler;
import android.os.IBinder;
@@ -34,15 +39,18 @@
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
+import android.view.ViewGroup;
import android.view.ViewGroup.LayoutParams;
import android.view.WindowManager;
import android.view.WindowManagerImpl;
import android.widget.LinearLayout;
+import android.widget.RemoteViews;
import com.android.internal.statusbar.IStatusBarService;
import com.android.internal.statusbar.StatusBarIcon;
import com.android.internal.statusbar.StatusBarIconList;
import com.android.internal.statusbar.StatusBarNotification;
+import com.android.internal.widget.SizeAdaptiveLayout;
import com.android.systemui.SystemUI;
import com.android.systemui.recent.RecentsPanelView;
import com.android.systemui.recent.RecentTasksLoader;
@@ -66,12 +74,15 @@
protected IStatusBarService mBarService;
protected H mHandler = createHandler();
+ // used to notify status bar for suppressing notification LED
+ protected boolean mPanelSlightlyVisible;
+
// Recent apps
protected RecentsPanelView mRecentsPanel;
protected RecentTasksLoader mRecentTasksLoader;
// UI-specific methods
-
+
/**
* Create all windows necessary for the status bar (including navigation, overlay panels, etc)
* and add them to the window manager.
@@ -81,15 +92,15 @@
protected Display mDisplay;
private IWindowManager mWindowManager;
-
+
public IWindowManager getWindowManager() {
return mWindowManager;
}
-
+
public Display getDisplay() {
return mDisplay;
}
-
+
public IStatusBarService getStatusBarService() {
return mBarService;
}
@@ -109,7 +120,7 @@
ArrayList<IBinder> notificationKeys = new ArrayList<IBinder>();
ArrayList<StatusBarNotification> notifications = new ArrayList<StatusBarNotification>();
mCommandQueue = new CommandQueue(this, iconList);
-
+
int[] switches = new int[7];
ArrayList<IBinder> binders = new ArrayList<IBinder>();
try {
@@ -118,7 +129,7 @@
} catch (RemoteException ex) {
// If the system process isn't there we're doomed anyway.
}
-
+
createAndAddWindows();
disable(switches[0]);
@@ -152,7 +163,7 @@
if (DEBUG) {
Slog.d(TAG, String.format(
- "init: icons=%d disabled=0x%08x lights=0x%08x menu=0x%08x imeButton=0x%08x",
+ "init: icons=%d disabled=0x%08x lights=0x%08x menu=0x%08x imeButton=0x%08x",
iconList.size(),
switches[0],
switches[1],
@@ -161,7 +172,7 @@
));
}
}
-
+
protected View updateNotificationVetoButton(View row, StatusBarNotification n) {
View vetoButton = row.findViewById(R.id.veto);
if (n.isClearable()) {
@@ -183,7 +194,7 @@
}
return vetoButton;
}
-
+
protected void applyLegacyRowBackground(StatusBarNotification sbn, View content) {
if (sbn.notification.contentView.getLayoutId() !=
@@ -323,4 +334,178 @@
return false;
}
}
+
+ protected void workAroundBadLayerDrawableOpacity(View v) {
+ }
+
+ protected boolean inflateViews(NotificationData.Entry entry, ViewGroup parent) {
+ int minHeight =
+ mContext.getResources().getDimensionPixelSize(R.dimen.notification_min_height);
+ int maxHeight =
+ mContext.getResources().getDimensionPixelSize(R.dimen.notification_max_height);
+ StatusBarNotification sbn = entry.notification;
+ RemoteViews oneU = sbn.notification.contentView;
+ RemoteViews large = sbn.notification.bigContentView;
+ if (oneU == null) {
+ return false;
+ }
+
+ // create the row view
+ LayoutInflater inflater = (LayoutInflater)mContext.getSystemService(
+ Context.LAYOUT_INFLATER_SERVICE);
+ View row = inflater.inflate(R.layout.status_bar_notification_row, parent, false);
+ // XXX: temporary: while testing big notifications, auto-expand all of them
+ ViewGroup.LayoutParams lp = row.getLayoutParams();
+ if (sbn.notification.bigContentView != null) {
+ lp.height = ViewGroup.LayoutParams.WRAP_CONTENT;
+ } else {
+ lp.height = minHeight;
+ }
+ row.setLayoutParams(lp);
+ workAroundBadLayerDrawableOpacity(row);
+ View vetoButton = updateNotificationVetoButton(row, sbn);
+ vetoButton.setContentDescription(mContext.getString(
+ R.string.accessibility_remove_notification));
+
+ // NB: the large icon is now handled entirely by the template
+
+ // bind the click event to the content area
+ ViewGroup content = (ViewGroup)row.findViewById(R.id.content);
+ ViewGroup adaptive = (ViewGroup)row.findViewById(R.id.adaptive);
+ // XXX: update to allow controls within notification views
+ content.setDescendantFocusability(ViewGroup.FOCUS_BLOCK_DESCENDANTS);
+// content.setOnFocusChangeListener(mFocusChangeListener);
+ PendingIntent contentIntent = sbn.notification.contentIntent;
+ if (contentIntent != null) {
+ final View.OnClickListener listener = new NotificationClicker(contentIntent,
+ sbn.pkg, sbn.tag, sbn.id);
+ content.setOnClickListener(listener);
+ } else {
+ content.setOnClickListener(null);
+ }
+
+ View expandedOneU = null;
+ View expandedLarge = null;
+ Exception exception = null;
+ try {
+ expandedOneU = oneU.apply(mContext, adaptive);
+ if (large != null) {
+ expandedLarge = large.apply(mContext, adaptive);
+ }
+ }
+ catch (RuntimeException e) {
+ exception = e;
+ }
+ if (expandedOneU == null && expandedLarge == null) {
+ final String ident = sbn.pkg + "/0x" + Integer.toHexString(sbn.id);
+ Slog.e(TAG, "couldn't inflate view for notification " + ident, exception);
+ return false;
+ } else {
+ if (expandedOneU != null) {
+ SizeAdaptiveLayout.LayoutParams params =
+ new SizeAdaptiveLayout.LayoutParams(expandedOneU.getLayoutParams());
+ params.minHeight = minHeight;
+ params.maxHeight = minHeight;
+ adaptive.addView(expandedOneU, params);
+ }
+ if (expandedLarge != null) {
+ SizeAdaptiveLayout.LayoutParams params =
+ new SizeAdaptiveLayout.LayoutParams(expandedLarge.getLayoutParams());
+ params.minHeight = minHeight+1;
+ params.maxHeight = SizeAdaptiveLayout.LayoutParams.UNBOUNDED;
+ adaptive.addView(expandedLarge, params);
+ }
+ row.setDrawingCacheEnabled(true);
+ }
+
+ applyLegacyRowBackground(sbn, content);
+
+ entry.row = row;
+ entry.content = content;
+ entry.expanded = expandedOneU;
+ entry.expandedLarge = expandedOneU;
+
+ return true;
+ }
+
+ public NotificationClicker makeClicker(PendingIntent intent, String pkg, String tag, int id) {
+ return new NotificationClicker(intent, pkg, tag, id);
+ }
+
+ private class NotificationClicker implements View.OnClickListener {
+ private PendingIntent mIntent;
+ private String mPkg;
+ private String mTag;
+ private int mId;
+
+ NotificationClicker(PendingIntent intent, String pkg, String tag, int id) {
+ mIntent = intent;
+ mPkg = pkg;
+ mTag = tag;
+ mId = id;
+ }
+
+ public void onClick(View v) {
+ try {
+ // The intent we are sending is for the application, which
+ // won't have permission to immediately start an activity after
+ // the user switches to home. We know it is safe to do at this
+ // point, so make sure new activity switches are now allowed.
+ ActivityManagerNative.getDefault().resumeAppSwitches();
+ // Also, notifications can be launched from the lock screen,
+ // so dismiss the lock screen when the activity starts.
+ ActivityManagerNative.getDefault().dismissKeyguardOnNextActivity();
+ } catch (RemoteException e) {
+ }
+
+ if (mIntent != null) {
+ int[] pos = new int[2];
+ v.getLocationOnScreen(pos);
+ Intent overlay = new Intent();
+ overlay.setSourceBounds(
+ new Rect(pos[0], pos[1], pos[0]+v.getWidth(), pos[1]+v.getHeight()));
+ try {
+ mIntent.send(mContext, 0, overlay);
+ } catch (PendingIntent.CanceledException e) {
+ // the stack trace isn't very helpful here. Just log the exception message.
+ Slog.w(TAG, "Sending contentIntent failed: " + e);
+ }
+
+ KeyguardManager kgm =
+ (KeyguardManager) mContext.getSystemService(Context.KEYGUARD_SERVICE);
+ if (kgm != null) kgm.exitKeyguardSecurely(null);
+ }
+
+ try {
+ mBarService.onNotificationClick(mPkg, mTag, mId);
+ } catch (RemoteException ex) {
+ // system process is dead if we're here.
+ }
+
+ // close the shade if it was open
+ animateCollapse();
+ visibilityChanged(false);
+
+ // If this click was on the intruder alert, hide that instead
+// mHandler.sendEmptyMessage(MSG_HIDE_INTRUDER);
+ }
+ }
+ /**
+ * The LEDs are turned o)ff when the notification panel is shown, even just a little bit.
+ * This was added last-minute and is inconsistent with the way the rest of the notifications
+ * are handled, because the notification isn't really cancelled. The lights are just
+ * turned off. If any other notifications happen, the lights will turn back on. Steve says
+ * this is what he wants. (see bug 1131461)
+ */
+ protected void visibilityChanged(boolean visible) {
+ if (mPanelSlightlyVisible != visible) {
+ mPanelSlightlyVisible = visible;
+ try {
+ mBarService.onPanelRevealed();
+ } catch (RemoteException ex) {
+ // Won't fail unless the world has ended.
+ }
+ }
+ }
+
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationData.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationData.java
index 6fbcd64..3ff85d9 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationData.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationData.java
@@ -38,6 +38,7 @@
public View content; // takes the click events and sends the PendingIntent
public View expanded; // the inflated RemoteViews
public ImageView largeIcon;
+ public View expandedLarge;
public Entry() {}
public Entry(IBinder key, StatusBarNotification n, StatusBarIconView ic) {
this.key = key;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
index 3f611fc..f45b3ad 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
@@ -28,14 +28,11 @@
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
-import android.content.pm.ApplicationInfo;
-import android.content.pm.PackageManager.NameNotFoundException;
import android.content.res.Configuration;
import android.content.res.Resources;
import android.graphics.PixelFormat;
import android.graphics.Rect;
import android.inputmethodservice.InputMethodService;
-import android.os.Build;
import android.os.IBinder;
import android.os.Message;
import android.os.RemoteException;
@@ -50,11 +47,9 @@
import android.view.Gravity;
import android.view.IWindowManager;
import android.view.KeyEvent;
-import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.VelocityTracker;
import android.view.View;
-import android.view.ViewConfiguration;
import android.view.ViewGroup;
import android.view.ViewGroup.LayoutParams;
import android.view.Window;
@@ -68,26 +63,25 @@
import android.widget.ScrollView;
import android.widget.TextView;
-import java.io.FileDescriptor;
-import java.io.PrintWriter;
-import java.util.ArrayList;
-
import com.android.internal.statusbar.StatusBarIcon;
import com.android.internal.statusbar.StatusBarNotification;
import com.android.systemui.R;
-import com.android.systemui.SwipeHelper;
import com.android.systemui.recent.RecentTasksLoader;
import com.android.systemui.statusbar.BaseStatusBar;
import com.android.systemui.statusbar.NotificationData;
import com.android.systemui.statusbar.SignalClusterView;
import com.android.systemui.statusbar.StatusBarIconView;
import com.android.systemui.statusbar.policy.BatteryController;
-import com.android.systemui.statusbar.policy.IntruderAlertView;
import com.android.systemui.statusbar.policy.DateView;
+import com.android.systemui.statusbar.policy.IntruderAlertView;
import com.android.systemui.statusbar.policy.LocationController;
import com.android.systemui.statusbar.policy.NetworkController;
import com.android.systemui.statusbar.policy.NotificationRowLayout;
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+import java.util.ArrayList;
+
public class PhoneStatusBar extends BaseStatusBar {
static final String TAG = "PhoneStatusBar";
public static final boolean DEBUG = false;
@@ -832,73 +826,6 @@
}
}
- private boolean inflateViews(NotificationData.Entry entry, ViewGroup parent) {
- StatusBarNotification sbn = entry.notification;
- // XXX: temporary: while testing big notifications, auto-expand all of them
- final boolean big = (sbn.notification.bigContentView != null);
- RemoteViews remoteViews = big ? sbn.notification.bigContentView
- : sbn.notification.contentView;
- if (remoteViews == null) {
- return false;
- }
-
- // create the row view
- LayoutInflater inflater = (LayoutInflater)mContext.getSystemService(
- Context.LAYOUT_INFLATER_SERVICE);
- View row = inflater.inflate(R.layout.status_bar_notification_row, parent, false);
- ViewGroup.LayoutParams lp = row.getLayoutParams();
- if (big) {
- lp.height = ViewGroup.LayoutParams.WRAP_CONTENT;
- } else {
- lp.height = mContext.getResources().getDimensionPixelSize(R.dimen.notification_height);
- }
- row.setLayoutParams(lp);
- View vetoButton = updateNotificationVetoButton(row, sbn);
- vetoButton.setContentDescription(mContext.getString(
- R.string.accessibility_remove_notification));
-
- // NB: the large icon is now handled entirely by the template
-
- // bind the click event to the content area
- ViewGroup content = (ViewGroup)row.findViewById(R.id.content);
- // XXX: update to allow controls within notification views
- content.setDescendantFocusability(ViewGroup.FOCUS_BLOCK_DESCENDANTS);
-// content.setOnFocusChangeListener(mFocusChangeListener);
- PendingIntent contentIntent = sbn.notification.contentIntent;
- if (contentIntent != null) {
- final View.OnClickListener listener = new NotificationClicker(contentIntent,
- sbn.pkg, sbn.tag, sbn.id);
- content.setOnClickListener(listener);
- } else {
- content.setOnClickListener(null);
- }
-
- View expanded = null;
- Exception exception = null;
- try {
- expanded = remoteViews.apply(mContext, content);
- }
- catch (RuntimeException e) {
- exception = e;
- }
- if (expanded == null) {
- final String ident = sbn.pkg + "/0x" + Integer.toHexString(sbn.id);
- Slog.e(TAG, "couldn't inflate view for notification " + ident, exception);
- return false;
- } else {
- content.addView(expanded);
- row.setDrawingCacheEnabled(true);
- }
-
- applyLegacyRowBackground(sbn, content);
-
- entry.row = row;
- entry.content = content;
- entry.expanded = expanded;
-
- return true;
- }
-
StatusBarNotification removeNotificationViews(IBinder key) {
NotificationData.Entry entry = mNotificationData.remove(key);
if (entry == null) {
@@ -1520,10 +1447,6 @@
@Override
public void setHardKeyboardStatus(boolean available, boolean enabled) { }
- public NotificationClicker makeClicker(PendingIntent intent, String pkg, String tag, int id) {
- return new NotificationClicker(intent, pkg, tag, id);
- }
-
private class NotificationClicker implements View.OnClickListener {
private PendingIntent mIntent;
private String mPkg;
@@ -1538,12 +1461,6 @@
}
public void onClick(View v) {
- if (DEBUG) {
- Slog.v(TAG, "NotificationClicker: intent=" + mIntent
- + " pkg=" + mPkg
- + " tag=" + mTag
- + " id=" + mId);
- }
try {
// The intent we are sending is for the application, which
// won't have permission to immediately start an activity after
@@ -1976,24 +1893,6 @@
}
}
- /**
- * The LEDs are turned o)ff when the notification panel is shown, even just a little bit.
- * This was added last-minute and is inconsistent with the way the rest of the notifications
- * are handled, because the notification isn't really cancelled. The lights are just
- * turned off. If any other notifications happen, the lights will turn back on. Steve says
- * this is what he wants. (see bug 1131461)
- */
- void visibilityChanged(boolean visible) {
- if (mPanelSlightlyVisible != visible) {
- mPanelSlightlyVisible = visible;
- try {
- mBarService.onPanelRevealed();
- } catch (RemoteException ex) {
- // Won't fail unless the world has ended.
- }
- }
- }
-
void performDisableActions(int net) {
int old = mDisabled;
int diff = net ^ old;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NotificationRowLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NotificationRowLayout.java
index 9fd89ed..5369317 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NotificationRowLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NotificationRowLayout.java
@@ -34,12 +34,17 @@
import android.view.ViewGroup;
import android.widget.LinearLayout;
+import com.android.systemui.ExpandHelper;
+import com.android.systemui.Gefingerpoken;
import com.android.systemui.R;
import com.android.systemui.SwipeHelper;
import java.util.HashMap;
-public class NotificationRowLayout extends LinearLayout implements SwipeHelper.Callback {
+public class NotificationRowLayout
+ extends LinearLayout
+ implements SwipeHelper.Callback, ExpandHelper.Callback
+{
private static final String TAG = "NotificationRowLayout";
private static final boolean DEBUG = false;
private static final boolean SLOW_ANIMATIONS = DEBUG;
@@ -55,6 +60,9 @@
HashMap<View, ValueAnimator> mDisappearingViews = new HashMap<View, ValueAnimator>();
private SwipeHelper mSwipeHelper;
+ private ExpandHelper mExpandHelper;
+
+ private Gefingerpoken mCurrentHelper;
// Flag set during notification removal animation to avoid causing too much work until
// animation is done
@@ -71,6 +79,8 @@
setOrientation(LinearLayout.VERTICAL);
+ setMotionEventSplittingEnabled(false);
+
if (DEBUG) {
setOnHierarchyChangeListener(new ViewGroup.OnHierarchyChangeListener() {
@Override
@@ -89,23 +99,61 @@
float densityScale = getResources().getDisplayMetrics().density;
float pagingTouchSlop = ViewConfiguration.get(mContext).getScaledPagingTouchSlop();
mSwipeHelper = new SwipeHelper(SwipeHelper.X, this, densityScale, pagingTouchSlop);
+ int minHeight = getResources().getDimensionPixelSize(R.dimen.notification_min_height);
+ int maxHeight = getResources().getDimensionPixelSize(R.dimen.notification_max_height);
+ mExpandHelper = new ExpandHelper(mContext, this, minHeight, maxHeight);
}
public void setAnimateBounds(boolean anim) {
mAnimateBounds = anim;
}
+ private void logLayoutTransition() {
+ Log.v(TAG, "layout " +
+ (getLayoutTransition().isChangingLayout() ? "is " : "is not ") +
+ "in transition and animations " +
+ (getLayoutTransition().isRunning() ? "are " : "are not ") +
+ "running.");
+ }
+
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
if (DEBUG) Log.v(TAG, "onInterceptTouchEvent()");
- return mSwipeHelper.onInterceptTouchEvent(ev) ||
- super.onInterceptTouchEvent(ev);
+ if (DEBUG) logLayoutTransition();
+
+ MotionEvent cancellation = MotionEvent.obtain(ev);
+ cancellation.setAction(MotionEvent.ACTION_CANCEL);
+
+ if (mSwipeHelper.onInterceptTouchEvent(ev)) {
+ if (DEBUG) Log.v(TAG, "will swipe");
+ mCurrentHelper = mSwipeHelper;
+ mExpandHelper.onInterceptTouchEvent(cancellation);
+ return true;
+ } else if (mExpandHelper.onInterceptTouchEvent(ev)) {
+ if (DEBUG) Log.v(TAG, "will stretch");
+ mCurrentHelper = mExpandHelper;
+ mSwipeHelper.onInterceptTouchEvent(cancellation);
+ return true;
+ } else {
+ mCurrentHelper = null;
+ if (super.onInterceptTouchEvent(ev)) {
+ if (DEBUG) Log.v(TAG, "intercepting ourselves");
+ mSwipeHelper.onInterceptTouchEvent(cancellation);
+ mExpandHelper.onInterceptTouchEvent(cancellation);
+ return true;
+ }
+ }
+ return false;
}
@Override
public boolean onTouchEvent(MotionEvent ev) {
- return mSwipeHelper.onTouchEvent(ev) ||
- super.onTouchEvent(ev);
+ if (DEBUG) Log.v(TAG, "onTouchEvent()");
+ if (DEBUG) logLayoutTransition();
+ if (mCurrentHelper != null) {
+ return mCurrentHelper.onTouchEvent(ev);
+ }
+ return super.onTouchEvent(ev);
}
public boolean canChildBeDismissed(View v) {
@@ -130,10 +178,12 @@
}
public View getChildAtPosition(MotionEvent ev) {
+ return getChildAtPosition(ev.getX(), ev.getY());
+ }
+ public View getChildAtPosition(float touchX, float touchY) {
// find the view under the pointer, accounting for GONE views
final int count = getChildCount();
int y = 0;
- int touchY = (int) ev.getY();
int childIdx = 0;
View slidingChild;
for (; childIdx < count; childIdx++) {
@@ -188,6 +238,7 @@
@Override
public void onDraw(android.graphics.Canvas c) {
super.onDraw(c);
+ if (DEBUG) logLayoutTransition();
if (DEBUG) {
//Slog.d(TAG, "onDraw: canvas height: " + c.getHeight() + "px; measured height: "
// + getMeasuredHeight() + "px");
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBar.java
index ba51108..8c1509b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBar.java
@@ -16,14 +16,9 @@
package com.android.systemui.statusbar.tablet;
-import java.io.FileDescriptor;
-import java.io.PrintWriter;
-import java.util.ArrayList;
-
import android.animation.LayoutTransition;
import android.animation.ObjectAnimator;
import android.app.ActivityManagerNative;
-import android.app.KeyguardManager;
import android.app.Notification;
import android.app.PendingIntent;
import android.app.StatusBarManager;
@@ -32,17 +27,13 @@
import android.content.Intent;
import android.content.IntentFilter;
import android.content.SharedPreferences;
-import android.content.pm.ApplicationInfo;
-import android.content.pm.PackageManager.NameNotFoundException;
import android.content.res.Configuration;
import android.content.res.Resources;
import android.graphics.PixelFormat;
import android.graphics.Point;
-import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.LayerDrawable;
import android.inputmethodservice.InputMethodService;
-import android.os.Build;
import android.os.IBinder;
import android.os.Message;
import android.os.RemoteException;
@@ -53,7 +44,6 @@
import android.view.Gravity;
import android.view.IWindowManager;
import android.view.KeyEvent;
-import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.SoundEffectConstants;
import android.view.VelocityTracker;
@@ -86,6 +76,10 @@
import com.android.systemui.statusbar.policy.NetworkController;
import com.android.systemui.statusbar.policy.Prefs;
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+import java.util.ArrayList;
+
public class TabletStatusBar extends BaseStatusBar implements
InputMethodsPanel.OnHardKeyboardEnabledChangeListener,
RecentsPanelView.OnRecentsPanelVisibilityChangedListener {
@@ -187,8 +181,6 @@
private CompatModePanel mCompatModePanel;
private int mSystemUiVisibility = 0;
- // used to notify status bar for suppressing notification LED
- private boolean mPanelSlightlyVisible;
private int mNavigationIconHints = 0;
@@ -912,7 +904,7 @@
// update the contentIntent
final PendingIntent contentIntent = notification.notification.contentIntent;
if (contentIntent != null) {
- final View.OnClickListener listener = new NotificationClicker(contentIntent,
+ final View.OnClickListener listener = makeClicker(contentIntent,
notification.pkg, notification.tag, notification.id);
oldEntry.content.setOnClickListener(listener);
} else {
@@ -1105,24 +1097,6 @@
}
}
- /**
- * The LEDs are turned o)ff when the notification panel is shown, even just a little bit.
- * This was added last-minute and is inconsistent with the way the rest of the notifications
- * are handled, because the notification isn't really cancelled. The lights are just
- * turned off. If any other notifications happen, the lights will turn back on. Steve says
- * this is what he wants. (see bug 1131461)
- */
- void visibilityChanged(boolean visible) {
- if (mPanelSlightlyVisible != visible) {
- mPanelSlightlyVisible = visible;
- try {
- mBarService.onPanelRevealed();
- } catch (RemoteException ex) {
- // Won't fail unless the world has ended.
- }
- }
- }
-
@Override // CommandQueue
public void setNavigationIconHints(int hints) {
if (hints == mNavigationIconHints) return;
@@ -1364,70 +1338,6 @@
mHandler.sendEmptyMessage(msg);
}
- public NotificationClicker makeClicker(PendingIntent intent, String pkg, String tag, int id) {
- return new NotificationClicker(intent, pkg, tag, id);
- }
-
- private class NotificationClicker implements View.OnClickListener {
- private PendingIntent mIntent;
- private String mPkg;
- private String mTag;
- private int mId;
-
- NotificationClicker(PendingIntent intent, String pkg, String tag, int id) {
- mIntent = intent;
- mPkg = pkg;
- mTag = tag;
- mId = id;
- }
-
- public void onClick(View v) {
- try {
- // The intent we are sending is for the application, which
- // won't have permission to immediately start an activity after
- // the user switches to home. We know it is safe to do at this
- // point, so make sure new activity switches are now allowed.
- ActivityManagerNative.getDefault().resumeAppSwitches();
- // Also, notifications can be launched from the lock screen,
- // so dismiss the lock screen when the activity starts.
- ActivityManagerNative.getDefault().dismissKeyguardOnNextActivity();
- } catch (RemoteException e) {
- }
-
- if (mIntent != null) {
- int[] pos = new int[2];
- v.getLocationOnScreen(pos);
- Intent overlay = new Intent();
- overlay.setSourceBounds(
- new Rect(pos[0], pos[1], pos[0]+v.getWidth(), pos[1]+v.getHeight()));
- try {
- mIntent.send(mContext, 0, overlay);
-
- } catch (PendingIntent.CanceledException e) {
- // the stack trace isn't very helpful here. Just log the exception message.
- Slog.w(TAG, "Sending contentIntent failed: " + e);
- }
-
- KeyguardManager kgm =
- (KeyguardManager) mContext.getSystemService(Context.KEYGUARD_SERVICE);
- if (kgm != null) kgm.exitKeyguardSecurely(null);
- }
-
- try {
- mBarService.onNotificationClick(mPkg, mTag, mId);
- } catch (RemoteException ex) {
- // system process is dead if we're here.
- }
-
- // close the shade if it was open
- animateCollapse();
- visibilityChanged(false);
-
- // If this click was on the intruder alert, hide that instead
-// mHandler.sendEmptyMessage(MSG_HIDE_INTRUDER);
- }
- }
-
StatusBarNotification removeNotificationViews(IBinder key) {
NotificationData.Entry entry = mNotificationData.remove(key);
if (entry == null) {
@@ -1801,7 +1711,8 @@
mNotificationPanel.setNotificationCount(N);
}
- void workAroundBadLayerDrawableOpacity(View v) {
+ @Override
+ protected void workAroundBadLayerDrawableOpacity(View v) {
Drawable bgd = v.getBackground();
if (!(bgd instanceof LayerDrawable)) return;
@@ -1811,64 +1722,6 @@
v.setBackgroundDrawable(d);
}
- private boolean inflateViews(NotificationData.Entry entry, ViewGroup parent) {
- StatusBarNotification sbn = entry.notification;
- RemoteViews remoteViews = sbn.notification.contentView;
- if (remoteViews == null) {
- return false;
- }
-
- // create the row view
- LayoutInflater inflater = (LayoutInflater)mContext.getSystemService(
- Context.LAYOUT_INFLATER_SERVICE);
- View row = inflater.inflate(R.layout.status_bar_notification_row, parent, false);
- workAroundBadLayerDrawableOpacity(row);
- View vetoButton = updateNotificationVetoButton(row, entry.notification);
- vetoButton.setContentDescription(mContext.getString(
- R.string.accessibility_remove_notification));
-
- // NB: the large icon is now handled entirely by the template
-
- // bind the click event to the content area
- ViewGroup content = (ViewGroup)row.findViewById(R.id.content);
- // XXX: update to allow controls within notification views
- content.setDescendantFocusability(ViewGroup.FOCUS_BLOCK_DESCENDANTS);
-// content.setOnFocusChangeListener(mFocusChangeListener);
- PendingIntent contentIntent = sbn.notification.contentIntent;
- if (contentIntent != null) {
- final View.OnClickListener listener = new NotificationClicker(
- contentIntent, sbn.pkg, sbn.tag, sbn.id);
- content.setOnClickListener(listener);
- } else {
- content.setOnClickListener(null);
- }
-
- View expanded = null;
- Exception exception = null;
- try {
- expanded = remoteViews.apply(mContext, content);
- }
- catch (RuntimeException e) {
- exception = e;
- }
- if (expanded == null) {
- final String ident = sbn.pkg + "/0x" + Integer.toHexString(sbn.id);
- Slog.e(TAG, "couldn't inflate view for notification " + ident, exception);
- return false;
- } else {
- content.addView(expanded);
- row.setDrawingCacheEnabled(true);
- }
-
- applyLegacyRowBackground(sbn, content);
-
- entry.row = row;
- entry.content = content;
- entry.expanded = expanded;
-
- return true;
- }
-
public void clearAll() {
try {
mBarService.onClearAllNotifications();
diff --git a/policy/src/com/android/internal/policy/impl/BiometricSensorUnlock.java b/policy/src/com/android/internal/policy/impl/BiometricSensorUnlock.java
index d445d5c..e2c317d 100644
--- a/policy/src/com/android/internal/policy/impl/BiometricSensorUnlock.java
+++ b/policy/src/com/android/internal/policy/impl/BiometricSensorUnlock.java
@@ -29,6 +29,7 @@
// Show the interface, but don't start the unlock procedure. The interface should disappear
// after the specified timeout. If the timeout is 0, the interface shows until another event,
// such as calling hide(), causes it to disappear.
+ // Called on the UI Thread
public void show(long timeoutMilliseconds);
// Hide the interface, if any, exposing the lockscreen.
@@ -39,6 +40,7 @@
// Start the unlock procedure. Returns ‘false’ if it can’t be started or if the backup should
// be used.
+ // Called on the UI thread.
public boolean start(boolean suppressBiometricUnlock);
// Provide a view to work within.
diff --git a/policy/src/com/android/internal/policy/impl/FaceUnlock.java b/policy/src/com/android/internal/policy/impl/FaceUnlock.java
index 7b0a086..09a1c8b 100644
--- a/policy/src/com/android/internal/policy/impl/FaceUnlock.java
+++ b/policy/src/com/android/internal/policy/impl/FaceUnlock.java
@@ -88,7 +88,9 @@
}
// Shows the FaceLock area for a period of time
+ // Called on the UI thread
public void show(long timeoutMillis) {
+ removeAreaDisplayMessages();
showArea();
if (timeoutMillis > 0)
mHandler.sendEmptyMessageDelayed(MSG_HIDE_AREA_VIEW, timeoutMillis);
@@ -134,6 +136,7 @@
/**
* When screen is turned on and focused, need to bind to FaceLock service if we are using
* FaceLock, but only if we're not dealing with a call
+ * Called on the UI thread
*/
public boolean start(boolean suppressBiometricUnlock) {
final boolean tooManyFaceUnlockTries = mUpdateMonitor.getMaxFaceUnlockAttemptsReached();
@@ -146,12 +149,13 @@
&& !suppressBiometricUnlock
&& !tooManyFaceUnlockTries
&& !backupIsTimedOut) {
- bind();
-
// Show FaceLock area, but only for a little bit so lockpattern will become visible if
// FaceLock fails to start or crashes
+ // This must show before bind to guarantee that Face Unlock has a place to display
show(VIEW_AREA_SERVICE_TIMEOUT);
+ bind();
+
// When switching between portrait and landscape view while FaceLock is running, the
// screen will eventually go dark unless we poke the wakelock when FaceLock is
// restarted
@@ -170,6 +174,8 @@
mAreaView = topView.findViewById(R.id.faceLockAreaView);
if (mAreaView == null) {
Log.e(TAG, "Layout does not have areaView and FaceLock is enabled");
+ } else {
+ show(0);
}
} else {
mAreaView = null; // Set to null if not using FaceLock
@@ -192,6 +198,14 @@
return DevicePolicyManager.PASSWORD_QUALITY_BIOMETRIC_WEAK;
}
+ // Shows the FaceLock area
+ // Called on the UI thread
+ private void showArea() {
+ if (mAreaView != null) {
+ mAreaView.setVisibility(View.VISIBLE);
+ }
+ }
+
// Handles covering or exposing FaceLock area on the client side when FaceLock starts or stops
// This needs to be done in a handler because the call could be coming from a callback from the
// FaceLock service that is in a thread that can't modify the UI
@@ -199,9 +213,7 @@
public boolean handleMessage(Message msg) {
switch (msg.what) {
case MSG_SHOW_AREA_VIEW:
- if (mAreaView != null) {
- mAreaView.setVisibility(View.VISIBLE);
- }
+ showArea();
break;
case MSG_HIDE_AREA_VIEW:
if (mAreaView != null) {
@@ -221,13 +233,6 @@
mHandler.removeMessages(MSG_HIDE_AREA_VIEW);
}
- // Shows the FaceLock area immediately
- private void showArea() {
- // Remove messages to prevent a delayed hide message from undo-ing the show
- removeAreaDisplayMessages();
- mHandler.sendEmptyMessage(MSG_SHOW_AREA_VIEW);
- }
-
// Binds to FaceLock service. This call does not tell it to start, but it causes the service
// to call the onServiceConnected callback, which then starts FaceLock.
private void bind() {
@@ -329,7 +334,11 @@
@Override
public void unlock() {
if (DEBUG) Log.d(TAG, "FaceLock unlock()");
- showArea(); // Keep fallback covered
+
+ // Keep fallback covered
+ removeAreaDisplayMessages();
+ mHandler.sendEmptyMessage(MSG_SHOW_AREA_VIEW);
+
stop();
mKeyguardScreenCallback.keyguardDone(true);
diff --git a/policy/src/com/android/internal/policy/impl/LockPatternKeyguardView.java b/policy/src/com/android/internal/policy/impl/LockPatternKeyguardView.java
index c382646..10c3381 100644
--- a/policy/src/com/android/internal/policy/impl/LockPatternKeyguardView.java
+++ b/policy/src/com/android/internal/policy/impl/LockPatternKeyguardView.java
@@ -613,13 +613,7 @@
((KeyguardScreen) mUnlockScreen).onResume();
}
- if (mBiometricUnlock.installedAndSelected() && !mSupressBiometricUnlock) {
- // Note that show() gets called before the screen turns off to set it up for next time
- // it is turned on. We don't want to set a timeout on the biometric unlock here because
- // it may be gone by the time the screen is turned on again. We set the timeout when
- // the screen turns on instead.
- mBiometricUnlock.show(0);
- } else {
+ if (!mBiometricUnlock.installedAndSelected() || mSupressBiometricUnlock) {
mBiometricUnlock.hide();
}
}
diff --git a/services/input/EventHub.cpp b/services/input/EventHub.cpp
index c0eb1b9..326dc32 100644
--- a/services/input/EventHub.cpp
+++ b/services/input/EventHub.cpp
@@ -443,11 +443,22 @@
AutoMutex _l(mLock);
Device* device = getDeviceLocked(deviceId);
- if (device && device->keyMap.haveKeyLayout()) {
- status_t err = device->keyMap.keyLayoutMap->mapKey(
- scanCode, usageCode, outKeycode, outFlags);
- if (err == NO_ERROR) {
- return NO_ERROR;
+ if (device) {
+ // Check the key character map first.
+ sp<KeyCharacterMap> kcm = device->getKeyCharacterMap();
+ if (kcm != NULL) {
+ if (!kcm->mapKey(scanCode, usageCode, outKeycode)) {
+ *outFlags = 0;
+ return NO_ERROR;
+ }
+ }
+
+ // Check the key layout next.
+ if (device->keyMap.haveKeyLayout()) {
+ if (!device->keyMap.keyLayoutMap->mapKey(
+ scanCode, usageCode, outKeycode, outFlags)) {
+ return NO_ERROR;
+ }
}
}
@@ -531,11 +542,26 @@
AutoMutex _l(mLock);
Device* device = getDeviceLocked(deviceId);
if (device) {
- return device->keyMap.keyCharacterMap;
+ return device->getKeyCharacterMap();
}
return NULL;
}
+bool EventHub::setKeyboardLayoutOverlay(int32_t deviceId,
+ const sp<KeyCharacterMap>& map) {
+ AutoMutex _l(mLock);
+ Device* device = getDeviceLocked(deviceId);
+ if (device) {
+ if (map != device->overlayKeyMap) {
+ device->overlayKeyMap = map;
+ device->combinedKeyMap = KeyCharacterMap::combine(
+ device->keyMap.keyCharacterMap, map);
+ return true;
+ }
+ }
+ return false;
+}
+
void EventHub::vibrate(int32_t deviceId, nsecs_t duration) {
AutoMutex _l(mLock);
Device* device = getDeviceLocked(deviceId);
diff --git a/services/input/EventHub.h b/services/input/EventHub.h
index 51d2bac..afc12ef 100644
--- a/services/input/EventHub.h
+++ b/services/input/EventHub.h
@@ -221,6 +221,7 @@
Vector<VirtualKeyDefinition>& outVirtualKeys) const = 0;
virtual sp<KeyCharacterMap> getKeyCharacterMap(int32_t deviceId) const = 0;
+ virtual bool setKeyboardLayoutOverlay(int32_t deviceId, const sp<KeyCharacterMap>& map) = 0;
/* Control the vibrator. */
virtual void vibrate(int32_t deviceId, nsecs_t duration) = 0;
@@ -283,6 +284,7 @@
Vector<VirtualKeyDefinition>& outVirtualKeys) const;
virtual sp<KeyCharacterMap> getKeyCharacterMap(int32_t deviceId) const;
+ virtual bool setKeyboardLayoutOverlay(int32_t deviceId, const sp<KeyCharacterMap>& map);
virtual void vibrate(int32_t deviceId, nsecs_t duration);
virtual void cancelVibrate(int32_t deviceId);
@@ -321,6 +323,9 @@
VirtualKeyMap* virtualKeyMap;
KeyMap keyMap;
+ sp<KeyCharacterMap> overlayKeyMap;
+ sp<KeyCharacterMap> combinedKeyMap;
+
bool ffEffectPlaying;
int16_t ffEffectId; // initially -1
@@ -330,6 +335,13 @@
void close();
inline bool isVirtual() const { return fd < 0; }
+
+ const sp<KeyCharacterMap>& getKeyCharacterMap() const {
+ if (combinedKeyMap != NULL) {
+ return combinedKeyMap;
+ }
+ return keyMap.keyCharacterMap;
+ }
};
status_t openDeviceLocked(const char *devicePath);
diff --git a/services/input/InputReader.cpp b/services/input/InputReader.cpp
index 8c37fbb..95e56bf 100644
--- a/services/input/InputReader.cpp
+++ b/services/input/InputReader.cpp
@@ -962,6 +962,14 @@
mContext->getEventHub()->getConfiguration(mId, &mConfiguration);
}
+ if (!changes || (changes & InputReaderConfiguration::CHANGE_KEYBOARD_LAYOUTS)) {
+ sp<KeyCharacterMap> keyboardLayout =
+ mContext->getPolicy()->getKeyboardLayoutOverlay(mIdentifier.descriptor);
+ if (mContext->getEventHub()->setKeyboardLayoutOverlay(mId, keyboardLayout)) {
+ bumpGeneration();
+ }
+ }
+
size_t numMappers = mMappers.size();
for (size_t i = 0; i < numMappers; i++) {
InputMapper* mapper = mMappers[i];
diff --git a/services/input/InputReader.h b/services/input/InputReader.h
index ed57596..e5897e7 100644
--- a/services/input/InputReader.h
+++ b/services/input/InputReader.h
@@ -67,6 +67,9 @@
// The visible touches option changed.
CHANGE_SHOW_TOUCHES = 1 << 3,
+ // The keyboard layouts must be reloaded.
+ CHANGE_KEYBOARD_LAYOUTS = 1 << 4,
+
// All devices must be reopened.
CHANGE_MUST_REOPEN = 1 << 31,
};
@@ -222,6 +225,9 @@
* and provides information about all current input devices.
*/
virtual void notifyInputDevicesChanged(const Vector<InputDeviceInfo>& inputDevices) = 0;
+
+ /* Gets the keyboard layout for a particular input device. */
+ virtual sp<KeyCharacterMap> getKeyboardLayoutOverlay(const String8& inputDeviceDescriptor) = 0;
};
diff --git a/services/input/tests/InputReader_test.cpp b/services/input/tests/InputReader_test.cpp
index 94d4189..a4b7585 100644
--- a/services/input/tests/InputReader_test.cpp
+++ b/services/input/tests/InputReader_test.cpp
@@ -170,6 +170,10 @@
virtual void notifyInputDevicesChanged(const Vector<InputDeviceInfo>& inputDevices) {
mInputDevices = inputDevices;
}
+
+ virtual sp<KeyCharacterMap> getKeyboardLayoutOverlay(const String8& inputDeviceDescriptor) {
+ return NULL;
+ }
};
@@ -646,6 +650,10 @@
return NULL;
}
+ virtual bool setKeyboardLayoutOverlay(int32_t deviceId, const sp<KeyCharacterMap>& map) {
+ return false;
+ }
+
virtual void vibrate(int32_t deviceId, nsecs_t duration) {
}
diff --git a/services/java/com/android/server/ConnectivityService.java b/services/java/com/android/server/ConnectivityService.java
index 352decf..722e312b 100644
--- a/services/java/com/android/server/ConnectivityService.java
+++ b/services/java/com/android/server/ConnectivityService.java
@@ -865,14 +865,39 @@
@Override
public NetworkQuotaInfo getActiveNetworkQuotaInfo() {
enforceAccessPermission();
- final NetworkState state = getNetworkStateUnchecked(mActiveDefaultNetwork);
- if (state != null) {
- try {
- return mPolicyManager.getNetworkQuotaInfo(state);
- } catch (RemoteException e) {
+
+ final long token = Binder.clearCallingIdentity();
+ try {
+ final NetworkState state = getNetworkStateUnchecked(mActiveDefaultNetwork);
+ if (state != null) {
+ try {
+ return mPolicyManager.getNetworkQuotaInfo(state);
+ } catch (RemoteException e) {
+ }
}
+ return null;
+ } finally {
+ Binder.restoreCallingIdentity(token);
}
- return null;
+ }
+
+ @Override
+ public boolean isActiveNetworkMetered() {
+ enforceAccessPermission();
+
+ final long token = Binder.clearCallingIdentity();
+ try {
+ final NetworkState state = getNetworkStateUnchecked(mActiveDefaultNetwork);
+ if (state != null) {
+ try {
+ return mPolicyManager.isNetworkMetered(state);
+ } catch (RemoteException e) {
+ }
+ }
+ return false;
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
}
public boolean setRadios(boolean turnOn) {
diff --git a/services/java/com/android/server/InputMethodManagerService.java b/services/java/com/android/server/InputMethodManagerService.java
index ca7241c..a474cec 100644
--- a/services/java/com/android/server/InputMethodManagerService.java
+++ b/services/java/com/android/server/InputMethodManagerService.java
@@ -118,7 +118,7 @@
public class InputMethodManagerService extends IInputMethodManager.Stub
implements ServiceConnection, Handler.Callback {
static final boolean DEBUG = false;
- static final String TAG = "InputManagerService";
+ static final String TAG = "InputMethodManagerService";
static final int MSG_SHOW_IM_PICKER = 1;
static final int MSG_SHOW_IM_SUBTYPE_PICKER = 2;
diff --git a/services/java/com/android/server/NsdService.java b/services/java/com/android/server/NsdService.java
index a3ac8d0..8014e27 100644
--- a/services/java/com/android/server/NsdService.java
+++ b/services/java/com/android/server/NsdService.java
@@ -167,6 +167,18 @@
NsdManager.ERROR);
}
break;
+ case NsdManager.UNREGISTER_SERVICE:
+ if (DBG) Slog.d(TAG, "unregister service");
+ clientInfo = mClients.get(msg.replyTo);
+ int regId = msg.arg1;
+ if (clientInfo.mRegisteredIds.remove(new Integer(regId)) &&
+ unregisterService(regId)) {
+ mReplyChannel.replyToMessage(msg, NsdManager.UNREGISTER_SERVICE_SUCCEEDED);
+ } else {
+ mReplyChannel.replyToMessage(msg, NsdManager.UNREGISTER_SERVICE_FAILED,
+ NsdManager.ERROR);
+ }
+ break;
case NsdManager.UPDATE_SERVICE:
if (DBG) Slog.d(TAG, "Update service");
//TODO: implement
@@ -237,6 +249,8 @@
}
public Messenger getMessenger() {
+ mContext.enforceCallingOrSelfPermission(android.Manifest.permission.INTERNET,
+ "NsdService");
return new Messenger(mAsyncServiceHandler);
}
diff --git a/services/java/com/android/server/PowerManagerService.java b/services/java/com/android/server/PowerManagerService.java
index 2d2a881..9a371c6 100644
--- a/services/java/com/android/server/PowerManagerService.java
+++ b/services/java/com/android/server/PowerManagerService.java
@@ -37,6 +37,7 @@
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
+import android.hardware.SystemSensorManager;
import android.os.BatteryManager;
import android.os.BatteryStats;
import android.os.Binder;
@@ -2946,7 +2947,7 @@
}
void systemReady() {
- mSensorManager = new SensorManager(mHandlerThread.getLooper());
+ mSensorManager = new SystemSensorManager(mHandlerThread.getLooper());
mProximitySensor = mSensorManager.getDefaultSensor(Sensor.TYPE_PROXIMITY);
// don't bother with the light sensor if auto brightness is handled in hardware
if (mUseSoftwareAutoBrightness) {
diff --git a/services/java/com/android/server/RecognitionManagerService.java b/services/java/com/android/server/RecognitionManagerService.java
index 8e55512..85224d8 100644
--- a/services/java/com/android/server/RecognitionManagerService.java
+++ b/services/java/com/android/server/RecognitionManagerService.java
@@ -75,7 +75,10 @@
try {
mContext.getPackageManager().getServiceInfo(comp, 0);
} catch (NameNotFoundException e) {
- setCurRecognizer(null);
+ comp = findAvailRecognizer(null);
+ if (comp != null) {
+ setCurRecognizer(comp);
+ }
}
} else {
comp = findAvailRecognizer(null);
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index 241d04ff..02c4d5a 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -51,6 +51,7 @@
import com.android.internal.widget.LockSettingsService;
import com.android.server.accessibility.AccessibilityManagerService;
import com.android.server.am.ActivityManagerService;
+import com.android.server.input.InputManagerService;
import com.android.server.net.NetworkPolicyManagerService;
import com.android.server.net.NetworkStatsService;
import com.android.server.pm.PackageManagerService;
@@ -115,6 +116,7 @@
LightsService lights = null;
PowerManagerService power = null;
BatteryService battery = null;
+ VibratorService vibrator = null;
AlarmManagerService alarm = null;
NetworkManagementService networkManagement = null;
NetworkStatsService networkStats = null;
@@ -136,6 +138,7 @@
ThrottleService throttle = null;
NetworkTimeUpdateService networkTimeUpdater = null;
CommonTimeManagementService commonTimeMgmtService = null;
+ InputManagerService inputManager = null;
// Critical services...
try {
@@ -203,7 +206,8 @@
ServiceManager.addService("battery", battery);
Slog.i(TAG, "Vibrator Service");
- ServiceManager.addService("vibrator", new VibratorService(context));
+ vibrator = new VibratorService(context);
+ ServiceManager.addService("vibrator", vibrator);
// only initialize the power service after we have started the
// lights service, content providers and the battery service.
@@ -222,7 +226,8 @@
factoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL,
!firstBoot);
ServiceManager.addService(Context.WINDOW_SERVICE, wm);
- ServiceManager.addService(Context.INPUT_SERVICE, wm.getInputManagerService());
+ inputManager = wm.getInputManagerService();
+ ServiceManager.addService(Context.INPUT_SERVICE, inputManager);
ActivityManagerService.self().setWindowManager(wm);
@@ -645,6 +650,12 @@
// It is now time to start up the app processes...
+ try {
+ vibrator.systemReady();
+ } catch (Throwable e) {
+ reportWtf("making Vibrator Service ready", e);
+ }
+
if (devicePolicy != null) {
try {
devicePolicy.systemReady();
@@ -714,6 +725,7 @@
final TextServicesManagerService textServiceManagerServiceF = tsms;
final StatusBarManagerService statusBarF = statusBar;
final DreamManagerService dreamyF = dreamy;
+ final InputManagerService inputManagerF = inputManager;
// We now tell the activity manager it is okay to run third party
// code. It will call back into us once it has gotten to the state
@@ -825,6 +837,11 @@
} catch (Throwable e) {
reportWtf("making DreamManagerService ready", e);
}
+ try {
+ if (inputManagerF != null) inputManagerF.systemReady();
+ } catch (Throwable e) {
+ reportWtf("making InputManagerService ready", e);
+ }
}
});
diff --git a/services/java/com/android/server/VibratorService.java b/services/java/com/android/server/VibratorService.java
index de25747..6282c31 100755
--- a/services/java/com/android/server/VibratorService.java
+++ b/services/java/com/android/server/VibratorService.java
@@ -21,6 +21,8 @@
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.PackageManager;
+import android.database.ContentObserver;
+import android.hardware.input.InputManager;
import android.os.Handler;
import android.os.IVibratorService;
import android.os.PowerManager;
@@ -29,18 +31,41 @@
import android.os.IBinder;
import android.os.Binder;
import android.os.SystemClock;
+import android.os.Vibrator;
import android.os.WorkSource;
+import android.provider.Settings;
+import android.provider.Settings.SettingNotFoundException;
import android.util.Slog;
+import android.view.InputDevice;
+import java.util.ArrayList;
import java.util.LinkedList;
import java.util.ListIterator;
-public class VibratorService extends IVibratorService.Stub {
+public class VibratorService extends IVibratorService.Stub
+ implements InputManager.InputDeviceListener {
private static final String TAG = "VibratorService";
private final LinkedList<Vibration> mVibrations;
private Vibration mCurrentVibration;
private final WorkSource mTmpWorkSource = new WorkSource();
+ private final Handler mH = new Handler();
+
+ private final Context mContext;
+ private final PowerManager.WakeLock mWakeLock;
+ private InputManager mIm;
+
+ volatile VibrateThread mThread;
+
+ // mInputDeviceVibrators lock should be acquired after mVibrations lock, if both are
+ // to be acquired
+ private final ArrayList<Vibrator> mInputDeviceVibrators = new ArrayList<Vibrator>();
+ private boolean mVibrateInputDevicesSetting; // guarded by mInputDeviceVibrators
+ private boolean mInputDeviceListenerRegistered; // guarded by mInputDeviceVibrators
+
+ native static boolean vibratorExists();
+ native static void vibratorOn(long milliseconds);
+ native static void vibratorOff();
private class Vibration implements IBinder.DeathRecipient {
private final IBinder mToken;
@@ -112,10 +137,23 @@
context.registerReceiver(mIntentReceiver, filter);
}
- public boolean hasVibrator() {
- return vibratorExists();
+ public void systemReady() {
+ mIm = (InputManager)mContext.getSystemService(Context.INPUT_SERVICE);
+ mContext.getContentResolver().registerContentObserver(
+ Settings.System.getUriFor(Settings.System.VIBRATE_INPUT_DEVICES), true,
+ new ContentObserver(mH) {
+ @Override
+ public void onChange(boolean selfChange) {
+ updateInputDeviceVibrators();
+ }
+ });
+ updateInputDeviceVibrators();
}
-
+
+ public boolean hasVibrator() {
+ return doVibratorExists();
+ }
+
public void vibrate(long milliseconds, IBinder token) {
if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.VIBRATE)
!= PackageManager.PERMISSION_GRANTED) {
@@ -131,6 +169,7 @@
// longer than milliseconds.
return;
}
+
Vibration vib = new Vibration(token, milliseconds, uid);
synchronized (mVibrations) {
removeVibrationLocked(token);
@@ -240,7 +279,7 @@
}
mThread = null;
}
- vibratorOff();
+ doVibratorOff();
mH.removeCallbacks(mVibrationRunnable);
}
@@ -257,7 +296,7 @@
// Lock held on mVibrations
private void startVibrationLocked(final Vibration vib) {
if (vib.mTimeout != 0) {
- vibratorOn(vib.mTimeout);
+ doVibratorOn(vib.mTimeout);
mH.postDelayed(mVibrationRunnable, vib.mTimeout);
} else {
// mThread better be null here. doCancelVibrate should always be
@@ -295,6 +334,94 @@
}
}
+ private void updateInputDeviceVibrators() {
+ synchronized (mVibrations) {
+ doCancelVibrateLocked();
+
+ synchronized (mInputDeviceVibrators) {
+ mVibrateInputDevicesSetting = false;
+ try {
+ mVibrateInputDevicesSetting = Settings.System.getInt(mContext.getContentResolver(),
+ Settings.System.VIBRATE_INPUT_DEVICES) > 0;
+ } catch (SettingNotFoundException snfe) {
+ }
+
+ if (mVibrateInputDevicesSetting) {
+ if (!mInputDeviceListenerRegistered) {
+ mInputDeviceListenerRegistered = true;
+ mIm.registerInputDeviceListener(this, mH);
+ }
+ } else {
+ if (mInputDeviceListenerRegistered) {
+ mInputDeviceListenerRegistered = false;
+ mIm.unregisterInputDeviceListener(this);
+ }
+ }
+
+ mInputDeviceVibrators.clear();
+ if (mVibrateInputDevicesSetting) {
+ int[] ids = mIm.getInputDeviceIds();
+ for (int i = 0; i < ids.length; i++) {
+ InputDevice device = mIm.getInputDevice(ids[i]);
+ Vibrator vibrator = device.getVibrator();
+ if (vibrator.hasVibrator()) {
+ mInputDeviceVibrators.add(vibrator);
+ }
+ }
+ }
+ }
+
+ startNextVibrationLocked();
+ }
+ }
+
+ @Override
+ public void onInputDeviceAdded(int deviceId) {
+ updateInputDeviceVibrators();
+ }
+
+ @Override
+ public void onInputDeviceChanged(int deviceId) {
+ updateInputDeviceVibrators();
+ }
+
+ @Override
+ public void onInputDeviceRemoved(int deviceId) {
+ updateInputDeviceVibrators();
+ }
+
+ private boolean doVibratorExists() {
+ synchronized (mInputDeviceVibrators) {
+ return !mInputDeviceVibrators.isEmpty() || vibratorExists();
+ }
+ }
+
+ private void doVibratorOn(long millis) {
+ synchronized (mInputDeviceVibrators) {
+ final int vibratorCount = mInputDeviceVibrators.size();
+ if (vibratorCount != 0) {
+ for (int i = 0; i < vibratorCount; i++) {
+ mInputDeviceVibrators.get(i).vibrate(millis);
+ }
+ } else {
+ vibratorOn(millis);
+ }
+ }
+ }
+
+ private void doVibratorOff() {
+ synchronized (mInputDeviceVibrators) {
+ final int vibratorCount = mInputDeviceVibrators.size();
+ if (vibratorCount != 0) {
+ for (int i = 0; i < vibratorCount; i++) {
+ mInputDeviceVibrators.get(i).cancel();
+ }
+ } else {
+ vibratorOff();
+ }
+ }
+ }
+
private class VibrateThread extends Thread {
final Vibration mVibration;
boolean mDone;
@@ -350,7 +477,7 @@
// duration is saved for delay() at top of loop
duration = pattern[index++];
if (duration > 0) {
- VibratorService.this.vibratorOn(duration);
+ VibratorService.this.doVibratorOn(duration);
}
} else {
if (repeat < 0) {
@@ -394,15 +521,4 @@
}
}
};
-
- private Handler mH = new Handler();
-
- private final Context mContext;
- private final PowerManager.WakeLock mWakeLock;
-
- volatile VibrateThread mThread;
-
- native static boolean vibratorExists();
- native static void vibratorOn(long milliseconds);
- native static void vibratorOff();
}
diff --git a/services/java/com/android/server/WifiService.java b/services/java/com/android/server/WifiService.java
index e2a2c83..bb38cd9 100644
--- a/services/java/com/android/server/WifiService.java
+++ b/services/java/com/android/server/WifiService.java
@@ -1202,6 +1202,8 @@
pw.println();
pw.println("WifiWatchdogStateMachine dump");
mWifiWatchdogStateMachine.dump(pw);
+ pw.println("WifiStateMachine dump");
+ mWifiStateMachine.dump(fd, pw, args);
}
private class WifiLock extends DeathRecipient {
diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java
index e37adc7..77bec41 100644
--- a/services/java/com/android/server/am/ActivityManagerService.java
+++ b/services/java/com/android/server/am/ActivityManagerService.java
@@ -1808,16 +1808,18 @@
final ProcessRecord getProcessRecordLocked(
String processName, int uid) {
- // Temporary hack to make Settings run per user
- if (uid == Process.SYSTEM_UID && !processName.equals("com.android.settings")) {
+ if (uid == Process.SYSTEM_UID) {
// The system gets to run in any process. If there are multiple
// processes with the same uid, just pick the first (this
// should never happen).
SparseArray<ProcessRecord> procs = mProcessNames.getMap().get(
processName);
- return procs != null ? procs.valueAt(0) : null;
+ if (procs == null) return null;
+ final int N = procs.size();
+ for (int i = 0; i < N; i++) {
+ if (UserId.isSameUser(procs.keyAt(i), uid)) return procs.valueAt(i);
+ }
}
- // uid = applyUserId(uid);
ProcessRecord proc = mProcessNames.get(processName, uid);
return proc;
}
@@ -6183,7 +6185,9 @@
if (cpi == null) {
return null;
}
-
+ if (isSingleton(cpi.processName, cpi.applicationInfo)) {
+ userId = 0;
+ }
cpi.applicationInfo = getAppInfoForUser(cpi.applicationInfo, userId);
String msg;
@@ -10923,6 +10927,9 @@
return null;
}
if (userId > 0) {
+ if (isSingleton(sInfo.processName, sInfo.applicationInfo)) {
+ userId = 0;
+ }
sInfo.applicationInfo = getAppInfoForUser(sInfo.applicationInfo, userId);
}
ComponentName name = new ComponentName(
@@ -11740,7 +11747,22 @@
}
}
}
-
+
+ boolean isSingleton(String componentProcessName, ApplicationInfo aInfo) {
+ boolean result = false;
+ if (UserId.getAppId(aInfo.uid) >= Process.FIRST_APPLICATION_UID) {
+ result = false;
+ } else if (componentProcessName == aInfo.packageName) {
+ result = (aInfo.flags & ApplicationInfo.FLAG_PERSISTENT) != 0;
+ } else if ("system".equals(componentProcessName)) {
+ result = true;
+ }
+ if (DEBUG_MU) {
+ Slog.v(TAG, "isSingleton(" + componentProcessName + ", " + aInfo + ") = " + result);
+ }
+ return result;
+ }
+
public int bindService(IApplicationThread caller, IBinder token,
Intent service, String resolvedType,
IServiceConnection connection, int flags, int userId) {
@@ -11808,6 +11830,11 @@
if (res.record == null) {
return -1;
}
+ if (isSingleton(res.record.processName, res.record.appInfo)) {
+ userId = 0;
+ res = retrieveServiceLocked(service, resolvedType, Binder.getCallingPid(),
+ Binder.getCallingUid(), 0);
+ }
ServiceRecord s = res.record;
final long origId = Binder.clearCallingIdentity();
@@ -12740,7 +12767,11 @@
if (ai != null) {
receivers = new ArrayList();
ResolveInfo ri = new ResolveInfo();
- ri.activityInfo = getActivityInfoForUser(ai, userId);
+ if (isSingleton(ai.processName, ai.applicationInfo)) {
+ ri.activityInfo = getActivityInfoForUser(ai, 0);
+ } else {
+ ri.activityInfo = getActivityInfoForUser(ai, userId);
+ }
receivers.add(ri);
}
} else {
@@ -14894,16 +14925,14 @@
if (info == null) return null;
ApplicationInfo newInfo = new ApplicationInfo(info);
newInfo.uid = applyUserId(info.uid, userId);
- if (newInfo.uid >= Process.FIRST_APPLICATION_UID) {
- newInfo.dataDir = USER_DATA_DIR + userId + "/"
- + info.packageName;
- }
+ newInfo.dataDir = USER_DATA_DIR + userId + "/"
+ + info.packageName;
return newInfo;
}
ActivityInfo getActivityInfoForUser(ActivityInfo aInfo, int userId) {
- if (aInfo == null || aInfo.applicationInfo.uid < Process.FIRST_APPLICATION_UID
- || userId < 1) {
+ if (aInfo == null
+ || (userId < 1 && aInfo.applicationInfo.uid < UserId.PER_USER_RANGE)) {
return aInfo;
}
diff --git a/services/java/com/android/server/am/ActivityRecord.java b/services/java/com/android/server/am/ActivityRecord.java
index a098f18..cce8e7a 100644
--- a/services/java/com/android/server/am/ActivityRecord.java
+++ b/services/java/com/android/server/am/ActivityRecord.java
@@ -558,6 +558,11 @@
pendingOptions.getCustomEnterResId(),
pendingOptions.getCustomExitResId());
break;
+ case ActivityOptions.ANIM_SCALE_UP:
+ service.mWindowManager.overridePendingAppTransitionScaleUp(
+ pendingOptions.getStartX(), pendingOptions.getStartY(),
+ pendingOptions.getStartWidth(), pendingOptions.getStartHeight());
+ break;
case ActivityOptions.ANIM_THUMBNAIL:
service.mWindowManager.overridePendingAppTransitionThumb(
pendingOptions.getThumbnail(),
diff --git a/services/java/com/android/server/am/ActivityStack.java b/services/java/com/android/server/am/ActivityStack.java
index 6596e1f..9085cea 100644
--- a/services/java/com/android/server/am/ActivityStack.java
+++ b/services/java/com/android/server/am/ActivityStack.java
@@ -2345,8 +2345,9 @@
}
if (err == ActivityManager.START_SUCCESS) {
+ final int userId = aInfo != null ? UserId.getUserId(aInfo.applicationInfo.uid) : 0;
Slog.i(TAG, "START {" + intent.toShortString(true, true, true, false)
- + "} from pid " + (callerApp != null ? callerApp.pid : callingPid));
+ + " u=" + userId + "} from pid " + (callerApp != null ? callerApp.pid : callingPid));
}
ActivityRecord sourceRecord = null;
@@ -2943,6 +2944,9 @@
// Collect information about the target of the Intent.
ActivityInfo aInfo = resolveActivity(intent, resolvedType, startFlags,
profileFile, profileFd, userId);
+ if (aInfo != null && mService.isSingleton(aInfo.processName, aInfo.applicationInfo)) {
+ userId = 0;
+ }
aInfo = mService.getActivityInfoForUser(aInfo, userId);
synchronized (mService) {
diff --git a/services/java/com/android/server/am/BroadcastQueue.java b/services/java/com/android/server/am/BroadcastQueue.java
index 1b83e0b..47b8c0a 100644
--- a/services/java/com/android/server/am/BroadcastQueue.java
+++ b/services/java/com/android/server/am/BroadcastQueue.java
@@ -719,8 +719,10 @@
info.activityInfo.applicationInfo.packageName,
info.activityInfo.name);
if (r.callingUid != Process.SYSTEM_UID) {
- info.activityInfo = mService.getActivityInfoForUser(info.activityInfo, UserId
- .getUserId(r.callingUid));
+ boolean isSingleton = mService.isSingleton(info.activityInfo.processName,
+ info.activityInfo.applicationInfo);
+ int targetUserId = isSingleton ? 0 : UserId.getUserId(r.callingUid);
+ info.activityInfo = mService.getActivityInfoForUser(info.activityInfo,targetUserId);
}
r.curReceiver = info.activityInfo;
if (DEBUG_MU && r.callingUid > UserId.PER_USER_RANGE) {
diff --git a/services/java/com/android/server/input/InputManagerService.java b/services/java/com/android/server/input/InputManagerService.java
index e819432..a4ed31c 100644
--- a/services/java/com/android/server/input/InputManagerService.java
+++ b/services/java/com/android/server/input/InputManagerService.java
@@ -16,20 +16,28 @@
package com.android.server.input;
+import com.android.internal.os.AtomicFile;
+import com.android.internal.util.FastXmlSerializer;
import com.android.internal.util.XmlUtils;
import com.android.server.Watchdog;
import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+import org.xmlpull.v1.XmlSerializer;
+import android.Manifest;
+import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
+import android.content.IntentFilter;
import android.content.pm.ActivityInfo;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.content.pm.PackageManager.NameNotFoundException;
import android.content.res.Configuration;
import android.content.res.Resources;
+import android.content.res.Resources.NotFoundException;
import android.content.res.TypedArray;
import android.content.res.XmlResourceParser;
import android.database.ContentObserver;
@@ -55,30 +63,37 @@
import android.view.InputChannel;
import android.view.InputDevice;
import android.view.InputEvent;
-import android.view.KeyCharacterMap;
import android.view.KeyEvent;
import android.view.PointerIcon;
import android.view.Surface;
import android.view.ViewConfiguration;
import android.view.WindowManagerPolicy;
-import android.view.KeyCharacterMap.UnavailableException;
+import java.io.BufferedInputStream;
+import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileDescriptor;
import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.HashMap;
-import java.util.List;
+import java.util.Map;
+
+import libcore.io.IoUtils;
+import libcore.io.Streams;
+import libcore.util.Objects;
/*
* Wraps the C++ InputManager and provides its callbacks.
*/
public class InputManagerService extends IInputManager.Stub implements Watchdog.Monitor {
static final String TAG = "InputManager";
- static final boolean DEBUG = false;
+ static final boolean DEBUG = true;
private static final String EXCLUDED_DEVICES_PATH = "etc/excluded-input-devices.xml";
@@ -90,10 +105,10 @@
private final Context mContext;
private final Callbacks mCallbacks;
private final InputManagerHandler mHandler;
+ private boolean mSystemReady;
- // Used to simulate a persistent data store for keyboard layouts.
- // TODO: Replace with the real thing.
- private final HashMap<String, String> mFakeRegistry = new HashMap<String, String>();
+ // Persistent data store. Must be locked each time during use.
+ private final PersistentDataStore mDataStore = new PersistentDataStore();
// List of currently registered input devices changed listeners by process id.
private Object mInputDevicesLock = new Object();
@@ -151,6 +166,7 @@
private static native void nativeVibrate(int ptr, int deviceId, long[] pattern,
int repeat, int token);
private static native void nativeCancelVibrate(int ptr, int deviceId, int token);
+ private static native void nativeReloadKeyboardLayouts(int ptr);
private static native String nativeDump(int ptr);
private static native void nativeMonitor(int ptr);
@@ -200,7 +216,33 @@
updatePointerSpeedFromSettings();
updateShowTouchesFromSettings();
}
-
+
+ public void systemReady() {
+ if (DEBUG) {
+ Slog.d(TAG, "System ready.");
+ }
+ mSystemReady = true;
+ reloadKeyboardLayouts();
+
+ IntentFilter filter = new IntentFilter(Intent.ACTION_PACKAGE_ADDED);
+ filter.addAction(Intent.ACTION_PACKAGE_REMOVED);
+ filter.addAction(Intent.ACTION_PACKAGE_CHANGED);
+ filter.addDataScheme("package");
+ mContext.registerReceiver(new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ if (DEBUG) {
+ Slog.d(TAG, "Packages changed, reloading keyboard layouts.");
+ }
+ reloadKeyboardLayouts();
+ }
+ }, filter, null, mHandler);
+ }
+
+ private void reloadKeyboardLayouts() {
+ nativeReloadKeyboardLayouts(mPtr);
+ }
+
public void setDisplaySize(int displayId, int width, int height,
int externalWidth, int externalHeight) {
if (width <= 0 || height <= 0 || externalWidth <= 0 || externalHeight <= 0) {
@@ -516,14 +558,14 @@
@Override // Binder call
public KeyboardLayout[] getKeyboardLayouts() {
- ArrayList<KeyboardLayout> list = new ArrayList<KeyboardLayout>();
-
- final PackageManager pm = mContext.getPackageManager();
- Intent intent = new Intent(InputManager.ACTION_QUERY_KEYBOARD_LAYOUTS);
- for (ResolveInfo resolveInfo : pm.queryBroadcastReceivers(intent,
- PackageManager.GET_META_DATA)) {
- loadKeyboardLayouts(pm, resolveInfo.activityInfo, list, null);
- }
+ final ArrayList<KeyboardLayout> list = new ArrayList<KeyboardLayout>();
+ visitAllKeyboardLayouts(new KeyboardLayoutVisitor() {
+ @Override
+ public void visitKeyboardLayout(Resources resources,
+ String descriptor, String label, int kcmResId) {
+ list.add(new KeyboardLayout(descriptor, label));
+ }
+ });
return list.toArray(new KeyboardLayout[list.size()]);
}
@@ -533,37 +575,57 @@
throw new IllegalArgumentException("keyboardLayoutDescriptor must not be null");
}
- KeyboardLayoutDescriptor d = KeyboardLayoutDescriptor.parse(keyboardLayoutDescriptor);
- if (d == null) {
- return null;
+ final KeyboardLayout[] result = new KeyboardLayout[1];
+ visitKeyboardLayout(keyboardLayoutDescriptor, new KeyboardLayoutVisitor() {
+ @Override
+ public void visitKeyboardLayout(Resources resources,
+ String descriptor, String label, int kcmResId) {
+ result[0] = new KeyboardLayout(descriptor, label);
+ }
+ });
+ if (result[0] == null) {
+ Log.w(TAG, "Could not get keyboard layout with descriptor '"
+ + keyboardLayoutDescriptor + "'.");
}
+ return result[0];
+ }
+ private void visitAllKeyboardLayouts(KeyboardLayoutVisitor visitor) {
final PackageManager pm = mContext.getPackageManager();
- try {
- ActivityInfo receiver = pm.getReceiverInfo(
- new ComponentName(d.packageName, d.receiverName),
- PackageManager.GET_META_DATA);
- return loadKeyboardLayouts(pm, receiver, null, d.keyboardLayoutName);
- } catch (NameNotFoundException ex) {
- Log.w(TAG, "Could not load keyboard layout '" + d.keyboardLayoutName
- + "' from receiver " + d.packageName + "/" + d.receiverName, ex);
- return null;
+ Intent intent = new Intent(InputManager.ACTION_QUERY_KEYBOARD_LAYOUTS);
+ for (ResolveInfo resolveInfo : pm.queryBroadcastReceivers(intent,
+ PackageManager.GET_META_DATA)) {
+ visitKeyboardLayoutsInPackage(pm, resolveInfo.activityInfo, null, visitor);
}
}
- private KeyboardLayout loadKeyboardLayouts(
- PackageManager pm, ActivityInfo receiver,
- List<KeyboardLayout> list, String keyboardName) {
+ private void visitKeyboardLayout(String keyboardLayoutDescriptor,
+ KeyboardLayoutVisitor visitor) {
+ KeyboardLayoutDescriptor d = KeyboardLayoutDescriptor.parse(keyboardLayoutDescriptor);
+ if (d != null) {
+ final PackageManager pm = mContext.getPackageManager();
+ try {
+ ActivityInfo receiver = pm.getReceiverInfo(
+ new ComponentName(d.packageName, d.receiverName),
+ PackageManager.GET_META_DATA);
+ visitKeyboardLayoutsInPackage(pm, receiver, d.keyboardLayoutName, visitor);
+ } catch (NameNotFoundException ex) {
+ }
+ }
+ }
+
+ private void visitKeyboardLayoutsInPackage(PackageManager pm, ActivityInfo receiver,
+ String keyboardName, KeyboardLayoutVisitor visitor) {
Bundle metaData = receiver.metaData;
if (metaData == null) {
- return null;
+ return;
}
int configResId = metaData.getInt(InputManager.META_DATA_KEYBOARD_LAYOUTS);
if (configResId == 0) {
Log.w(TAG, "Missing meta-data '" + InputManager.META_DATA_KEYBOARD_LAYOUTS
+ "' on receiver " + receiver.packageName + "/" + receiver.name);
- return null;
+ return;
}
try {
@@ -596,12 +658,9 @@
} else {
String descriptor = KeyboardLayoutDescriptor.format(
receiver.packageName, receiver.name, name);
- KeyboardLayout c = new KeyboardLayout(descriptor, label);
- if (keyboardName != null && name.equals(keyboardName)) {
- return c;
- }
- if (list != null) {
- list.add(c);
+ if (keyboardName == null || name.equals(keyboardName)) {
+ visitor.visitKeyboardLayout(resources, descriptor,
+ label, kcmResId);
}
}
} finally {
@@ -617,16 +676,9 @@
parser.close();
}
} catch (Exception ex) {
- Log.w(TAG, "Could not load keyboard layout resource from receiver "
+ Log.w(TAG, "Could not parse keyboard layout resource from receiver "
+ receiver.packageName + "/" + receiver.name, ex);
- return null;
}
- if (keyboardName != null) {
- Log.w(TAG, "Could not load keyboard layout '" + keyboardName
- + "' from receiver " + receiver.packageName + "/" + receiver.name
- + " because it was not declared in the keyboard layout resource.");
- }
- return null;
}
@Override // Binder call
@@ -635,7 +687,9 @@
throw new IllegalArgumentException("inputDeviceDescriptor must not be null");
}
- return mFakeRegistry.get(inputDeviceDescriptor);
+ synchronized (mDataStore) {
+ return mDataStore.getKeyboardLayout(inputDeviceDescriptor);
+ }
}
@Override // Binder call
@@ -650,45 +704,23 @@
throw new IllegalArgumentException("inputDeviceDescriptor must not be null");
}
- mFakeRegistry.put(inputDeviceDescriptor, keyboardLayoutDescriptor);
- }
-
- /**
- * Loads the key character map associated with the keyboard layout.
- *
- * @param pm The package manager.
- * @return The key character map, or null if it could not be loaded for any reason.
- *
- public KeyCharacterMap loadKeyCharacterMap(PackageManager pm) {
- if (pm == null) {
- throw new IllegalArgumentException("pm must not be null");
- }
-
- if (mKeyCharacterMap == null) {
- KeyboardLayoutDescriptor d = InputManager.parseKeyboardLayoutDescriptor(mDescriptor);
- if (d == null) {
- Log.e(InputManager.TAG, "Could not load key character map '" + mDescriptor
- + "' because the descriptor could not be parsed.");
- return null;
- }
-
- CharSequence cs = pm.getText(d.packageName, mKeyCharacterMapResId, null);
- if (cs == null) {
- Log.e(InputManager.TAG, "Could not load key character map '" + mDescriptor
- + "' because its associated resource could not be loaded.");
- return null;
- }
-
+ final boolean changed;
+ synchronized (mDataStore) {
try {
- mKeyCharacterMap = KeyCharacterMap.load(cs);
- } catch (UnavailableException ex) {
- Log.e(InputManager.TAG, "Could not load key character map '" + mDescriptor
- + "' due to an error while parsing.", ex);
- return null;
+ changed = mDataStore.setKeyboardLayout(
+ inputDeviceDescriptor, keyboardLayoutDescriptor);
+ } finally {
+ mDataStore.saveIfNeeded();
}
}
- return mKeyCharacterMap;
- }*/
+
+ if (changed) {
+ if (DEBUG) {
+ Slog.d(TAG, "Keyboard layout changed, reloading keyboard layouts.");
+ }
+ reloadKeyboardLayouts();
+ }
+ }
public void setInputWindows(InputWindowHandle[] windowHandles) {
nativeSetInputWindows(mPtr, windowHandles);
@@ -862,7 +894,7 @@
@Override
public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
- if (mContext.checkCallingOrSelfPermission("android.permission.DUMP")
+ if (mContext.checkCallingOrSelfPermission(Manifest.permission.DUMP)
!= PackageManager.PERMISSION_GRANTED) {
pw.println("Permission Denial: can't dump InputManager from from pid="
+ Binder.getCallingPid()
@@ -1056,6 +1088,40 @@
return PointerIcon.getDefaultIcon(mContext);
}
+ // Native callback.
+ private String[] getKeyboardLayoutOverlay(String inputDeviceDescriptor) {
+ if (!mSystemReady) {
+ return null;
+ }
+
+ String keyboardLayoutDescriptor = getKeyboardLayoutForInputDevice(inputDeviceDescriptor);
+ if (keyboardLayoutDescriptor == null) {
+ return null;
+ }
+
+ final String[] result = new String[2];
+ visitKeyboardLayout(keyboardLayoutDescriptor, new KeyboardLayoutVisitor() {
+ @Override
+ public void visitKeyboardLayout(Resources resources,
+ String descriptor, String label, int kcmResId) {
+ try {
+ result[0] = descriptor;
+ result[1] = Streams.readFully(new InputStreamReader(
+ resources.openRawResource(kcmResId)));
+ } catch (IOException ex) {
+ } catch (NotFoundException ex) {
+ }
+ }
+ });
+ if (result[0] == null) {
+ Log.w(TAG, "Could not get keyboard layout with descriptor '"
+ + keyboardLayoutDescriptor + "'.");
+ return null;
+ }
+ return result;
+ }
+
+
/**
* Callback interface implemented by the Window Manager.
*/
@@ -1149,6 +1215,11 @@
}
}
+ private interface KeyboardLayoutVisitor {
+ void visitKeyboardLayout(Resources resources,
+ String descriptor, String label, int kcmResId);
+ }
+
private final class InputDevicesChangedListenerRecord implements DeathRecipient {
private final int mPid;
private final IInputDevicesChangedListener mListener;
@@ -1198,4 +1269,186 @@
onVibratorTokenDied(this);
}
}
+
+ /**
+ * Manages persistent state recorded by the input manager service as an XML file.
+ * Caller must acquire lock on the data store before accessing it.
+ *
+ * File format:
+ * <code>
+ * <input-mananger-state>
+ * <input-devices>
+ * <input-device descriptor="xxxxx" keyboard-layout="yyyyy" />
+ * >input-devices>
+ * >/input-manager-state>
+ * </code>
+ */
+ private static final class PersistentDataStore {
+ // Input device state by descriptor.
+ private final HashMap<String, InputDeviceState> mInputDevices =
+ new HashMap<String, InputDeviceState>();
+ private final AtomicFile mAtomicFile;
+
+ // True if the data has been loaded.
+ private boolean mLoaded;
+
+ // True if there are changes to be saved.
+ private boolean mDirty;
+
+ public PersistentDataStore() {
+ mAtomicFile = new AtomicFile(new File("/data/system/input-manager-state.xml"));
+ }
+
+ public void saveIfNeeded() {
+ if (mDirty) {
+ save();
+ mDirty = false;
+ }
+ }
+
+ public String getKeyboardLayout(String inputDeviceDescriptor) {
+ InputDeviceState state = getInputDeviceState(inputDeviceDescriptor, false);
+ return state != null ? state.keyboardLayoutDescriptor : null;
+ }
+
+ public boolean setKeyboardLayout(String inputDeviceDescriptor,
+ String keyboardLayoutDescriptor) {
+ InputDeviceState state = getInputDeviceState(inputDeviceDescriptor, true);
+ if (!Objects.equal(state.keyboardLayoutDescriptor, keyboardLayoutDescriptor)) {
+ state.keyboardLayoutDescriptor = keyboardLayoutDescriptor;
+ setDirty();
+ return true;
+ }
+ return false;
+ }
+
+ private InputDeviceState getInputDeviceState(String inputDeviceDescriptor,
+ boolean createIfAbsent) {
+ loadIfNeeded();
+ InputDeviceState state = mInputDevices.get(inputDeviceDescriptor);
+ if (state == null && createIfAbsent) {
+ state = new InputDeviceState();
+ mInputDevices.put(inputDeviceDescriptor, state);
+ setDirty();
+ }
+ return state;
+ }
+
+ private void loadIfNeeded() {
+ if (!mLoaded) {
+ load();
+ mLoaded = true;
+ }
+ }
+
+ private void setDirty() {
+ mDirty = true;
+ }
+
+ private void clearState() {
+ mInputDevices.clear();
+ }
+
+ private void load() {
+ clearState();
+
+ final InputStream is;
+ try {
+ is = mAtomicFile.openRead();
+ } catch (FileNotFoundException ex) {
+ return;
+ }
+
+ XmlPullParser parser;
+ try {
+ parser = Xml.newPullParser();
+ parser.setInput(new BufferedInputStream(is), null);
+ loadFromXml(parser);
+ } catch (IOException ex) {
+ Slog.w(TAG, "Failed to load input manager persistent store data.", ex);
+ clearState();
+ } catch (XmlPullParserException ex) {
+ Slog.w(TAG, "Failed to load input manager persistent store data.", ex);
+ clearState();
+ } finally {
+ IoUtils.closeQuietly(is);
+ }
+ }
+
+ private void save() {
+ final FileOutputStream os;
+ try {
+ os = mAtomicFile.startWrite();
+ boolean success = false;
+ try {
+ XmlSerializer serializer = new FastXmlSerializer();
+ serializer.setOutput(new BufferedOutputStream(os), "utf-8");
+ saveToXml(serializer);
+ serializer.flush();
+ success = true;
+ } finally {
+ if (success) {
+ mAtomicFile.finishWrite(os);
+ } else {
+ mAtomicFile.failWrite(os);
+ }
+ }
+ } catch (IOException ex) {
+ Slog.w(TAG, "Failed to save input manager persistent store data.", ex);
+ }
+ }
+
+ private void loadFromXml(XmlPullParser parser)
+ throws IOException, XmlPullParserException {
+ XmlUtils.beginDocument(parser, "input-manager-state");
+ final int outerDepth = parser.getDepth();
+ while (XmlUtils.nextElementWithin(parser, outerDepth)) {
+ if (parser.getName().equals("input-devices")) {
+ loadInputDevicesFromXml(parser);
+ }
+ }
+ }
+
+ private void loadInputDevicesFromXml(XmlPullParser parser)
+ throws IOException, XmlPullParserException {
+ final int outerDepth = parser.getDepth();
+ while (XmlUtils.nextElementWithin(parser, outerDepth)) {
+ if (parser.getName().equals("input-device")) {
+ String descriptor = parser.getAttributeValue(null, "descriptor");
+ if (descriptor == null) {
+ throw new XmlPullParserException(
+ "Missing descriptor attribute on input-device");
+ }
+ InputDeviceState state = new InputDeviceState();
+ state.keyboardLayoutDescriptor =
+ parser.getAttributeValue(null, "keyboard-layout");
+ mInputDevices.put(descriptor, state);
+ }
+ }
+ }
+
+ private void saveToXml(XmlSerializer serializer) throws IOException {
+ serializer.startDocument(null, true);
+ serializer.setFeature("http://xmlpull.org/v1/doc/features.html#indent-output", true);
+ serializer.startTag(null, "input-manager-state");
+ serializer.startTag(null, "input-devices");
+ for (Map.Entry<String, InputDeviceState> entry : mInputDevices.entrySet()) {
+ final String descriptor = entry.getKey();
+ final InputDeviceState state = entry.getValue();
+ serializer.startTag(null, "input-device");
+ serializer.attribute(null, "descriptor", descriptor);
+ if (state.keyboardLayoutDescriptor != null) {
+ serializer.attribute(null, "keyboard-layout", state.keyboardLayoutDescriptor);
+ }
+ serializer.endTag(null, "input-device");
+ }
+ serializer.endTag(null, "input-devices");
+ serializer.endTag(null, "input-manager-state");
+ serializer.endDocument();
+ }
+ }
+
+ private static final class InputDeviceState {
+ public String keyboardLayoutDescriptor;
+ }
}
diff --git a/services/java/com/android/server/net/NetworkPolicyManagerService.java b/services/java/com/android/server/net/NetworkPolicyManagerService.java
index fa62e497..1e17067 100644
--- a/services/java/com/android/server/net/NetworkPolicyManagerService.java
+++ b/services/java/com/android/server/net/NetworkPolicyManagerService.java
@@ -50,6 +50,7 @@
import static android.net.TrafficStats.MB_IN_BYTES;
import static android.telephony.TelephonyManager.SIM_STATE_READY;
import static android.text.format.DateUtils.DAY_IN_MILLIS;
+import static com.android.internal.util.ArrayUtils.appendInt;
import static com.android.internal.util.Preconditions.checkNotNull;
import static com.android.server.NetworkManagementService.LIMIT_GLOBAL_ALERT;
import static com.android.server.net.NetworkPolicyManagerService.XmlUtils.readBooleanAttribute;
@@ -1216,6 +1217,23 @@
}
@Override
+ public int[] getAppsWithPolicy(int policy) {
+ mContext.enforceCallingOrSelfPermission(MANAGE_NETWORK_POLICY, TAG);
+
+ int[] appIds = new int[0];
+ synchronized (mRulesLock) {
+ for (int i = 0; i < mAppPolicy.size(); i++) {
+ final int appId = mAppPolicy.keyAt(i);
+ final int appPolicy = mAppPolicy.valueAt(i);
+ if (appPolicy == policy) {
+ appIds = appendInt(appIds, appId);
+ }
+ }
+ }
+ return appIds;
+ }
+
+ @Override
public void registerListener(INetworkPolicyListener listener) {
// TODO: create permission for observing network policy
mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
@@ -1373,6 +1391,22 @@
}
@Override
+ public boolean isNetworkMetered(NetworkState state) {
+ final NetworkIdentity ident = NetworkIdentity.buildNetworkIdentity(mContext, state);
+
+ final NetworkPolicy policy;
+ synchronized (mRulesLock) {
+ policy = findPolicyForNetworkLocked(ident);
+ }
+
+ if (policy != null) {
+ return policy.metered;
+ } else {
+ return false;
+ }
+ }
+
+ @Override
protected void dump(FileDescriptor fd, PrintWriter writer, String[] args) {
mContext.enforceCallingOrSelfPermission(DUMP, TAG);
@@ -1796,11 +1830,6 @@
mHandler.getLooper().getQueue().addIdleHandler(handler);
}
- public static boolean isAirplaneModeOn(Context context) {
- return Settings.System.getInt(
- context.getContentResolver(), Settings.System.AIRPLANE_MODE_ON, 0) != 0;
- }
-
private static void collectKeys(SparseIntArray source, SparseBooleanArray target) {
final int size = source.size();
for (int i = 0; i < size; i++) {
diff --git a/services/java/com/android/server/net/NetworkStatsService.java b/services/java/com/android/server/net/NetworkStatsService.java
index 4382a03..2a67e02 100644
--- a/services/java/com/android/server/net/NetworkStatsService.java
+++ b/services/java/com/android/server/net/NetworkStatsService.java
@@ -26,6 +26,7 @@
import static android.content.Intent.EXTRA_UID;
import static android.net.ConnectivityManager.ACTION_TETHER_STATE_CHANGED;
import static android.net.ConnectivityManager.CONNECTIVITY_ACTION_IMMEDIATE;
+import static android.net.ConnectivityManager.isNetworkTypeMobile;
import static android.net.NetworkIdentity.COMBINE_SUBTYPE_ENABLED;
import static android.net.NetworkStats.IFACE_ALL;
import static android.net.NetworkStats.SET_ALL;
@@ -33,7 +34,7 @@
import static android.net.NetworkStats.SET_FOREGROUND;
import static android.net.NetworkStats.TAG_NONE;
import static android.net.NetworkStats.UID_ALL;
-import static android.net.NetworkTemplate.buildTemplateMobileAll;
+import static android.net.NetworkTemplate.buildTemplateMobileWildcard;
import static android.net.NetworkTemplate.buildTemplateWifiWildcard;
import static android.net.TrafficStats.MB_IN_BYTES;
import static android.provider.Settings.Secure.NETSTATS_DEV_BUCKET_DURATION;
@@ -54,6 +55,8 @@
import static android.text.format.DateUtils.HOUR_IN_MILLIS;
import static android.text.format.DateUtils.MINUTE_IN_MILLIS;
import static android.text.format.DateUtils.SECOND_IN_MILLIS;
+import static com.android.internal.util.ArrayUtils.appendElement;
+import static com.android.internal.util.ArrayUtils.contains;
import static com.android.internal.util.Preconditions.checkNotNull;
import static com.android.server.NetworkManagementService.LIMIT_GLOBAL_ALERT;
import static com.android.server.NetworkManagementSocketTagger.resetKernelUidStats;
@@ -194,6 +197,8 @@
private HashMap<String, NetworkIdentitySet> mActiveIfaces = Maps.newHashMap();
/** Current default active iface. */
private String mActiveIface;
+ /** Set of any ifaces associated with mobile networks since boot. */
+ private String[] mMobileIfaces = new String[0];
private final DropBoxNonMonotonicObserver mNonMonotonicObserver =
new DropBoxNonMonotonicObserver();
@@ -517,6 +522,11 @@
}
@Override
+ public String[] getMobileIfaces() {
+ return mMobileIfaces;
+ }
+
+ @Override
public void incrementOperationCount(int uid, int tag, int operationCount) {
if (Binder.getCallingUid() != uid) {
mContext.enforceCallingOrSelfPermission(MODIFY_NETWORK_ACCOUNTING, TAG);
@@ -735,6 +745,13 @@
}
ident.add(NetworkIdentity.buildNetworkIdentity(mContext, state));
+
+ // remember any ifaces associated with mobile networks
+ if (isNetworkTypeMobile(state.networkInfo.getType())) {
+ if (!contains(mMobileIfaces, iface)) {
+ mMobileIfaces = appendElement(String.class, mMobileIfaces, iface);
+ }
+ }
}
}
}
@@ -861,7 +878,7 @@
NetworkStats.Entry uidTotal;
// collect mobile sample
- template = buildTemplateMobileAll(getActiveSubscriberId(mContext));
+ template = buildTemplateMobileWildcard();
devTotal = mDevRecorder.getTotalSinceBootLocked(template);
xtTotal = new NetworkStats.Entry();
uidTotal = mUidRecorder.getTotalSinceBootLocked(template);
@@ -1022,12 +1039,6 @@
}
};
- private static String getActiveSubscriberId(Context context) {
- final TelephonyManager telephony = (TelephonyManager) context.getSystemService(
- Context.TELEPHONY_SERVICE);
- return telephony.getSubscriberId();
- }
-
private boolean isBandwidthControlEnabled() {
try {
return mNetworkManager.isBandwidthControlEnabled();
diff --git a/services/java/com/android/server/pm/PackageManagerService.java b/services/java/com/android/server/pm/PackageManagerService.java
index 1d02b7a3..b97d7fd 100644
--- a/services/java/com/android/server/pm/PackageManagerService.java
+++ b/services/java/com/android/server/pm/PackageManagerService.java
@@ -16,12 +16,14 @@
package com.android.server.pm;
+import static android.Manifest.permission.GRANT_REVOKE_PERMISSIONS;
+import static android.Manifest.permission.READ_EXTERNAL_STORAGE;
import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DEFAULT;
import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DISABLED;
import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DISABLED_USER;
import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_ENABLED;
-import static android.Manifest.permission.READ_EXTERNAL_STORAGE;
-import static android.Manifest.permission.GRANT_REVOKE_PERMISSIONS;
+import static com.android.internal.util.ArrayUtils.appendInt;
+import static com.android.internal.util.ArrayUtils.removeInt;
import static libcore.io.OsConstants.S_ISLNK;
import com.android.internal.app.IMediaContainerService;
@@ -139,6 +141,7 @@
import java.util.zip.ZipOutputStream;
import libcore.io.ErrnoException;
+import libcore.io.IoUtils;
import libcore.io.Libcore;
/**
@@ -1451,22 +1454,6 @@
}
}
- static int[] appendInt(int[] cur, int val) {
- if (cur == null) {
- return new int[] { val };
- }
- final int N = cur.length;
- for (int i=0; i<N; i++) {
- if (cur[i] == val) {
- return cur;
- }
- }
- int[] ret = new int[N+1];
- System.arraycopy(cur, 0, ret, 0, N);
- ret[N] = val;
- return ret;
- }
-
static int[] appendInts(int[] cur, int[] add) {
if (add == null) return cur;
if (cur == null) return add;
@@ -1477,26 +1464,6 @@
return cur;
}
- static int[] removeInt(int[] cur, int val) {
- if (cur == null) {
- return null;
- }
- final int N = cur.length;
- for (int i=0; i<N; i++) {
- if (cur[i] == val) {
- int[] ret = new int[N-1];
- if (i > 0) {
- System.arraycopy(cur, 0, ret, 0, i);
- }
- if (i < (N-1)) {
- System.arraycopy(cur, i + 1, ret, i, N - i - 1);
- }
- return ret;
- }
- }
- return cur;
- }
-
static int[] removeInts(int[] cur, int[] rem) {
if (rem == null) return cur;
if (cur == null) return cur;
@@ -6614,6 +6581,7 @@
oldPackage = mPackages.get(pkgName);
if (compareSignatures(oldPackage.mSignatures, pkg.mSignatures)
!= PackageManager.SIGNATURE_MATCH) {
+ Slog.w(TAG, "New package has a different signature: " + pkgName);
res.returnCode = PackageManager.INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES;
return;
}
@@ -6979,9 +6947,8 @@
} catch (IOException e) {
Slog.e(TAG, "Couldn't create a new zip file for the public parts of a" +
" forward-locked app.");
+ destResourceFile.delete();
return PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE;
- } finally {
- //TODO clean up the extracted public files
}
retCode = mInstaller.setForwardLockPerm(getApkName(newPackage.mPath),
newPackage.applicationInfo.uid);
@@ -7023,38 +6990,34 @@
File publicZipFile) throws IOException {
final FileOutputStream fstr = new FileOutputStream(publicZipFile);
final ZipOutputStream publicZipOutStream = new ZipOutputStream(fstr);
- final ZipFile privateZip = new ZipFile(newPackage.mPath);
+ try {
+ final ZipFile privateZip = new ZipFile(newPackage.mPath);
+ try {
+ // Copy manifest, resources.arsc and res directory to public zip
- // Copy manifest, resources.arsc and res directory to public zip
-
- final Enumeration<? extends ZipEntry> privateZipEntries = privateZip.entries();
- while (privateZipEntries.hasMoreElements()) {
- final ZipEntry zipEntry = privateZipEntries.nextElement();
- final String zipEntryName = zipEntry.getName();
- if ("AndroidManifest.xml".equals(zipEntryName)
- || "resources.arsc".equals(zipEntryName)
- || zipEntryName.startsWith("res/")) {
- try {
- copyZipEntry(zipEntry, privateZip, publicZipOutStream);
- } catch (IOException e) {
- try {
- publicZipOutStream.close();
- throw e;
- } finally {
- publicZipFile.delete();
+ final Enumeration<? extends ZipEntry> privateZipEntries = privateZip.entries();
+ while (privateZipEntries.hasMoreElements()) {
+ final ZipEntry zipEntry = privateZipEntries.nextElement();
+ final String zipEntryName = zipEntry.getName();
+ if ("AndroidManifest.xml".equals(zipEntryName)
+ || "resources.arsc".equals(zipEntryName)
+ || zipEntryName.startsWith("res/")) {
+ copyZipEntry(zipEntry, privateZip, publicZipOutStream);
}
}
+ } finally {
+ try { privateZip.close(); } catch (IOException e) { }
}
- }
- publicZipOutStream.finish();
- publicZipOutStream.flush();
- FileUtils.sync(fstr);
- publicZipOutStream.close();
- FileUtils.setPermissions(
- publicZipFile.getAbsolutePath(),
- FileUtils.S_IRUSR|FileUtils.S_IWUSR|FileUtils.S_IRGRP|FileUtils.S_IROTH,
- -1, -1);
+ publicZipOutStream.finish();
+ publicZipOutStream.flush();
+ FileUtils.sync(fstr);
+ publicZipOutStream.close();
+ FileUtils.setPermissions(publicZipFile.getAbsolutePath(), FileUtils.S_IRUSR
+ | FileUtils.S_IWUSR | FileUtils.S_IRGRP | FileUtils.S_IROTH, -1, -1);
+ } finally {
+ IoUtils.closeQuietly(publicZipOutStream);
+ }
}
private static void copyZipEntry(ZipEntry zipEntry,
@@ -7073,11 +7036,15 @@
}
outZipStream.putNextEntry(newEntry);
- InputStream data = inZipFile.getInputStream(zipEntry);
- while ((num = data.read(buffer)) > 0) {
- outZipStream.write(buffer, 0, num);
+ final InputStream data = inZipFile.getInputStream(zipEntry);
+ try {
+ while ((num = data.read(buffer)) > 0) {
+ outZipStream.write(buffer, 0, num);
+ }
+ outZipStream.flush();
+ } finally {
+ IoUtils.closeQuietly(data);
}
- outZipStream.flush();
}
private void deleteTempPackageFiles() {
diff --git a/services/java/com/android/server/wm/ScreenRotationAnimation.java b/services/java/com/android/server/wm/ScreenRotationAnimation.java
index 3dcfd3c..13013a8 100644
--- a/services/java/com/android/server/wm/ScreenRotationAnimation.java
+++ b/services/java/com/android/server/wm/ScreenRotationAnimation.java
@@ -18,6 +18,8 @@
import java.io.PrintWriter;
+import static com.android.server.wm.WindowStateAnimator.SurfaceTrace;
+
import android.content.Context;
import android.graphics.Matrix;
import android.graphics.PixelFormat;
@@ -119,6 +121,7 @@
private boolean mMoreStartEnter;
private boolean mMoreStartExit;
private boolean mMoreStartFrame;
+ long mHalfwayPoint;
public void printTo(String prefix, PrintWriter pw) {
pw.print(prefix); pw.print("mSurface="); pw.print(mSurface);
@@ -205,17 +208,23 @@
">>> OPEN TRANSACTION ScreenRotationAnimation");
Surface.openTransaction();
}
-
+
try {
try {
- mSurface = new Surface(session, 0, "FreezeSurface",
- -1, mWidth, mHeight, PixelFormat.OPAQUE, Surface.FX_SURFACE_SCREENSHOT | Surface.HIDDEN);
+ if (WindowManagerService.DEBUG_SURFACE_TRACE) {
+ mSurface = new SurfaceTrace(session, 0, "FreezeSurface", -1, mWidth, mHeight,
+ PixelFormat.OPAQUE, Surface.FX_SURFACE_SCREENSHOT | Surface.HIDDEN);
+ } else {
+ mSurface = new Surface(session, 0, "FreezeSurface", -1, mWidth, mHeight,
+ PixelFormat.OPAQUE, Surface.FX_SURFACE_SCREENSHOT | Surface.HIDDEN);
+ }
if (!mSurface.isValid()) {
// Screenshot failed, punt.
mSurface = null;
return;
}
mSurface.setLayer(FREEZE_LAYER + 1);
+ mSurface.setAlpha(0);
mSurface.show();
} catch (Surface.OutOfResourcesException e) {
Slog.w(TAG, "Unable to allocate freeze surface", e);
@@ -308,10 +317,10 @@
if (TWO_PHASE_ANIMATION) {
return startAnimation(session, maxAnimationDuration, animationScale,
finalWidth, finalHeight, false);
- } else {
- // Don't start animation yet.
- return false;
}
+
+ // Don't start animation yet.
+ return false;
}
/**
@@ -590,29 +599,37 @@
mEnteringBlackFrame.kill();
mEnteringBlackFrame = null;
}
- if (mStartExitAnimation != null) {
- mStartExitAnimation.cancel();
- mStartExitAnimation = null;
+ if (TWO_PHASE_ANIMATION) {
+ if (mStartExitAnimation != null) {
+ mStartExitAnimation.cancel();
+ mStartExitAnimation = null;
+ }
+ if (mStartEnterAnimation != null) {
+ mStartEnterAnimation.cancel();
+ mStartEnterAnimation = null;
+ }
+ if (mFinishExitAnimation != null) {
+ mFinishExitAnimation.cancel();
+ mFinishExitAnimation = null;
+ }
+ if (mFinishEnterAnimation != null) {
+ mFinishEnterAnimation.cancel();
+ mFinishEnterAnimation = null;
+ }
}
- if (mStartEnterAnimation != null) {
- mStartEnterAnimation.cancel();
- mStartEnterAnimation = null;
- }
- if (mStartFrameAnimation != null) {
- mStartFrameAnimation.cancel();
- mStartFrameAnimation = null;
- }
- if (mFinishExitAnimation != null) {
- mFinishExitAnimation.cancel();
- mFinishExitAnimation = null;
- }
- if (mFinishEnterAnimation != null) {
- mFinishEnterAnimation.cancel();
- mFinishEnterAnimation = null;
- }
- if (mFinishFrameAnimation != null) {
- mFinishFrameAnimation.cancel();
- mFinishFrameAnimation = null;
+ if (USE_CUSTOM_BLACK_FRAME) {
+ if (mStartFrameAnimation != null) {
+ mStartFrameAnimation.cancel();
+ mStartFrameAnimation = null;
+ }
+ if (mRotateFrameAnimation != null) {
+ mRotateFrameAnimation.cancel();
+ mRotateFrameAnimation = null;
+ }
+ if (mFinishFrameAnimation != null) {
+ mFinishFrameAnimation.cancel();
+ mFinishFrameAnimation = null;
+ }
}
if (mRotateExitAnimation != null) {
mRotateExitAnimation.cancel();
@@ -622,72 +639,74 @@
mRotateEnterAnimation.cancel();
mRotateEnterAnimation = null;
}
- if (mRotateFrameAnimation != null) {
- mRotateFrameAnimation.cancel();
- mRotateFrameAnimation = null;
- }
}
public boolean isAnimating() {
- if (TWO_PHASE_ANIMATION) {
- return hasAnimations() || mFinishAnimReady;
- } else {
- return hasAnimations();
- }
+ return hasAnimations() || (TWO_PHASE_ANIMATION && mFinishAnimReady);
}
private boolean hasAnimations() {
- return mStartEnterAnimation != null || mStartExitAnimation != null
- || mStartFrameAnimation != null
- || mFinishEnterAnimation != null || mFinishExitAnimation != null
- || mFinishFrameAnimation != null
- || mRotateEnterAnimation != null || mRotateExitAnimation != null
- || mRotateFrameAnimation != null;
+ return (TWO_PHASE_ANIMATION &&
+ (mStartEnterAnimation != null || mStartExitAnimation != null
+ || mFinishEnterAnimation != null || mFinishExitAnimation != null))
+ || (USE_CUSTOM_BLACK_FRAME &&
+ (mStartFrameAnimation != null || mRotateFrameAnimation != null
+ || mFinishFrameAnimation != null))
+ || mRotateEnterAnimation != null || mRotateExitAnimation != null;
}
private boolean stepAnimation(long now) {
+ if (now > mHalfwayPoint) {
+ mHalfwayPoint = Long.MAX_VALUE;
+ }
if (mFinishAnimReady && mFinishAnimStartTime < 0) {
if (DEBUG_STATE) Slog.v(TAG, "Step: finish anim now ready");
mFinishAnimStartTime = now;
}
- mMoreStartExit = false;
- if (mStartExitAnimation != null) {
- mMoreStartExit = mStartExitAnimation.getTransformation(now, mStartExitTransformation);
- if (DEBUG_TRANSFORMS) Slog.v(TAG, "Stepped start exit: " + mStartExitTransformation);
- }
+ if (TWO_PHASE_ANIMATION) {
+ mMoreStartExit = false;
+ if (mStartExitAnimation != null) {
+ mMoreStartExit = mStartExitAnimation.getTransformation(now, mStartExitTransformation);
+ if (DEBUG_TRANSFORMS) Slog.v(TAG, "Stepped start exit: " + mStartExitTransformation);
+ }
- mMoreStartEnter = false;
- if (mStartEnterAnimation != null) {
- mMoreStartEnter = mStartEnterAnimation.getTransformation(now, mStartEnterTransformation);
- if (DEBUG_TRANSFORMS) Slog.v(TAG, "Stepped start enter: " + mStartEnterTransformation);
+ mMoreStartEnter = false;
+ if (mStartEnterAnimation != null) {
+ mMoreStartEnter = mStartEnterAnimation.getTransformation(now, mStartEnterTransformation);
+ if (DEBUG_TRANSFORMS) Slog.v(TAG, "Stepped start enter: " + mStartEnterTransformation);
+ }
}
-
- mMoreStartFrame = false;
- if (mStartFrameAnimation != null) {
- mMoreStartFrame = mStartFrameAnimation.getTransformation(now, mStartFrameTransformation);
- if (DEBUG_TRANSFORMS) Slog.v(TAG, "Stepped start frame: " + mStartFrameTransformation);
+ if (USE_CUSTOM_BLACK_FRAME) {
+ mMoreStartFrame = false;
+ if (mStartFrameAnimation != null) {
+ mMoreStartFrame = mStartFrameAnimation.getTransformation(now, mStartFrameTransformation);
+ if (DEBUG_TRANSFORMS) Slog.v(TAG, "Stepped start frame: " + mStartFrameTransformation);
+ }
}
long finishNow = mFinishAnimReady ? (now - mFinishAnimStartTime) : 0;
if (DEBUG_STATE) Slog.v(TAG, "Step: finishNow=" + finishNow);
- mMoreFinishExit = false;
- if (mFinishExitAnimation != null) {
- mMoreFinishExit = mFinishExitAnimation.getTransformation(finishNow, mFinishExitTransformation);
- if (DEBUG_TRANSFORMS) Slog.v(TAG, "Stepped finish exit: " + mFinishExitTransformation);
- }
+ if (TWO_PHASE_ANIMATION) {
+ mMoreFinishExit = false;
+ if (mFinishExitAnimation != null) {
+ mMoreFinishExit = mFinishExitAnimation.getTransformation(finishNow, mFinishExitTransformation);
+ if (DEBUG_TRANSFORMS) Slog.v(TAG, "Stepped finish exit: " + mFinishExitTransformation);
+ }
- mMoreFinishEnter = false;
- if (mFinishEnterAnimation != null) {
- mMoreFinishEnter = mFinishEnterAnimation.getTransformation(finishNow, mFinishEnterTransformation);
- if (DEBUG_TRANSFORMS) Slog.v(TAG, "Stepped finish enter: " + mFinishEnterTransformation);
+ mMoreFinishEnter = false;
+ if (mFinishEnterAnimation != null) {
+ mMoreFinishEnter = mFinishEnterAnimation.getTransformation(finishNow, mFinishEnterTransformation);
+ if (DEBUG_TRANSFORMS) Slog.v(TAG, "Stepped finish enter: " + mFinishEnterTransformation);
+ }
}
-
- mMoreFinishFrame = false;
- if (mFinishFrameAnimation != null) {
- mMoreFinishFrame = mFinishFrameAnimation.getTransformation(finishNow, mFinishFrameTransformation);
- if (DEBUG_TRANSFORMS) Slog.v(TAG, "Stepped finish frame: " + mFinishFrameTransformation);
+ if (USE_CUSTOM_BLACK_FRAME) {
+ mMoreFinishFrame = false;
+ if (mFinishFrameAnimation != null) {
+ mMoreFinishFrame = mFinishFrameAnimation.getTransformation(finishNow, mFinishFrameTransformation);
+ if (DEBUG_TRANSFORMS) Slog.v(TAG, "Stepped finish frame: " + mFinishFrameTransformation);
+ }
}
mMoreRotateExit = false;
@@ -702,24 +721,28 @@
if (DEBUG_TRANSFORMS) Slog.v(TAG, "Stepped rotate enter: " + mRotateEnterTransformation);
}
- mMoreRotateFrame = false;
- if (mRotateFrameAnimation != null) {
- mMoreRotateFrame = mRotateFrameAnimation.getTransformation(now, mRotateFrameTransformation);
- if (DEBUG_TRANSFORMS) Slog.v(TAG, "Stepped rotate frame: " + mRotateFrameTransformation);
+ if (USE_CUSTOM_BLACK_FRAME) {
+ mMoreRotateFrame = false;
+ if (mRotateFrameAnimation != null) {
+ mMoreRotateFrame = mRotateFrameAnimation.getTransformation(now, mRotateFrameTransformation);
+ if (DEBUG_TRANSFORMS) Slog.v(TAG, "Stepped rotate frame: " + mRotateFrameTransformation);
+ }
}
- if (!mMoreStartExit && !mMoreRotateExit && !mMoreFinishExit) {
- if (mStartExitAnimation != null) {
- if (DEBUG_STATE) Slog.v(TAG, "Exit animations done, clearing start exit anim!");
- mStartExitAnimation.cancel();
- mStartExitAnimation = null;
- mStartExitTransformation.clear();
- }
- if (mFinishExitAnimation != null) {
- if (DEBUG_STATE) Slog.v(TAG, "Exit animations done, clearing finish exit anim!");
- mFinishExitAnimation.cancel();
- mFinishExitAnimation = null;
- mFinishExitTransformation.clear();
+ if (!mMoreRotateExit && (!TWO_PHASE_ANIMATION || (!mMoreStartExit && !mMoreFinishExit))) {
+ if (TWO_PHASE_ANIMATION) {
+ if (mStartExitAnimation != null) {
+ if (DEBUG_STATE) Slog.v(TAG, "Exit animations done, clearing start exit anim!");
+ mStartExitAnimation.cancel();
+ mStartExitAnimation = null;
+ mStartExitTransformation.clear();
+ }
+ if (mFinishExitAnimation != null) {
+ if (DEBUG_STATE) Slog.v(TAG, "Exit animations done, clearing finish exit anim!");
+ mFinishExitAnimation.cancel();
+ mFinishExitAnimation = null;
+ mFinishExitTransformation.clear();
+ }
}
if (mRotateExitAnimation != null) {
if (DEBUG_STATE) Slog.v(TAG, "Exit animations done, clearing rotate exit anim!");
@@ -729,18 +752,20 @@
}
}
- if (!mMoreStartEnter && !mMoreRotateEnter && !mMoreFinishEnter) {
- if (mStartEnterAnimation != null) {
- if (DEBUG_STATE) Slog.v(TAG, "Enter animations done, clearing start enter anim!");
- mStartEnterAnimation.cancel();
- mStartEnterAnimation = null;
- mStartEnterTransformation.clear();
- }
- if (mFinishEnterAnimation != null) {
- if (DEBUG_STATE) Slog.v(TAG, "Enter animations done, clearing finish enter anim!");
- mFinishEnterAnimation.cancel();
- mFinishEnterAnimation = null;
- mFinishEnterTransformation.clear();
+ if (!mMoreRotateEnter && (!TWO_PHASE_ANIMATION || (!mMoreStartEnter && !mMoreFinishEnter))) {
+ if (TWO_PHASE_ANIMATION) {
+ if (mStartEnterAnimation != null) {
+ if (DEBUG_STATE) Slog.v(TAG, "Enter animations done, clearing start enter anim!");
+ mStartEnterAnimation.cancel();
+ mStartEnterAnimation = null;
+ mStartEnterTransformation.clear();
+ }
+ if (mFinishEnterAnimation != null) {
+ if (DEBUG_STATE) Slog.v(TAG, "Enter animations done, clearing finish enter anim!");
+ mFinishEnterAnimation.cancel();
+ mFinishEnterAnimation = null;
+ mFinishEnterTransformation.clear();
+ }
}
if (mRotateEnterAnimation != null) {
if (DEBUG_STATE) Slog.v(TAG, "Enter animations done, clearing rotate enter anim!");
@@ -772,12 +797,14 @@
}
mExitTransformation.set(mRotateExitTransformation);
- mExitTransformation.compose(mStartExitTransformation);
- mExitTransformation.compose(mFinishExitTransformation);
-
mEnterTransformation.set(mRotateEnterTransformation);
- mEnterTransformation.compose(mStartEnterTransformation);
- mEnterTransformation.compose(mFinishEnterTransformation);
+ if (TWO_PHASE_ANIMATION) {
+ mExitTransformation.compose(mStartExitTransformation);
+ mExitTransformation.compose(mFinishExitTransformation);
+
+ mEnterTransformation.compose(mStartEnterTransformation);
+ mEnterTransformation.compose(mFinishEnterTransformation);
+ }
if (DEBUG_TRANSFORMS) Slog.v(TAG, "Final exit: " + mExitTransformation);
if (DEBUG_TRANSFORMS) Slog.v(TAG, "Final enter: " + mEnterTransformation);
@@ -793,9 +820,11 @@
if (DEBUG_TRANSFORMS) Slog.v(TAG, "Final frame: " + mFrameTransformation);
}
- final boolean more = mMoreStartEnter || mMoreStartExit || mMoreStartFrame
- || mMoreFinishEnter || mMoreFinishExit || mMoreFinishFrame
- || mMoreRotateEnter || mMoreRotateExit || mMoreRotateFrame
+ final boolean more = (TWO_PHASE_ANIMATION
+ && (mMoreStartEnter || mMoreStartExit || mMoreFinishEnter || mMoreFinishExit))
+ || (USE_CUSTOM_BLACK_FRAME
+ && (mMoreStartFrame || mMoreRotateFrame || mMoreFinishFrame))
+ || mMoreRotateEnter || mMoreRotateExit
|| !mFinishAnimReady;
mSnapshotFinalMatrix.setConcat(mExitTransformation.getMatrix(), mSnapshotInitialMatrix);
@@ -848,7 +877,7 @@
setSnapshotTransform(mSnapshotFinalMatrix, mExitTransformation.getAlpha());
}
-
+
public boolean stepAnimationLocked(long now) {
if (!hasAnimations()) {
if (DEBUG_STATE) Slog.v(TAG, "Step: no animations running");
@@ -858,23 +887,30 @@
if (!mAnimRunning) {
if (DEBUG_STATE) Slog.v(TAG, "Step: starting start, finish, rotate");
- if (mStartEnterAnimation != null) {
- mStartEnterAnimation.setStartTime(now);
+ if (TWO_PHASE_ANIMATION) {
+ if (mStartEnterAnimation != null) {
+ mStartEnterAnimation.setStartTime(now);
+ }
+ if (mStartExitAnimation != null) {
+ mStartExitAnimation.setStartTime(now);
+ }
+ if (mFinishEnterAnimation != null) {
+ mFinishEnterAnimation.setStartTime(0);
+ }
+ if (mFinishExitAnimation != null) {
+ mFinishExitAnimation.setStartTime(0);
+ }
}
- if (mStartExitAnimation != null) {
- mStartExitAnimation.setStartTime(now);
- }
- if (mStartFrameAnimation != null) {
- mStartFrameAnimation.setStartTime(now);
- }
- if (mFinishEnterAnimation != null) {
- mFinishEnterAnimation.setStartTime(0);
- }
- if (mFinishExitAnimation != null) {
- mFinishExitAnimation.setStartTime(0);
- }
- if (mFinishFrameAnimation != null) {
- mFinishFrameAnimation.setStartTime(0);
+ if (USE_CUSTOM_BLACK_FRAME) {
+ if (mStartFrameAnimation != null) {
+ mStartFrameAnimation.setStartTime(now);
+ }
+ if (mFinishFrameAnimation != null) {
+ mFinishFrameAnimation.setStartTime(0);
+ }
+ if (mRotateFrameAnimation != null) {
+ mRotateFrameAnimation.setStartTime(now);
+ }
}
if (mRotateEnterAnimation != null) {
mRotateEnterAnimation.setStartTime(now);
@@ -882,10 +918,8 @@
if (mRotateExitAnimation != null) {
mRotateExitAnimation.setStartTime(now);
}
- if (mRotateFrameAnimation != null) {
- mRotateFrameAnimation.setStartTime(now);
- }
mAnimRunning = true;
+ mHalfwayPoint = now + mRotateEnterAnimation.getDuration() / 2;
}
return stepAnimation(now);
diff --git a/services/java/com/android/server/wm/WindowAnimator.java b/services/java/com/android/server/wm/WindowAnimator.java
index 00fd7d8..7611a0f 100644
--- a/services/java/com/android/server/wm/WindowAnimator.java
+++ b/services/java/com/android/server/wm/WindowAnimator.java
@@ -431,6 +431,10 @@
mPendingLayoutChanges = 0;
mCurrentTime = SystemClock.uptimeMillis();
mBulkUpdateParams = 0;
+ mAnimating = false;
+ if (WindowManagerService.DEBUG_WINDOW_TRACE) {
+ Slog.i(TAG, "!!! animate: entry time=" + mCurrentTime);
+ }
// Update animations of all applications, including those
// associated with exiting/removed apps
@@ -478,7 +482,16 @@
Surface.closeTransaction();
}
- mService.bulkSetParameters(mBulkUpdateParams);
+ mService.bulkSetParameters(mBulkUpdateParams, mPendingLayoutChanges);
+
+ if (mAnimating) {
+ mService.scheduleAnimationLocked();
+ }
+ if (WindowManagerService.DEBUG_WINDOW_TRACE) {
+ Slog.i(TAG, "!!! animate: exit mAnimating=" + mAnimating
+ + " mBulkUpdateParams=" + Integer.toHexString(mBulkUpdateParams)
+ + " mPendingLayoutChanges=" + Integer.toHexString(mPendingLayoutChanges));
+ }
}
WindowState mCurrentFocus;
diff --git a/services/java/com/android/server/wm/WindowManagerService.java b/services/java/com/android/server/wm/WindowManagerService.java
index 82018fe..966f4c1 100644
--- a/services/java/com/android/server/wm/WindowManagerService.java
+++ b/services/java/com/android/server/wm/WindowManagerService.java
@@ -50,6 +50,7 @@
import android.Manifest;
import android.app.ActivityManagerNative;
+import android.app.ActivityOptions;
import android.app.IActivityManager;
import android.app.StatusBarManager;
import android.app.admin.DevicePolicyManager;
@@ -176,6 +177,7 @@
static final boolean DEBUG_BOOT = false;
static final boolean DEBUG_LAYOUT_REPEATS = true;
static final boolean DEBUG_SURFACE_TRACE = false;
+ static final boolean DEBUG_WINDOW_TRACE = false;
static final boolean SHOW_SURFACE_ALLOC = false;
static final boolean SHOW_TRANSACTIONS = false;
static final boolean SHOW_LIGHT_TRANSACTIONS = false || SHOW_TRANSACTIONS;
@@ -496,6 +498,7 @@
// mOpeningApps and mClosingApps are the lists of tokens that will be
// made visible or hidden at the next transition.
int mNextAppTransition = WindowManagerPolicy.TRANSIT_UNSET;
+ int mNextAppTransitionType = ActivityOptions.ANIM_NONE;
String mNextAppTransitionPackage;
Bitmap mNextAppTransitionThumbnail;
IRemoteCallback mNextAppTransitionCallback;
@@ -503,6 +506,8 @@
int mNextAppTransitionExit;
int mNextAppTransitionStartX;
int mNextAppTransitionStartY;
+ int mNextAppTransitionStartWidth;
+ int mNextAppTransitionStartHeight;
boolean mAppTransitionReady = false;
boolean mAppTransitionRunning = false;
boolean mAppTransitionTimeout = false;
@@ -593,6 +598,7 @@
static final int SET_WALLPAPER_MAY_CHANGE = 1 << 1;
static final int SET_FORCE_HIDING_CHANGED = 1 << 2;
static final int CLEAR_ORIENTATION_CHANGE_COMPLETE = 1 << 3;
+ static final int SET_TURN_ON_SCREEN = 1 << 4;
boolean mWallpaperForceHidingChanged = false;
boolean mWallpaperMayChange = false;
@@ -616,7 +622,20 @@
public void run() {
synchronized(mWindowMap) {
mAnimationScheduled = false;
- performLayoutAndPlaceSurfacesLocked();
+ // Update animations of all applications, including those
+ // associated with exiting/removed apps
+ synchronized (mAnimator) {
+ final ArrayList<WindowStateAnimator> winAnimators = mAnimator.mWinAnimators;
+ winAnimators.clear();
+ final int N = mWindows.size();
+ for (int i = 0; i < N; i++) {
+ final WindowStateAnimator winAnimator = mWindows.get(i).mWinAnimator;
+ if (winAnimator.mSurface != null) {
+ winAnimators.add(winAnimator);
+ }
+ }
+ mAnimator.animate();
+ }
}
}
}
@@ -3057,6 +3076,50 @@
return null;
}
+ private Animation createScaleUpAnimationLocked(int transit, boolean enter) {
+ Animation a;
+ // Pick the desired duration. If this is an inter-activity transition,
+ // it is the standard duration for that. Otherwise we use the longer
+ // task transition duration.
+ int duration;
+ switch (transit) {
+ case WindowManagerPolicy.TRANSIT_ACTIVITY_OPEN:
+ case WindowManagerPolicy.TRANSIT_ACTIVITY_CLOSE:
+ duration = mContext.getResources().getInteger(
+ com.android.internal.R.integer.config_shortAnimTime);
+ break;
+ default:
+ duration = 500;
+ break;
+ }
+ if (enter) {
+ // Entering app zooms out from the center of the initial rect.
+ Animation scale = new ScaleAnimation(
+ mNextAppTransitionStartWidth/mAppDisplayWidth, 1,
+ mNextAppTransitionStartHeight/mAppDisplayHeight, 1,
+ mNextAppTransitionStartX + mNextAppTransitionStartWidth/2,
+ mNextAppTransitionStartY + mNextAppTransitionStartHeight/2);
+ AnimationSet set = new AnimationSet(true);
+ Animation alpha = new AlphaAnimation(0, 1);
+ scale.setDuration(duration);
+ set.addAnimation(scale);
+ alpha.setDuration(duration);
+ set.addAnimation(alpha);
+ a = set;
+ } else {
+ // Exiting app just holds in place.
+ a = new AlphaAnimation(1, 1);
+ a.setDuration(duration);
+ }
+ a.setFillAfter(true);
+ final Interpolator interpolator = AnimationUtils.loadInterpolator(mContext,
+ com.android.internal.R.interpolator.decelerate_quint);
+ a.setInterpolator(interpolator);
+ a.initialize(mAppDisplayWidth, mAppDisplayHeight,
+ mAppDisplayWidth, mAppDisplayHeight);
+ return a;
+ }
+
private Animation createThumbnailAnimationLocked(int transit,
boolean enter, boolean thumb) {
Animation a;
@@ -3075,7 +3138,6 @@
default:
duration = 500;
break;
-
}
if (thumb) {
// Animation for zooming thumbnail from its initial size to
@@ -3123,12 +3185,15 @@
if (okToDisplay()) {
Animation a;
boolean initialized = false;
- if (mNextAppTransitionThumbnail != null) {
- a = createThumbnailAnimationLocked(transit, enter, false);
- initialized = true;
- } else if (mNextAppTransitionPackage != null) {
+ if (mNextAppTransitionType == ActivityOptions.ANIM_CUSTOM) {
a = loadAnimation(mNextAppTransitionPackage, enter ?
mNextAppTransitionEnter : mNextAppTransitionExit);
+ } else if (mNextAppTransitionType == ActivityOptions.ANIM_SCALE_UP) {
+ a = createScaleUpAnimationLocked(transit, enter);
+ initialized = true;
+ } else if (mNextAppTransitionType == ActivityOptions.ANIM_THUMBNAIL) {
+ a = createThumbnailAnimationLocked(transit, enter, false);
+ initialized = true;
} else {
int animAttr = 0;
switch (transit) {
@@ -3723,6 +3788,7 @@
public void overridePendingAppTransition(String packageName,
int enterAnim, int exitAnim) {
if (mNextAppTransition != WindowManagerPolicy.TRANSIT_UNSET) {
+ mNextAppTransitionType = ActivityOptions.ANIM_CUSTOM;
mNextAppTransitionPackage = packageName;
mNextAppTransitionThumbnail = null;
mNextAppTransitionEnter = enterAnim;
@@ -3730,9 +3796,23 @@
}
}
+ public void overridePendingAppTransitionScaleUp(int startX, int startY, int startWidth,
+ int startHeight) {
+ if (mNextAppTransition != WindowManagerPolicy.TRANSIT_UNSET) {
+ mNextAppTransitionType = ActivityOptions.ANIM_SCALE_UP;
+ mNextAppTransitionPackage = null;
+ mNextAppTransitionThumbnail = null;
+ mNextAppTransitionStartX = startX;
+ mNextAppTransitionStartY = startY;
+ mNextAppTransitionStartWidth = startWidth;
+ mNextAppTransitionStartHeight = startHeight;
+ }
+ }
+
public void overridePendingAppTransitionThumb(Bitmap srcThumb, int startX,
int startY, IRemoteCallback startedCallback) {
if (mNextAppTransition != WindowManagerPolicy.TRANSIT_UNSET) {
+ mNextAppTransitionType = ActivityOptions.ANIM_THUMBNAIL;
mNextAppTransitionPackage = null;
mNextAppTransitionThumbnail = srcThumb;
mNextAppTransitionStartX = startX;
@@ -4165,6 +4245,7 @@
if (w.mHasSurface && !w.mOrientationChanging) {
if (DEBUG_ORIENTATION) Slog.v(TAG, "set mOrientationChanging of " + w);
w.mOrientationChanging = true;
+ mInnerFields.mOrientationChangeComplete = false;
}
unfrozeWindows = true;
}
@@ -5470,6 +5551,7 @@
if (w.mHasSurface) {
if (DEBUG_ORIENTATION) Slog.v(TAG, "Set mOrientationChanging of " + w);
w.mOrientationChanging = true;
+ mInnerFields.mOrientationChangeComplete = false;
}
}
for (int i=mRotationWatchers.size()-1; i>=0; i--) {
@@ -6487,6 +6569,9 @@
@Override
public void handleMessage(Message msg) {
+ if (DEBUG_WINDOW_TRACE) {
+ Slog.v(TAG, "handleMessage: entry what=" + msg.what);
+ }
switch (msg.what) {
case REPORT_FOCUS_CHANGE: {
WindowState lastFocus;
@@ -6918,6 +7003,14 @@
doRequest = true;
}
}
+ if ((msg.arg1 & LayoutFields.SET_TURN_ON_SCREEN) != 0) {
+ mTurnOnScreen = true;
+ }
+
+ mPendingLayoutChanges |= msg.arg2;
+ if (mPendingLayoutChanges != 0) {
+ doRequest = true;
+ }
if (doRequest) {
requestTraversalLocked();
@@ -6962,6 +7055,9 @@
break;
}
}
+ if (DEBUG_WINDOW_TRACE) {
+ Slog.v(TAG, "handleMessage: exit");
+ }
}
}
@@ -6969,6 +7065,7 @@
// IWindowManager API
// -------------------------------------------------------------
+ @Override
public IWindowSession openSession(IInputMethodClient client,
IInputContext inputContext) {
if (client == null) throw new IllegalArgumentException("null client");
@@ -6977,6 +7074,7 @@
return session;
}
+ @Override
public boolean inputMethodClientHasFocus(IInputMethodClient client) {
synchronized (mWindowMap) {
// The focus for the client is the window immediately below
@@ -7410,12 +7508,6 @@
} else {
mLayoutRepeatCount = 0;
}
-
- if (mAnimator.mAnimating) {
- // Do this even if requestTraversalLocked was called above so we get a frame drawn
- // at the proper time as well as the one drawn early.
- scheduleAnimationLocked();
- }
if (mWindowsChanged && !mWindowChangeListeners.isEmpty()) {
mH.removeMessages(H.REPORT_WINDOWS_CHANGE);
@@ -7564,6 +7656,7 @@
if (DEBUG_ORIENTATION) Slog.v(TAG,
"Changing surface while display frozen: " + w);
w.mOrientationChanging = true;
+ mInnerFields.mOrientationChangeComplete = false;
if (!mWindowsFreezingScreen) {
mWindowsFreezingScreen = true;
// XXX should probably keep timeout from
@@ -7820,6 +7913,7 @@
}
}
+ mNextAppTransitionType = ActivityOptions.ANIM_NONE;
mNextAppTransitionPackage = null;
mNextAppTransitionThumbnail = null;
if (mNextAppTransitionCallback != null) {
@@ -7931,7 +8025,7 @@
Slog.v(TAG, "Resize reasons: "
+ " contentInsetsChanged=" + w.mContentInsetsChanged
+ " visibleInsetsChanged=" + w.mVisibleInsetsChanged
- + " surfaceResized=" + w.mWinAnimator.mSurfaceResized
+ + " surfaceResized=" + winAnimator.mSurfaceResized
+ " configChanged=" + configChanged);
}
@@ -7946,7 +8040,7 @@
if (w.mOrientationChanging) {
if (DEBUG_ORIENTATION) Slog.v(TAG,
"Orientation start waiting for draw in "
- + w + ", surface " + w.mWinAnimator.mSurface);
+ + w + ", surface " + winAnimator.mSurface);
winAnimator.mDrawState = WindowStateAnimator.DRAW_PENDING;
if (w.mAppToken != null) {
w.mAppToken.allDrawn = false;
@@ -7954,15 +8048,15 @@
}
if (!mResizingWindows.contains(w)) {
if (DEBUG_RESIZE || DEBUG_ORIENTATION) Slog.v(TAG,
- "Resizing window " + w + " to " + w.mWinAnimator.mSurfaceW
- + "x" + w.mWinAnimator.mSurfaceH);
+ "Resizing window " + w + " to " + winAnimator.mSurfaceW
+ + "x" + winAnimator.mSurfaceH);
mResizingWindows.add(w);
}
} else if (w.mOrientationChanging) {
if (w.isDrawnLw()) {
if (DEBUG_ORIENTATION) Slog.v(TAG,
"Orientation not waiting for draw in "
- + w + ", surface " + w.mWinAnimator.mSurface);
+ + w + ", surface " + winAnimator.mSurface);
w.mOrientationChanging = false;
}
}
@@ -8033,6 +8127,10 @@
// "Something has changed! Let's make it correct now."
private final void performLayoutAndPlaceSurfacesLockedInner(
boolean recoveringMemory) {
+ if (DEBUG_WINDOW_TRACE) {
+ Slog.v(TAG, "performLayoutAndPlaceSurfacesLockedInner: entry. Called by "
+ + Debug.getCallers(3));
+ }
if (mDisplay == null) {
Slog.i(TAG, "skipping performLayoutAndPlaceSurfacesLockedInner with no mDisplay");
return;
@@ -8051,7 +8149,7 @@
updateFocusedWindowLocked(UPDATE_FOCUS_WILL_PLACE_SURFACES,
false /*updateInputWindows*/);
}
-
+
// Initialize state of exiting tokens.
for (i=mExitingTokens.size()-1; i>=0; i--) {
mExitingTokens.get(i).hasVisible = false;
@@ -8065,7 +8163,6 @@
mInnerFields.mHoldScreen = null;
mInnerFields.mScreenBrightness = -1;
mInnerFields.mButtonBrightness = -1;
- mAnimator.mAnimating = false;
if (SHOW_LIGHT_TRANSACTIONS) Slog.i(TAG,
">>> OPEN TRANSACTION performLayoutAndPlaceSurfaces");
@@ -8081,7 +8178,7 @@
try {
int repeats = 0;
-
+
do {
repeats++;
if (repeats > 6) {
@@ -8141,7 +8238,7 @@
mInnerFields.mObscured = false;
mInnerFields.mDimming = false;
mInnerFields.mSyswin = false;
-
+
boolean focusDisplayed = false;
final int N = mWindows.size();
for (i=N-1; i>=0; i--) {
@@ -8165,7 +8262,52 @@
// has been updated accordingly.
updateWallpaperVisibilityLocked();
}
+
+ final WindowStateAnimator winAnimator = w.mWinAnimator;
+
+ // If the window has moved due to its containing
+ // content frame changing, then we'd like to animate
+ // it.
+ if (w.mHasSurface && w.shouldAnimateMove()) {
+ // Frame has moved, containing content frame
+ // has also moved, and we're not currently animating...
+ // let's do something.
+ Animation a = AnimationUtils.loadAnimation(mContext,
+ com.android.internal.R.anim.window_move_from_decor);
+ winAnimator.setAnimation(a);
+ winAnimator.mAnimDw = w.mLastFrame.left - w.mFrame.left;
+ winAnimator.mAnimDh = w.mLastFrame.top - w.mFrame.top;
+ } else {
+ winAnimator.mAnimDw = innerDw;
+ winAnimator.mAnimDh = innerDh;
+ }
+
+ //Slog.i(TAG, "Window " + this + " clearing mContentChanged - done placing");
+ w.mContentChanged = false;
+
+ // Moved from updateWindowsAndWallpaperLocked().
+ if (w.mHasSurface) {
+ // Take care of the window being ready to display.
+ if (winAnimator.commitFinishDrawingLocked(currentTime)) {
+ if ((w.mAttrs.flags
+ & WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER) != 0) {
+ if (WindowManagerService.DEBUG_WALLPAPER) Slog.v(TAG,
+ "First draw done in potential wallpaper target " + w);
+ mInnerFields.mWallpaperMayChange = true;
+ mPendingLayoutChanges |= WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER;
+ if (WindowManagerService.DEBUG_LAYOUT_REPEATS) {
+ debugLayoutRepeats("updateWindowsAndWallpaperLocked 1",
+ mPendingLayoutChanges);
+ }
+ }
+ }
+
+ winAnimator.setSurfaceBoundaries(recoveringMemory);
+ }
+
+ updateResizingWindows(w);
}
+
if (focusDisplayed) {
mH.sendEmptyMessage(H.REPORT_LOSING_FOCUS);
}
@@ -8247,84 +8389,10 @@
if (DEBUG_LAYOUT_REPEATS) debugLayoutRepeats("mLayoutNeeded", mPendingLayoutChanges);
}
- final int N = mWindows.size();
- for (i=N-1; i>=0; i--) {
- final WindowState w = mWindows.get(i);
- final WindowStateAnimator winAnimator = w.mWinAnimator;
-
- // If the window has moved due to its containing
- // content frame changing, then we'd like to animate
- // it.
- if (w.mHasSurface && w.shouldAnimateMove()) {
- // Frame has moved, containing content frame
- // has also moved, and we're not currently animating...
- // let's do something.
- Animation a = AnimationUtils.loadAnimation(mContext,
- com.android.internal.R.anim.window_move_from_decor);
- winAnimator.setAnimation(a);
- winAnimator.mAnimDw = w.mLastFrame.left - w.mFrame.left;
- winAnimator.mAnimDh = w.mLastFrame.top - w.mFrame.top;
- } else {
- winAnimator.mAnimDw = innerDw;
- winAnimator.mAnimDh = innerDh;
- }
-
- //Slog.i(TAG, "Window " + this + " clearing mContentChanged - done placing");
- w.mContentChanged = false;
-
- // TODO(cmautner): Can this move up to the loop at the end of try/catch above?
- updateResizingWindows(w);
-
- // Moved from updateWindowsAndWallpaperLocked().
- if (w.mHasSurface) {
- // Take care of the window being ready to display.
- if (winAnimator.commitFinishDrawingLocked(currentTime)) {
- if ((w.mAttrs.flags
- & WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER) != 0) {
- if (WindowManagerService.DEBUG_WALLPAPER) Slog.v(TAG,
- "First draw done in potential wallpaper target " + w);
- mInnerFields.mWallpaperMayChange = true;
- mPendingLayoutChanges |= WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER;
- if (WindowManagerService.DEBUG_LAYOUT_REPEATS) {
- debugLayoutRepeats("updateWindowsAndWallpaperLocked 1",
- mPendingLayoutChanges);
- }
- }
- }
- }
- }
-
- // Update animations of all applications, including those
- // associated with exiting/removed apps
- synchronized (mAnimator) {
- final ArrayList<WindowStateAnimator> winAnimators = mAnimator.mWinAnimators;
- winAnimators.clear();
- for (i = 0; i < N; i++) {
- final WindowStateAnimator winAnimator = mWindows.get(i).mWinAnimator;
- if (winAnimator.mSurface != null) {
- winAnimators.add(winAnimator);
- }
- }
- mAnimator.animate();
- mPendingLayoutChanges |= mAnimator.mPendingLayoutChanges;
- if (DEBUG_LAYOUT_REPEATS) debugLayoutRepeats("after animate()", mPendingLayoutChanges);
- }
-
- if (DEBUG_ORIENTATION && mDisplayFrozen) Slog.v(TAG,
- "With display frozen, orientationChangeComplete="
- + mInnerFields.mOrientationChangeComplete);
- if (mInnerFields.mOrientationChangeComplete) {
- if (mWindowsFreezingScreen) {
- mWindowsFreezingScreen = false;
- mH.removeMessages(H.WINDOW_FREEZE_TIMEOUT);
- }
- stopFreezingDisplayLocked();
- }
-
if (!mResizingWindows.isEmpty()) {
for (i = mResizingWindows.size() - 1; i >= 0; i--) {
WindowState win = mResizingWindows.get(i);
- final WindowStateAnimator winAnimator = win.mWinAnimator;
+ final WindowStateAnimator winAnimator = win.mWinAnimator;
try {
if (DEBUG_RESIZE || DEBUG_ORIENTATION) Slog.v(TAG,
"Reporting new frame to " + win + ": " + win.mCompatFrame);
@@ -8343,7 +8411,7 @@
win.mConfiguration = mCurConfiguration;
if (DEBUG_ORIENTATION &&
winAnimator.mDrawState == WindowStateAnimator.DRAW_PENDING) Slog.i(
- TAG, "Resizing " + win + " WITH DRAW PENDING");
+ TAG, "Resizing " + win + " WITH DRAW PENDING");
win.mClient.resized((int)winAnimator.mSurfaceW,
(int)winAnimator.mSurfaceH,
win.mLastContentInsets, win.mLastVisibleInsets,
@@ -8359,6 +8427,17 @@
mResizingWindows.clear();
}
+ if (DEBUG_ORIENTATION && mDisplayFrozen) Slog.v(TAG,
+ "With display frozen, orientationChangeComplete="
+ + mInnerFields.mOrientationChangeComplete);
+ if (mInnerFields.mOrientationChangeComplete) {
+ if (mWindowsFreezingScreen) {
+ mWindowsFreezingScreen = false;
+ mH.removeMessages(H.WINDOW_FREEZE_TIMEOUT);
+ }
+ stopFreezingDisplayLocked();
+ }
+
// Destroy the surface of any windows that are no longer visible.
boolean wallpaperDestroyed = false;
i = mDestroySurface.size();
@@ -8475,9 +8554,14 @@
// Check to see if we are now in a state where the screen should
// be enabled, because the window obscured flags have changed.
enableScreenIfNeededLocked();
-// Slog.e(TAG, "performLayoutAndPlaceSurfacesLockedInner exit: mPendingLayoutChanges="
-// + Integer.toHexString(mPendingLayoutChanges) + " mLayoutNeeded=" + mLayoutNeeded
-// + " animating=" + mAnimator.mAnimating);
+
+ scheduleAnimationLocked();
+
+ if (DEBUG_WINDOW_TRACE) {
+ Slog.e(TAG, "performLayoutAndPlaceSurfacesLockedInner exit: mPendingLayoutChanges="
+ + Integer.toHexString(mPendingLayoutChanges) + " mLayoutNeeded=" + mLayoutNeeded
+ + " animating=" + mAnimator.mAnimating);
+ }
}
void checkDrawnWindowsLocked() {
@@ -8789,11 +8873,12 @@
mScreenFrozenLock.acquire();
mDisplayFrozen = true;
-
+
mInputMonitor.freezeInputDispatchingLw();
-
+
if (mNextAppTransition != WindowManagerPolicy.TRANSIT_UNSET) {
mNextAppTransition = WindowManagerPolicy.TRANSIT_UNSET;
+ mNextAppTransitionType = ActivityOptions.ANIM_NONE;
mNextAppTransitionPackage = null;
mNextAppTransitionThumbnail = null;
mAppTransitionReady = true;
@@ -8850,6 +8935,7 @@
mTransitionAnimationScale, mCurDisplayWidth, mCurDisplayHeight)) {
scheduleAnimationLocked();
} else {
+ mAnimator.mScreenRotationAnimation.kill();
mAnimator.mScreenRotationAnimation = null;
updateRotation = true;
}
@@ -9333,20 +9419,34 @@
pw.print(Integer.toHexString(mNextAppTransition));
pw.print(" mAppTransitionReady="); pw.println(mAppTransitionReady);
pw.print(" mAppTransitionRunning="); pw.print(mAppTransitionRunning);
- pw.print(" mAppTransitionTimeout="); pw.println( mAppTransitionTimeout);
- if (mNextAppTransitionPackage != null) {
- pw.print(" mNextAppTransitionPackage=");
- pw.print(mNextAppTransitionPackage);
- pw.print(" mNextAppTransitionEnter=0x");
- pw.print(Integer.toHexString(mNextAppTransitionEnter));
- pw.print(" mNextAppTransitionExit=0x");
- pw.print(Integer.toHexString(mNextAppTransitionExit));
+ pw.print(" mAppTransitionTimeout="); pw.println(mAppTransitionTimeout);
+ if (mNextAppTransitionType != ActivityOptions.ANIM_NONE) {
+ pw.print(" mNextAppTransitionType="); pw.println(mNextAppTransitionType);
}
- if (mNextAppTransitionThumbnail != null) {
- pw.print(" mNextAppTransitionThumbnail=");
- pw.print(mNextAppTransitionThumbnail);
- pw.print(" mNextAppTransitionStartX="); pw.print(mNextAppTransitionStartX);
- pw.print(" mNextAppTransitionStartY="); pw.println(mNextAppTransitionStartY);
+ switch (mNextAppTransitionType) {
+ case ActivityOptions.ANIM_CUSTOM:
+ pw.print(" mNextAppTransitionPackage=");
+ pw.print(mNextAppTransitionPackage);
+ pw.print(" mNextAppTransitionEnter=0x");
+ pw.print(Integer.toHexString(mNextAppTransitionEnter));
+ pw.print(" mNextAppTransitionExit=0x");
+ pw.print(Integer.toHexString(mNextAppTransitionExit));
+ break;
+ case ActivityOptions.ANIM_SCALE_UP:
+ pw.print(" mNextAppTransitionStartX="); pw.print(mNextAppTransitionStartX);
+ pw.print(" mNextAppTransitionStartY=");
+ pw.println(mNextAppTransitionStartY);
+ pw.print(" mNextAppTransitionStartWidth=");
+ pw.print(mNextAppTransitionStartWidth);
+ pw.print(" mNextAppTransitionStartHeight=");
+ pw.println(mNextAppTransitionStartHeight);
+ break;
+ case ActivityOptions.ANIM_THUMBNAIL:
+ pw.print(" mNextAppTransitionThumbnail=");
+ pw.print(mNextAppTransitionThumbnail);
+ pw.print(" mNextAppTransitionStartX="); pw.print(mNextAppTransitionStartX);
+ pw.print(" mNextAppTransitionStartY="); pw.println(mNextAppTransitionStartY);
+ break;
}
pw.print(" mStartingIconInTransition="); pw.print(mStartingIconInTransition);
pw.print(", mSkipAppTransitionAnimation="); pw.println(mSkipAppTransitionAnimation);
@@ -9517,12 +9617,8 @@
}
}
- void bulkSetParameters(final int bulkUpdateParams) {
- mH.sendMessage(mH.obtainMessage(H.BULK_UPDATE_PARAMETERS, bulkUpdateParams, 0));
- }
-
- static String getCaller() {
- StackTraceElement caller = Thread.currentThread().getStackTrace()[4];
- return caller.getClassName() + "." + caller.getMethodName() + ":" + caller.getLineNumber();
+ void bulkSetParameters(final int bulkUpdateParams, int pendingLayoutChanges) {
+ mH.sendMessage(mH.obtainMessage(H.BULK_UPDATE_PARAMETERS, bulkUpdateParams,
+ pendingLayoutChanges));
}
}
diff --git a/services/java/com/android/server/wm/WindowStateAnimator.java b/services/java/com/android/server/wm/WindowStateAnimator.java
index 164325b..3a51afe 100644
--- a/services/java/com/android/server/wm/WindowStateAnimator.java
+++ b/services/java/com/android/server/wm/WindowStateAnimator.java
@@ -6,6 +6,7 @@
import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER;
import static com.android.server.wm.WindowManagerService.LayoutFields.CLEAR_ORIENTATION_CHANGE_COMPLETE;
+import static com.android.server.wm.WindowManagerService.LayoutFields.SET_TURN_ON_SCREEN;
import android.content.Context;
import android.graphics.Matrix;
@@ -14,6 +15,7 @@
import android.graphics.PointF;
import android.graphics.Rect;
import android.graphics.Region;
+import android.os.Debug;
import android.os.RemoteException;
import android.util.Slog;
import android.view.Surface;
@@ -84,9 +86,9 @@
*/
boolean mSurfaceDestroyDeferred;
- float mShownAlpha = 1;
- float mAlpha = 1;
- float mLastAlpha = 1;
+ float mShownAlpha = 0;
+ float mAlpha = 0;
+ float mLastAlpha = 0;
// Used to save animation distances between the time they are calculated and when they are
// used.
@@ -403,50 +405,55 @@
return true;
}
- static class MySurface extends Surface {
- final static ArrayList<MySurface> sSurfaces = new ArrayList<MySurface>();
+ static class SurfaceTrace extends Surface {
+ private final static String SURFACE_TAG = "SurfaceTrace";
+ final static ArrayList<SurfaceTrace> sSurfaces = new ArrayList<SurfaceTrace>();
- private float mMySurfaceAlpha = 0xff;
+ private float mSurfaceTraceAlpha = 0;
private int mLayer;
private PointF mPosition = new PointF();
- private Point mSize = new Point();
+ private Point mSize;
private boolean mShown = false;
private String mName = "Not named";
- public MySurface(SurfaceSession s,
+ public SurfaceTrace(SurfaceSession s,
int pid, int display, int w, int h, int format, int flags) throws
OutOfResourcesException {
super(s, pid, display, w, h, format, flags);
mSize = new Point(w, h);
- Slog.v("SurfaceTrace", "ctor: " + this);
+ Slog.v(SURFACE_TAG, "ctor: " + this + ". Called by "
+ + Debug.getCallers(3));
}
- public MySurface(SurfaceSession s,
+ public SurfaceTrace(SurfaceSession s,
int pid, String name, int display, int w, int h, int format, int flags)
throws OutOfResourcesException {
super(s, pid, name, display, w, h, format, flags);
mName = name;
mSize = new Point(w, h);
- Slog.v("SurfaceTrace", "ctor: " + this);
+ Slog.v(SURFACE_TAG, "ctor: " + this + ". Called by "
+ + Debug.getCallers(3));
}
@Override
public void setAlpha(float alpha) {
super.setAlpha(alpha);
- mMySurfaceAlpha = alpha;
- Slog.v("SurfaceTrace", "setAlpha: " + this);
+ mSurfaceTraceAlpha = alpha;
+ Slog.v(SURFACE_TAG, "setAlpha: " + this + ". Called by "
+ + Debug.getCallers(3));
}
@Override
public void setLayer(int zorder) {
super.setLayer(zorder);
mLayer = zorder;
- Slog.v("SurfaceTrace", "setLayer: " + this);
+ Slog.v(SURFACE_TAG, "setLayer: " + this + ". Called by "
+ + Debug.getCallers(3));
sSurfaces.remove(this);
int i;
for (i = sSurfaces.size() - 1; i >= 0; i--) {
- MySurface s = sSurfaces.get(i);
+ SurfaceTrace s = sSurfaces.get(i);
if (s.mLayer < zorder) {
break;
}
@@ -458,32 +465,46 @@
public void setPosition(float x, float y) {
super.setPosition(x, y);
mPosition = new PointF(x, y);
+ Slog.v(SURFACE_TAG, "setPosition: " + this + ". Called by "
+ + Debug.getCallers(3));
}
@Override
public void setSize(int w, int h) {
super.setSize(w, h);
mSize = new Point(w, h);
+ Slog.v(SURFACE_TAG, "setSize: " + this + ". Called by "
+ + Debug.getCallers(3));
}
@Override
public void hide() {
super.hide();
mShown = false;
- Slog.v("SurfaceTrace", "hide: " + this);
+ Slog.v(SURFACE_TAG, "hide: " + this + ". Called by "
+ + Debug.getCallers(3));
}
@Override
public void show() {
super.show();
mShown = true;
- Slog.v("SurfaceTrace", "show: " + this);
+ Slog.v(SURFACE_TAG, "show: " + this + ". Called by "
+ + Debug.getCallers(3));
}
@Override
public void destroy() {
super.destroy();
- Slog.v("SurfaceTrace", "destroy: " + this + ". Called by "
- + WindowManagerService.getCaller());
+ Slog.v(SURFACE_TAG, "destroy: " + this + ". Called by "
+ + Debug.getCallers(3));
+ sSurfaces.remove(this);
+ }
+
+ @Override
+ public void release() {
+ super.release();
+ Slog.v(SURFACE_TAG, "release: " + this + ". Called by "
+ + Debug.getCallers(3));
sSurfaces.remove(this);
}
@@ -497,7 +518,7 @@
@Override
public String toString() {
return "Surface " + mName + ": shown=" + mShown + " layer=" + mLayer
- + " alpha=" + mMySurfaceAlpha + " " + mPosition.x + "," + mPosition.y
+ + " alpha=" + mSurfaceTraceAlpha + " " + mPosition.x + "," + mPosition.y
+ " " + mSize.x + "x" + mSize.y;
}
}
@@ -544,7 +565,7 @@
mSurfaceShown = false;
mSurfaceLayer = 0;
- mSurfaceAlpha = 1;
+ mSurfaceAlpha = 0;
mSurfaceX = 0;
mSurfaceY = 0;
mSurfaceW = w;
@@ -557,7 +578,7 @@
flags |= Surface.OPAQUE;
}
if (DEBUG_SURFACE_TRACE) {
- mSurface = new MySurface(
+ mSurface = new SurfaceTrace(
mSession.mSurfaceSession, mSession.mPid,
attrs.getTitle().toString(),
0, w, h, format, flags);
@@ -608,6 +629,7 @@
mSurface.setPosition(mSurfaceX, mSurfaceY);
mSurfaceLayer = mAnimLayer;
mSurface.setLayer(mAnimLayer);
+ mSurface.setAlpha(0);
mSurfaceShown = false;
mSurface.hide();
if ((mWin.mAttrs.flags&WindowManager.LayoutParams.FLAG_DITHER) != 0) {
@@ -873,22 +895,8 @@
mDtDy = mWin.mGlobalScale;
}
- public void prepareSurfaceLocked(final boolean recoveringMemory) {
+ void setSurfaceBoundaries(final boolean recoveringMemory) {
final WindowState w = mWin;
- if (mSurface == null) {
- if (w.mOrientationChanging) {
- if (DEBUG_ORIENTATION) {
- Slog.v(TAG, "Orientation change skips hidden " + w);
- }
- w.mOrientationChanging = false;
- }
- return;
- }
-
- boolean displayed = false;
-
- computeShownFrameLocked();
-
int width, height;
if ((w.mAttrs.flags & LayoutParams.FLAG_SCALED) != 0) {
// for a scaled surface, we just want to use
@@ -937,6 +945,8 @@
"SIZE " + width + "x" + height, null);
mSurfaceResized = true;
mSurface.setSize(width, height);
+ mAnimator.mPendingLayoutChanges |=
+ WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER;
} catch (RuntimeException e) {
// If something goes wrong with the surface (such
// as running out of memory), don't take down the
@@ -948,8 +958,27 @@
}
}
}
+ }
- if (w.mAttachedHidden || !w.isReadyForDisplay()) {
+ public void prepareSurfaceLocked(final boolean recoveringMemory) {
+ final WindowState w = mWin;
+ if (mSurface == null) {
+ if (w.mOrientationChanging) {
+ if (DEBUG_ORIENTATION) {
+ Slog.v(TAG, "Orientation change skips hidden " + w);
+ }
+ w.mOrientationChanging = false;
+ }
+ return;
+ }
+
+ boolean displayed = false;
+
+ computeShownFrameLocked();
+
+ setSurfaceBoundaries(recoveringMemory);
+
+ if (w.mAttachedHidden || !w.isReadyForDisplay() || !w.isDrawnLw()) {
if (!mLastHidden) {
//dump();
mLastHidden = true;
@@ -1185,7 +1214,7 @@
if (DEBUG_VISIBILITY) Slog.v(TAG,
"Show surface turning screen on: " + mWin);
mWin.mTurnOnScreen = false;
- mService.mTurnOnScreen = true;
+ mAnimator.mBulkUpdateParams |= SET_TURN_ON_SCREEN;
}
}
return true;
diff --git a/services/jni/Android.mk b/services/jni/Android.mk
index ac4fd15..e2bd622 100644
--- a/services/jni/Android.mk
+++ b/services/jni/Android.mk
@@ -22,7 +22,8 @@
$(JNI_H_INCLUDE) \
frameworks/base/services \
frameworks/base/core/jni \
- external/skia/include/core
+ external/skia/include/core \
+ libcore/include
LOCAL_SHARED_LIBRARIES := \
libandroid_runtime \
diff --git a/services/jni/com_android_server_input_InputManagerService.cpp b/services/jni/com_android_server_input_InputManagerService.cpp
index 3795074..b361a26 100644
--- a/services/jni/com_android_server_input_InputManagerService.cpp
+++ b/services/jni/com_android_server_input_InputManagerService.cpp
@@ -46,6 +46,9 @@
#include <android_view_PointerIcon.h>
#include <android/graphics/GraphicsJNI.h>
+#include <ScopedLocalRef.h>
+#include <ScopedUtfChars.h>
+
#include "com_android_server_PowerManagerService.h"
#include "com_android_server_input_InputApplicationHandle.h"
#include "com_android_server_input_InputWindowHandle.h"
@@ -79,6 +82,7 @@
jmethodID getLongPressTimeout;
jmethodID getPointerLayer;
jmethodID getPointerIcon;
+ jmethodID getKeyboardLayoutOverlay;
} gServiceClassInfo;
static struct {
@@ -179,12 +183,14 @@
void setSystemUiVisibility(int32_t visibility);
void setPointerSpeed(int32_t speed);
void setShowTouches(bool enabled);
+ void reloadKeyboardLayouts();
/* --- InputReaderPolicyInterface implementation --- */
virtual void getReaderConfiguration(InputReaderConfiguration* outConfig);
virtual sp<PointerControllerInterface> obtainPointerController(int32_t deviceId);
virtual void notifyInputDevicesChanged(const Vector<InputDeviceInfo>& inputDevices);
+ virtual sp<KeyCharacterMap> getKeyboardLayoutOverlay(const String8& inputDeviceDescriptor);
/* --- InputDispatcherPolicyInterface implementation --- */
@@ -522,6 +528,29 @@
checkAndClearExceptionFromCallback(env, "notifyInputDevicesChanged");
}
+sp<KeyCharacterMap> NativeInputManager::getKeyboardLayoutOverlay(
+ const String8& inputDeviceDescriptor) {
+ JNIEnv* env = jniEnv();
+
+ sp<KeyCharacterMap> result;
+ ScopedLocalRef<jstring> descriptorObj(env, env->NewStringUTF(inputDeviceDescriptor.string()));
+ ScopedLocalRef<jobjectArray> arrayObj(env, jobjectArray(env->CallObjectMethod(mServiceObj,
+ gServiceClassInfo.getKeyboardLayoutOverlay, descriptorObj.get())));
+ if (arrayObj.get()) {
+ ScopedLocalRef<jstring> filenameObj(env,
+ jstring(env->GetObjectArrayElement(arrayObj.get(), 0)));
+ ScopedLocalRef<jstring> contentsObj(env,
+ jstring(env->GetObjectArrayElement(arrayObj.get(), 1)));
+ ScopedUtfChars filenameChars(env, filenameObj.get());
+ ScopedUtfChars contentsChars(env, contentsObj.get());
+
+ KeyCharacterMap::loadContents(String8(filenameChars.c_str()),
+ String8(contentsChars.c_str()), KeyCharacterMap::FORMAT_OVERLAY, &result);
+ }
+ checkAndClearExceptionFromCallback(env, "getKeyboardLayoutOverlay");
+ return result;
+}
+
void NativeInputManager::notifySwitch(nsecs_t when, int32_t switchCode,
int32_t switchValue, uint32_t policyFlags) {
#if DEBUG_INPUT_DISPATCHER_POLICY
@@ -728,6 +757,11 @@
InputReaderConfiguration::CHANGE_SHOW_TOUCHES);
}
+void NativeInputManager::reloadKeyboardLayouts() {
+ mInputManager->getReader()->requestRefreshConfiguration(
+ InputReaderConfiguration::CHANGE_KEYBOARD_LAYOUTS);
+}
+
bool NativeInputManager::isScreenOn() {
return android_server_PowerManagerService_isScreenOn();
}
@@ -1258,6 +1292,13 @@
im->getInputManager()->getReader()->cancelVibrate(deviceId, token);
}
+static void nativeReloadKeyboardLayouts(JNIEnv* env,
+ jclass clazz, jint ptr) {
+ NativeInputManager* im = reinterpret_cast<NativeInputManager*>(ptr);
+
+ im->reloadKeyboardLayouts();
+}
+
static jstring nativeDump(JNIEnv* env, jclass clazz, jint ptr) {
NativeInputManager* im = reinterpret_cast<NativeInputManager*>(ptr);
@@ -1323,6 +1364,8 @@
(void*) nativeVibrate },
{ "nativeCancelVibrate", "(III)V",
(void*) nativeCancelVibrate },
+ { "nativeReloadKeyboardLayouts", "(I)V",
+ (void*) nativeReloadKeyboardLayouts },
{ "nativeDump", "(I)Ljava/lang/String;",
(void*) nativeDump },
{ "nativeMonitor", "(I)V",
@@ -1418,6 +1461,9 @@
GET_METHOD_ID(gServiceClassInfo.getPointerIcon, clazz,
"getPointerIcon", "()Landroid/view/PointerIcon;");
+ GET_METHOD_ID(gServiceClassInfo.getKeyboardLayoutOverlay, clazz,
+ "getKeyboardLayoutOverlay", "(Ljava/lang/String;)[Ljava/lang/String;");
+
// InputDevice
FIND_CLASS(gInputDeviceClassInfo.clazz, "android/view/InputDevice");
diff --git a/telephony/java/android/telephony/PhoneNumberUtils.java b/telephony/java/android/telephony/PhoneNumberUtils.java
index 8cfdb79..183beb1 100644
--- a/telephony/java/android/telephony/PhoneNumberUtils.java
+++ b/telephony/java/android/telephony/PhoneNumberUtils.java
@@ -64,8 +64,8 @@
/*
* Calling Line Identification Restriction (CLIR)
*/
- private static final String CLIR_ON = "*31#+";
- private static final String CLIR_OFF = "#31#+";
+ private static final String CLIR_ON = "*31#";
+ private static final String CLIR_OFF = "#31#";
/*
* TOA = TON + NPI
@@ -213,23 +213,26 @@
int len = phoneNumber.length();
StringBuilder ret = new StringBuilder(len);
- boolean firstCharAdded = false;
for (int i = 0; i < len; i++) {
char c = phoneNumber.charAt(i);
- if (isDialable(c) && (c != '+' || !firstCharAdded)) {
- firstCharAdded = true;
+ // Character.digit() supports ASCII and Unicode digits (fullwidth, Arabic-Indic, etc.)
+ int digit = Character.digit(c, 10);
+ if (digit != -1) {
+ ret.append(digit);
+ } else if (c == '+') {
+ // Allow '+' as first character or after CLIR MMI prefix
+ String prefix = ret.toString();
+ if (prefix.length() == 0 || prefix.equals(CLIR_ON) || prefix.equals(CLIR_OFF)) {
+ ret.append(c);
+ }
+ } else if (isDialable(c)) {
ret.append(c);
} else if (isStartsPostDial (c)) {
break;
}
}
- int pos = addPlusChar(phoneNumber);
- if (pos >= 0 && ret.length() > pos) {
- ret.insert(pos, '+');
- }
-
return ret.toString();
}
@@ -283,7 +286,11 @@
for (int i = 0; i < len; i++) {
char c = phoneNumber.charAt(i);
- if (isNonSeparator(c)) {
+ // Character.digit() supports ASCII and Unicode digits (fullwidth, Arabic-Indic, etc.)
+ int digit = Character.digit(c, 10);
+ if (digit != -1) {
+ ret.append(digit);
+ } else if (isNonSeparator(c)) {
ret.append(c);
}
}
@@ -371,28 +378,6 @@
}
}
- /** GSM codes
- * Finds if a GSM code includes the international prefix (+).
- *
- * @param number the number to dial.
- *
- * @return the position where the + char will be inserted, -1 if the GSM code was not found.
- */
- private static int
- addPlusChar(String number) {
- int pos = -1;
-
- if (number.startsWith(CLIR_OFF)) {
- pos = CLIR_OFF.length() - 1;
- }
-
- if (number.startsWith(CLIR_ON)) {
- pos = CLIR_ON.length() - 1;
- }
-
- return pos;
- }
-
/**
* Extracts the post-dial sequence of DTMF control digits, pauses, and
* waits. Strips separators. This string may be empty, but will not be null
@@ -1504,7 +1489,11 @@
int len = phoneNumber.length();
for (int i = 0; i < len; i++) {
char c = phoneNumber.charAt(i);
- if ((i == 0 && c == '+') || PhoneNumberUtils.isISODigit(c)) {
+ // Character.digit() supports ASCII and Unicode digits (fullwidth, Arabic-Indic, etc.)
+ int digit = Character.digit(c, 10);
+ if (digit != -1) {
+ sb.append(digit);
+ } else if (i == 0 && c == '+') {
sb.append(c);
} else if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')) {
return normalizeNumber(PhoneNumberUtils.convertKeypadLettersToDigits(phoneNumber));
@@ -1513,6 +1502,27 @@
return sb.toString();
}
+ /**
+ * Replace arabic/unicode digits with decimal digits.
+ * @param number
+ * the number to be normalized.
+ * @return the replaced number.
+ *
+ * @hide
+ */
+ public static String replaceUnicodeDigits(String number) {
+ StringBuilder normalizedDigits = new StringBuilder(number.length());
+ for (char c : number.toCharArray()) {
+ int digit = Character.digit(c, 10);
+ if (digit != -1) {
+ normalizedDigits.append(digit);
+ } else {
+ normalizedDigits.append(c);
+ }
+ }
+ return normalizedDigits.toString();
+ }
+
// Three and four digit phone numbers for either special services,
// or 3-6 digit addresses from the network (eg carrier-originated SMS messages) should
// not match.
diff --git a/telephony/java/com/android/internal/telephony/CallerInfo.java b/telephony/java/com/android/internal/telephony/CallerInfo.java
index 5d1f758..b1a5872 100644
--- a/telephony/java/com/android/internal/telephony/CallerInfo.java
+++ b/telephony/java/com/android/internal/telephony/CallerInfo.java
@@ -18,6 +18,7 @@
import android.content.Context;
import android.database.Cursor;
+import android.graphics.Bitmap;
import android.graphics.drawable.Drawable;
import android.location.CountryDetector;
import android.net.Uri;
@@ -107,10 +108,33 @@
/**
* Drawable representing the caller image. This is essentially
* a cache for the image data tied into the connection /
- * callerinfo object. The isCachedPhotoCurrent flag indicates
- * if the image data needs to be reloaded.
+ * callerinfo object.
+ *
+ * This might be a high resolution picture which is more suitable
+ * for full-screen image view than for smaller icons used in some
+ * kinds of notifications.
+ *
+ * The {@link #isCachedPhotoCurrent} flag indicates if the image
+ * data needs to be reloaded.
*/
public Drawable cachedPhoto;
+ /**
+ * Bitmap representing the caller image which has possibly lower
+ * resolution than {@link #cachedPhoto} and thus more suitable for
+ * icons (like notification icons).
+ *
+ * In usual cases this is just down-scaled image of {@link #cachedPhoto}.
+ * If the down-scaling fails, this will just become null.
+ *
+ * The {@link #isCachedPhotoCurrent} flag indicates if the image
+ * data needs to be reloaded.
+ */
+ public Bitmap cachedPhotoIcon;
+ /**
+ * Boolean which indicates if {@link #cachedPhoto} and
+ * {@link #cachedPhotoIcon} is fresh enough. If it is false,
+ * those images aren't pointing to valid objects.
+ */
public boolean isCachedPhotoCurrent;
private boolean mIsEmergency;
diff --git a/telephony/java/com/android/internal/telephony/DataConnectionTracker.java b/telephony/java/com/android/internal/telephony/DataConnectionTracker.java
index 55f2ca3..214627d 100644
--- a/telephony/java/com/android/internal/telephony/DataConnectionTracker.java
+++ b/telephony/java/com/android/internal/telephony/DataConnectionTracker.java
@@ -46,6 +46,7 @@
import com.android.internal.R;
import com.android.internal.telephony.DataConnection.FailCause;
+import com.android.internal.telephony.uicc.UiccController;
import com.android.internal.util.AsyncChannel;
import com.android.internal.util.Protocol;
@@ -57,6 +58,7 @@
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicInteger;
+import java.util.concurrent.atomic.AtomicReference;
/**
* {@hide}
@@ -138,6 +140,7 @@
public static final int EVENT_CLEAN_UP_ALL_CONNECTIONS = BASE + 30;
public static final int CMD_SET_DEPENDENCY_MET = BASE + 31;
public static final int CMD_SET_POLICY_DATA_ENABLE = BASE + 32;
+ protected static final int EVENT_ICC_CHANGED = BASE + 33;
/***** Constants *****/
@@ -250,6 +253,8 @@
// member variables
protected PhoneBase mPhone;
+ protected UiccController mUiccController;
+ protected AtomicReference<IccRecords> mIccRecords = new AtomicReference<IccRecords>();
protected Activity mActivity = Activity.NONE;
protected State mState = State.IDLE;
protected Handler mDataConnectionTracker = null;
@@ -500,6 +505,8 @@
protected DataConnectionTracker(PhoneBase phone) {
super();
mPhone = phone;
+ mUiccController = UiccController.getInstance();
+ mUiccController.registerForIccChanged(this, EVENT_ICC_CHANGED, null);
IntentFilter filter = new IntentFilter();
filter.addAction(getActionIntentReconnectAlarm());
@@ -541,6 +548,7 @@
mIsDisposed = true;
mPhone.getContext().unregisterReceiver(this.mIntentReceiver);
mDataRoamingSettingObserver.unregister(mPhone.getContext());
+ mUiccController.unregisterForIccChanged(this);
}
protected void broadcastMessenger() {
@@ -663,6 +671,7 @@
protected abstract void onCleanUpConnection(boolean tearDown, int apnId, String reason);
protected abstract void onCleanUpAllConnections(String cause);
protected abstract boolean isDataPossible(String apnType);
+ protected abstract void onUpdateIcc();
protected void onDataStallAlarm(int tag) {
loge("onDataStallAlarm: not impleted tag=" + tag);
@@ -773,6 +782,10 @@
onSetPolicyDataEnabled(enabled);
break;
}
+ case EVENT_ICC_CHANGED:
+ onUpdateIcc();
+ break;
+
default:
Log.e("DATA", "Unidentified event msg=" + msg);
break;
diff --git a/telephony/java/com/android/internal/telephony/IccCard.java b/telephony/java/com/android/internal/telephony/IccCard.java
index 92024cd..140b7c6 100644
--- a/telephony/java/com/android/internal/telephony/IccCard.java
+++ b/telephony/java/com/android/internal/telephony/IccCard.java
@@ -35,10 +35,12 @@
import com.android.internal.telephony.PhoneBase;
import com.android.internal.telephony.CommandsInterface.RadioState;
+import com.android.internal.telephony.gsm.GSMPhone;
import com.android.internal.telephony.gsm.SIMFileHandler;
import com.android.internal.telephony.gsm.SIMRecords;
import com.android.internal.telephony.cat.CatService;
import com.android.internal.telephony.cdma.CDMALTEPhone;
+import com.android.internal.telephony.cdma.CDMAPhone;
import com.android.internal.telephony.cdma.CdmaLteUiccFileHandler;
import com.android.internal.telephony.cdma.CdmaLteUiccRecords;
import com.android.internal.telephony.cdma.CdmaSubscriptionSourceManager;
@@ -114,8 +116,6 @@
protected static final int EVENT_ICC_LOCKED = 1;
private static final int EVENT_GET_ICC_STATUS_DONE = 2;
protected static final int EVENT_RADIO_OFF_OR_NOT_AVAILABLE = 3;
- private static final int EVENT_PINPUK_DONE = 4;
- private static final int EVENT_REPOLL_STATUS_DONE = 5;
protected static final int EVENT_ICC_READY = 6;
private static final int EVENT_QUERY_FACILITY_LOCK_DONE = 7;
private static final int EVENT_CHANGE_FACILITY_LOCK_DONE = 8;
@@ -178,34 +178,19 @@
return State.UNKNOWN;
}
- public IccCard(PhoneBase phone, String logTag, Boolean is3gpp, Boolean dbg) {
+ public IccCard(PhoneBase phone, IccCardStatus ics, String logTag, boolean dbg) {
mLogTag = logTag;
mDbg = dbg;
- if (mDbg) log("[IccCard] Creating card type " + (is3gpp ? "3gpp" : "3gpp2"));
- mPhone = phone;
- this.is3gpp = is3gpp;
+ if (mDbg) log("Creating");
+ update(phone, ics);
mCdmaSSM = CdmaSubscriptionSourceManager.getInstance(mPhone.getContext(),
mPhone.mCM, mHandler, EVENT_CDMA_SUBSCRIPTION_SOURCE_CHANGED, null);
- if (phone.mCM.getLteOnCdmaMode() == Phone.LTE_ON_CDMA_TRUE
- && phone instanceof CDMALTEPhone) {
- mIccFileHandler = new CdmaLteUiccFileHandler(this, "", mPhone.mCM);
- mIccRecords = new CdmaLteUiccRecords(this, mPhone.mContext, mPhone.mCM);
- } else {
- // Correct aid will be set later (when GET_SIM_STATUS returns)
- mIccFileHandler = is3gpp ? new SIMFileHandler(this, "", mPhone.mCM) :
- new RuimFileHandler(this, "", mPhone.mCM);
- mIccRecords = is3gpp ? new SIMRecords(this, mPhone.mContext, mPhone.mCM) :
- new RuimRecords(this, mPhone.mContext, mPhone.mCM);
- }
- mCatService = CatService.getInstance(mPhone.mCM, mIccRecords,
- mPhone.mContext, mIccFileHandler, this);
mPhone.mCM.registerForOffOrNotAvailable(mHandler, EVENT_RADIO_OFF_OR_NOT_AVAILABLE, null);
mPhone.mCM.registerForOn(mHandler, EVENT_RADIO_ON, null);
- mPhone.mCM.registerForIccStatusChanged(mHandler, EVENT_ICC_STATUS_CHANGED, null);
}
public void dispose() {
- if (mDbg) log("[IccCard] Disposing card type " + (is3gpp ? "3gpp" : "3gpp2"));
+ if (mDbg) log("Disposing card type " + (is3gpp ? "3gpp" : "3gpp2"));
mPhone.mCM.unregisterForIccStatusChanged(mHandler);
mPhone.mCM.unregisterForOffOrNotAvailable(mHandler);
mPhone.mCM.unregisterForOn(mHandler);
@@ -215,6 +200,40 @@
mIccFileHandler.dispose();
}
+ public void update(PhoneBase phone, IccCardStatus ics) {
+ if (phone != mPhone) {
+ PhoneBase oldPhone = mPhone;
+ mPhone = phone;
+ log("Update");
+ if (phone instanceof GSMPhone) {
+ is3gpp = true;
+ } else if (phone instanceof CDMALTEPhone){
+ is3gpp = true;
+ } else if (phone instanceof CDMAPhone){
+ is3gpp = false;
+ } else {
+ throw new RuntimeException("Update: Unhandled phone type. Critical error!" +
+ phone.getPhoneName());
+ }
+
+
+ if (phone.mCM.getLteOnCdmaMode() == Phone.LTE_ON_CDMA_TRUE
+ && phone instanceof CDMALTEPhone) {
+ mIccFileHandler = new CdmaLteUiccFileHandler(this, "", mPhone.mCM);
+ mIccRecords = new CdmaLteUiccRecords(this, mPhone.mContext, mPhone.mCM);
+ } else {
+ // Correct aid will be set later (when GET_SIM_STATUS returns)
+ mIccFileHandler = is3gpp ? new SIMFileHandler(this, "", mPhone.mCM) :
+ new RuimFileHandler(this, "", mPhone.mCM);
+ mIccRecords = is3gpp ? new SIMRecords(this, mPhone.mContext, mPhone.mCM) :
+ new RuimRecords(this, mPhone.mContext, mPhone.mCM);
+ }
+ mCatService = CatService.getInstance(mPhone.mCM, mIccRecords, mPhone.mContext,
+ mIccFileHandler, this);
+ }
+ mHandler.sendMessage(mHandler.obtainMessage(EVENT_GET_ICC_STATUS_DONE, ics));
+ }
+
protected void finalize() {
if (mDbg) log("[IccCard] Finalized card type " + (is3gpp ? "3gpp" : "3gpp2"));
}
@@ -344,27 +363,23 @@
*/
public void supplyPin (String pin, Message onComplete) {
- mPhone.mCM.supplyIccPin(pin, mHandler.obtainMessage(EVENT_PINPUK_DONE, onComplete));
+ mPhone.mCM.supplyIccPin(pin, onComplete);
}
public void supplyPuk (String puk, String newPin, Message onComplete) {
- mPhone.mCM.supplyIccPuk(puk, newPin,
- mHandler.obtainMessage(EVENT_PINPUK_DONE, onComplete));
+ mPhone.mCM.supplyIccPuk(puk, newPin, onComplete);
}
public void supplyPin2 (String pin2, Message onComplete) {
- mPhone.mCM.supplyIccPin2(pin2,
- mHandler.obtainMessage(EVENT_PINPUK_DONE, onComplete));
+ mPhone.mCM.supplyIccPin2(pin2, onComplete);
}
public void supplyPuk2 (String puk2, String newPin2, Message onComplete) {
- mPhone.mCM.supplyIccPuk2(puk2, newPin2,
- mHandler.obtainMessage(EVENT_PINPUK_DONE, onComplete));
+ mPhone.mCM.supplyIccPuk2(puk2, newPin2, onComplete);
}
public void supplyNetworkDepersonalization (String pin, Message onComplete) {
- mPhone.mCM.supplyNetworkDepersonalization(pin,
- mHandler.obtainMessage(EVENT_PINPUK_DONE, onComplete));
+ mPhone.mCM.supplyNetworkDepersonalization(pin, onComplete);
}
/**
@@ -494,21 +509,15 @@
*
*/
public String getServiceProviderName () {
- return mPhone.mIccRecords.getServiceProviderName();
+ return mIccRecords.getServiceProviderName();
}
protected void updateStateProperty() {
mPhone.setSystemProperty(TelephonyProperties.PROPERTY_SIM_STATE, getState().toString());
}
- private void getIccCardStatusDone(AsyncResult ar) {
- if (ar.exception != null) {
- Log.e(mLogTag,"Error getting ICC status. "
- + "RIL_REQUEST_GET_ICC_STATUS should "
- + "never return an error", ar.exception);
- return;
- }
- handleIccCardStatus((IccCardStatus) ar.result);
+ private void getIccCardStatusDone(IccCardStatus ics) {
+ handleIccCardStatus(ics);
}
private void handleIccCardStatus(IccCardStatus newCardStatus) {
@@ -584,6 +593,7 @@
if (oldState != State.READY && newState == State.READY &&
(is3gpp || isSubscriptionFromIccCard)) {
mIccFileHandler.setAid(getAid());
+ broadcastIccStateChangedIntent(INTENT_VALUE_ICC_READY, null);
mIccRecords.onReady();
}
}
@@ -704,7 +714,6 @@
if (!is3gpp) {
handleCdmaSubscriptionSource();
}
- mPhone.mCM.getIccCardStatus(obtainMessage(EVENT_GET_ICC_STATUS_DONE));
break;
case EVENT_CDMA_SUBSCRIPTION_SOURCE_CHANGED:
handleCdmaSubscriptionSource();
@@ -725,30 +734,9 @@
obtainMessage(EVENT_QUERY_FACILITY_LOCK_DONE));
break;
case EVENT_GET_ICC_STATUS_DONE:
- ar = (AsyncResult)msg.obj;
+ IccCardStatus cs = (IccCardStatus)msg.obj;
- getIccCardStatusDone(ar);
- break;
- case EVENT_PINPUK_DONE:
- // a PIN/PUK/PIN2/PUK2/Network Personalization
- // request has completed. ar.userObj is the response Message
- // Repoll before returning
- ar = (AsyncResult)msg.obj;
- // TODO should abstract these exceptions
- AsyncResult.forMessage(((Message)ar.userObj)).exception
- = ar.exception;
- mPhone.mCM.getIccCardStatus(
- obtainMessage(EVENT_REPOLL_STATUS_DONE, ar.userObj));
- break;
- case EVENT_REPOLL_STATUS_DONE:
- // Finished repolling status after PIN operation
- // ar.userObj is the response messaeg
- // ar.userObj.obj is already an AsyncResult with an
- // appropriate exception filled in if applicable
-
- ar = (AsyncResult)msg.obj;
- getIccCardStatusDone(ar);
- ((Message)ar.userObj).sendToTarget();
+ getIccCardStatusDone(cs);
break;
case EVENT_QUERY_FACILITY_LOCK_DONE:
ar = (AsyncResult)msg.obj;
@@ -797,10 +785,6 @@
= ar.exception;
((Message)ar.userObj).sendToTarget();
break;
- case EVENT_ICC_STATUS_CHANGED:
- Log.d(mLogTag, "Received Event EVENT_ICC_STATUS_CHANGED");
- mPhone.mCM.getIccCardStatus(obtainMessage(EVENT_GET_ICC_STATUS_DONE));
- break;
case EVENT_CARD_REMOVED:
onIccSwap(false);
break;
@@ -967,6 +951,10 @@
Log.d(mLogTag, "[IccCard] " + msg);
}
+ private void loge(String msg) {
+ Log.e(mLogTag, "[IccCard] " + msg);
+ }
+
protected int getCurrentApplicationIndex() {
if (is3gpp) {
return mIccCardStatus.getGsmUmtsSubscriptionAppIndex();
diff --git a/telephony/java/com/android/internal/telephony/IccPhoneBookInterfaceManager.java b/telephony/java/com/android/internal/telephony/IccPhoneBookInterfaceManager.java
index 45562ca..0e5f2da 100644
--- a/telephony/java/com/android/internal/telephony/IccPhoneBookInterfaceManager.java
+++ b/telephony/java/com/android/internal/telephony/IccPhoneBookInterfaceManager.java
@@ -103,11 +103,23 @@
public IccPhoneBookInterfaceManager(PhoneBase phone) {
this.phone = phone;
+ IccRecords r = phone.mIccRecords.get();
+ if (r != null) {
+ adnCache = r.getAdnCache();
+ }
}
public void dispose() {
}
+ public void updateIccRecords(IccRecords iccRecords) {
+ if (iccRecords != null) {
+ adnCache = iccRecords.getAdnCache();
+ } else {
+ adnCache = null;
+ }
+ }
+
protected void publish() {
//NOTE service "simphonebook" added by IccSmsInterfaceManagerProxy
ServiceManager.addService("simphonebook", this);
diff --git a/telephony/java/com/android/internal/telephony/IccRecords.java b/telephony/java/com/android/internal/telephony/IccRecords.java
index 41c9d5a..3c906471a 100644
--- a/telephony/java/com/android/internal/telephony/IccRecords.java
+++ b/telephony/java/com/android/internal/telephony/IccRecords.java
@@ -26,6 +26,8 @@
import com.android.internal.telephony.gsm.UsimServiceTable;
import com.android.internal.telephony.ims.IsimRecords;
+import java.util.concurrent.atomic.AtomicBoolean;
+
/**
* {@hide}
*/
@@ -33,7 +35,7 @@
protected static final boolean DBG = true;
// ***** Instance Variables
- protected boolean mDestroyed = false; // set to true once this object needs to be disposed of
+ protected AtomicBoolean mDestroyed = new AtomicBoolean(false);
protected Context mContext;
protected CommandsInterface mCi;
protected IccFileHandler mFh;
@@ -79,9 +81,9 @@
// ***** Event Constants
protected static final int EVENT_SET_MSISDN_DONE = 30;
- public static final int EVENT_MWI = 0;
- public static final int EVENT_CFI = 1;
- public static final int EVENT_SPN = 2;
+ public static final int EVENT_MWI = 0; // Message Waiting indication
+ public static final int EVENT_CFI = 1; // Call Forwarding indication
+ public static final int EVENT_SPN = 2; // Service Provider Name
public static final int EVENT_GET_ICC_RECORD_DONE = 100;
@@ -113,7 +115,7 @@
* Call when the IccRecords object is no longer going to be used.
*/
public void dispose() {
- mDestroyed = true;
+ mDestroyed.set(true);
mParentCard = null;
mFh = null;
mCi = null;
@@ -128,12 +130,8 @@
return adnCache;
}
- public IccCard getIccCard() {
- return mParentCard;
- }
-
public void registerForRecordsLoaded(Handler h, int what, Object obj) {
- if (mDestroyed) {
+ if (mDestroyed.get()) {
return;
}
diff --git a/telephony/java/com/android/internal/telephony/PhoneBase.java b/telephony/java/com/android/internal/telephony/PhoneBase.java
index 2ac9365..0c2f234 100644
--- a/telephony/java/com/android/internal/telephony/PhoneBase.java
+++ b/telephony/java/com/android/internal/telephony/PhoneBase.java
@@ -40,6 +40,7 @@
import com.android.internal.telephony.gsm.UsimServiceTable;
import com.android.internal.telephony.ims.IsimRecords;
import com.android.internal.telephony.test.SimulatedRadioControl;
+import com.android.internal.telephony.uicc.UiccController;
import com.android.internal.telephony.gsm.SIMRecords;
import java.io.FileDescriptor;
@@ -110,6 +111,7 @@
protected static final int EVENT_SET_NETWORK_AUTOMATIC = 28;
protected static final int EVENT_NEW_ICC_SMS = 29;
protected static final int EVENT_ICC_RECORD_EVENTS = 30;
+ protected static final int EVENT_ICC_CHANGED = 31;
// Key used to read/write current CLIR setting
public static final String CLIR_KEY = "clir_key";
@@ -126,7 +128,8 @@
int mCallRingDelay;
public boolean mIsTheCurrentActivePhone = true;
boolean mIsVoiceCapable = true;
- public IccRecords mIccRecords;
+ protected UiccController mUiccController = null;
+ public AtomicReference<IccRecords> mIccRecords = new AtomicReference<IccRecords>();
protected AtomicReference<IccCard> mIccCard = new AtomicReference<IccCard>();
public SmsStorageMonitor mSmsStorageMonitor;
public SmsUsageMonitor mSmsUsageMonitor;
@@ -251,6 +254,8 @@
// Initialize device storage and outgoing SMS usage monitors for SMSDispatchers.
mSmsStorageMonitor = new SmsStorageMonitor(this);
mSmsUsageMonitor = new SmsUsageMonitor(context);
+ mUiccController = UiccController.getInstance(this);
+ mUiccController.registerForIccChanged(this, EVENT_ICC_CHANGED, null);
}
public void dispose() {
@@ -262,6 +267,7 @@
// Dispose the SMS usage and storage monitors
mSmsStorageMonitor.dispose();
mSmsUsageMonitor.dispose();
+ mUiccController.unregisterForIccChanged(this);
}
}
@@ -269,9 +275,10 @@
mSmsStorageMonitor = null;
mSmsUsageMonitor = null;
mSMS = null;
- mIccRecords = null;
+ mIccRecords.set(null);
mIccCard.set(null);
mDataConnectionTracker = null;
+ mUiccController = null;
}
/**
@@ -308,6 +315,10 @@
}
break;
+ case EVENT_ICC_CHANGED:
+ onUpdateIccAvailability();
+ break;
+
default:
throw new RuntimeException("unexpected event not handled");
}
@@ -318,6 +329,9 @@
return mContext;
}
+ // Will be called when icc changed
+ protected abstract void onUpdateIccAvailability();
+
/**
* Disables the DNS check (i.e., allows "0.0.0.0").
* Useful for lab testing environment.
@@ -666,22 +680,26 @@
@Override
public String getIccSerialNumber() {
- return mIccRecords.iccid;
+ IccRecords r = mIccRecords.get();
+ return (r != null) ? r.iccid : "";
}
@Override
public boolean getIccRecordsLoaded() {
- return mIccRecords.getRecordsLoaded();
+ IccRecords r = mIccRecords.get();
+ return (r != null) ? r.getRecordsLoaded() : false;
}
@Override
public boolean getMessageWaitingIndicator() {
- return mIccRecords.getVoiceMessageWaiting();
+ IccRecords r = mIccRecords.get();
+ return (r != null) ? r.getVoiceMessageWaiting() : false;
}
@Override
public boolean getCallForwardingIndicator() {
- return mIccRecords.getVoiceCallForwardingFlag();
+ IccRecords r = mIccRecords.get();
+ return (r != null) ? r.getVoiceCallForwardingFlag() : false;
}
/**
@@ -1135,7 +1153,10 @@
*/
@Override
public void setVoiceMessageWaiting(int line, int countWaiting) {
- mIccRecords.setVoiceMessageWaiting(line, countWaiting);
+ IccRecords r = mIccRecords.get();
+ if (r != null) {
+ r.setVoiceMessageWaiting(line, countWaiting);
+ }
}
/**
@@ -1144,7 +1165,8 @@
*/
@Override
public UsimServiceTable getUsimServiceTable() {
- return mIccRecords.getUsimServiceTable();
+ IccRecords r = mIccRecords.get();
+ return (r != null) ? r.getUsimServiceTable() : null;
}
public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
diff --git a/telephony/java/com/android/internal/telephony/ServiceStateTracker.java b/telephony/java/com/android/internal/telephony/ServiceStateTracker.java
index 75eb226..a86b68b 100644
--- a/telephony/java/com/android/internal/telephony/ServiceStateTracker.java
+++ b/telephony/java/com/android/internal/telephony/ServiceStateTracker.java
@@ -18,12 +18,15 @@
import android.os.AsyncResult;
import android.os.Handler;
+import android.os.Looper;
import android.os.Message;
import android.os.Registrant;
import android.os.RegistrantList;
import android.telephony.ServiceState;
import android.telephony.SignalStrength;
+import com.android.internal.telephony.uicc.UiccController;
+
import java.io.FileDescriptor;
import java.io.PrintWriter;
@@ -33,6 +36,9 @@
public abstract class ServiceStateTracker extends Handler {
protected CommandsInterface cm;
+ protected UiccController mUiccController = null;
+ protected IccCard mIccCard = null;
+ protected IccRecords mIccRecords = null;
public ServiceState ss;
protected ServiceState newSS;
@@ -130,7 +136,7 @@
protected static final int EVENT_CDMA_SUBSCRIPTION_SOURCE_CHANGED = 39;
protected static final int EVENT_CDMA_PRL_VERSION_CHANGED = 40;
protected static final int EVENT_RADIO_ON = 41;
-
+ protected static final int EVENT_ICC_CHANGED = 42;
protected static final String TIMEZONE_PROPERTY = "persist.sys.timezone";
@@ -167,7 +173,10 @@
protected static final String REGISTRATION_DENIED_GEN = "General";
protected static final String REGISTRATION_DENIED_AUTH = "Authentication Failure";
- public ServiceStateTracker() {
+ public ServiceStateTracker(PhoneBase p, CommandsInterface ci) {
+ cm = ci;
+ mUiccController = UiccController.getInstance();
+ mUiccController.registerForIccChanged(this, EVENT_ICC_CHANGED, null);
}
public boolean getDesiredPowerState() {
@@ -294,6 +303,10 @@
}
break;
+ case EVENT_ICC_CHANGED:
+ onUpdateIccAvailability();
+ break;
+
default:
log("Unhandled message with number: " + msg.what);
break;
@@ -304,6 +317,7 @@
protected abstract void handlePollStateResult(int what, AsyncResult ar);
protected abstract void updateSpnDisplay();
protected abstract void setPowerStateToDesired();
+ protected abstract void onUpdateIccAvailability();
protected abstract void log(String s);
protected abstract void loge(String s);
@@ -463,6 +477,21 @@
pollingContext = new int[1];
}
+ /**
+ * Verifies the current thread is the same as the thread originally
+ * used in the initialization of this instance. Throws RuntimeException
+ * if not.
+ *
+ * @exception RuntimeException if the current thread is not
+ * the thread that originally obtained this PhoneBase instance.
+ */
+ protected void checkCorrectThread() {
+ if (Thread.currentThread() != getLooper().getThread()) {
+ throw new RuntimeException(
+ "ServiceStateTracker must be used from within one thread");
+ }
+ }
+
public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
pw.println("ServiceStateTracker:");
pw.println(" ss=" + ss);
diff --git a/telephony/java/com/android/internal/telephony/cdma/CDMALTEPhone.java b/telephony/java/com/android/internal/telephony/cdma/CDMALTEPhone.java
index d99a625..24bb814 100644
--- a/telephony/java/com/android/internal/telephony/cdma/CDMALTEPhone.java
+++ b/telephony/java/com/android/internal/telephony/cdma/CDMALTEPhone.java
@@ -29,6 +29,7 @@
import com.android.internal.telephony.CommandsInterface;
import com.android.internal.telephony.IccCard;
+import com.android.internal.telephony.IccRecords;
import com.android.internal.telephony.OperatorInfo;
import com.android.internal.telephony.Phone;
import com.android.internal.telephony.PhoneNotifier;
@@ -66,7 +67,6 @@
public CDMALTEPhone(Context context, CommandsInterface ci, PhoneNotifier notifier) {
super(context, ci, notifier, false);
m3gppSMS = new GsmSMSDispatcher(this, mSmsStorageMonitor, mSmsUsageMonitor);
- mIccRecords.registerForNewSms(this, EVENT_NEW_ICC_SMS, null);
}
@Override
@@ -88,10 +88,6 @@
@Override
protected void initSstIcc() {
- mIccCard.set(UiccController.getInstance(this).getIccCard());
- mIccRecords = mIccCard.get().getIccRecords();
- // CdmaLteServiceStateTracker registers with IccCard to know
- // when the card is ready. So create mIccCard before the ServiceStateTracker
mSST = new CdmaLteServiceStateTracker(this);
}
@@ -100,7 +96,6 @@
synchronized(PhoneProxy.lockForRadioTechnologyChange) {
super.dispose();
m3gppSMS.dispose();
- mIccRecords.unregisterForNewSms(this);
}
}
@@ -203,11 +198,12 @@
@Override
public boolean updateCurrentCarrierInProvider() {
- if (mIccRecords != null) {
+ IccRecords r = mIccRecords.get();
+ if (r != null) {
try {
Uri uri = Uri.withAppendedPath(Telephony.Carriers.CONTENT_URI, "current");
ContentValues map = new ContentValues();
- String operatorNumeric = mIccRecords.getOperatorNumeric();
+ String operatorNumeric = r.getOperatorNumeric();
map.put(Telephony.Carriers.NUMERIC, operatorNumeric);
if (DBG) log("updateCurrentCarrierInProvider from UICC: numeric=" +
operatorNumeric);
@@ -225,7 +221,8 @@
// return IMSI from USIM as subscriber ID.
@Override
public String getSubscriberId() {
- return mIccRecords.getIMSI();
+ IccRecords r = mIccRecords.get();
+ return (r != null) ? r.getIMSI() : "";
}
@Override
@@ -240,12 +237,14 @@
@Override
public IsimRecords getIsimRecords() {
- return mIccRecords.getIsimRecords();
+ IccRecords r = mIccRecords.get();
+ return (r != null) ? r.getIsimRecords() : null;
}
@Override
public String getMsisdn() {
- return mIccRecords.getMsisdnNumber();
+ IccRecords r = mIccRecords.get();
+ return (r != null) ? r.getMsisdnNumber() : null;
}
@Override
@@ -259,6 +258,26 @@
}
@Override
+ protected void registerForRuimRecordEvents() {
+ IccRecords r = mIccRecords.get();
+ if (r == null) {
+ return;
+ }
+ r.registerForNewSms(this, EVENT_NEW_ICC_SMS, null);
+ super.registerForRuimRecordEvents();
+ }
+
+ @Override
+ protected void unregisterForRuimRecordEvents() {
+ IccRecords r = mIccRecords.get();
+ if (r == null) {
+ return;
+ }
+ r.unregisterForNewSms(this);
+ super.unregisterForRuimRecordEvents();
+ }
+
+ @Override
protected void log(String s) {
Log.d(LOG_TAG, "[CDMALTEPhone] " + s);
}
diff --git a/telephony/java/com/android/internal/telephony/cdma/CDMAPhone.java b/telephony/java/com/android/internal/telephony/cdma/CDMAPhone.java
index 9f6ec71..7922b3c 100755
--- a/telephony/java/com/android/internal/telephony/cdma/CDMAPhone.java
+++ b/telephony/java/com/android/internal/telephony/cdma/CDMAPhone.java
@@ -50,6 +50,7 @@
import com.android.internal.telephony.IccException;
import com.android.internal.telephony.IccFileHandler;
import com.android.internal.telephony.IccPhoneBookInterfaceManager;
+import com.android.internal.telephony.IccRecords;
import com.android.internal.telephony.IccSmsInterfaceManager;
import com.android.internal.telephony.MccTable;
import com.android.internal.telephony.MmiCode;
@@ -152,10 +153,6 @@
}
protected void initSstIcc() {
- mIccCard.set(UiccController.getInstance(this).getIccCard());
- mIccRecords = mIccCard.get().getIccRecords();
- // CdmaServiceStateTracker registers with IccCard to know
- // when the Ruim card is ready. So create mIccCard before the ServiceStateTracker
mSST = new CdmaServiceStateTracker(this);
}
@@ -172,7 +169,6 @@
mEriManager = new EriManager(this, context, EriManager.ERI_FROM_XML);
mCM.registerForAvailable(this, EVENT_RADIO_AVAILABLE, null);
- registerForRuimRecordEvents();
mCM.registerForOffOrNotAvailable(this, EVENT_RADIO_OFF_OR_NOT_AVAILABLE, null);
mCM.registerForOn(this, EVENT_RADIO_ON, null);
mCM.setOnSuppServiceNotification(this, EVENT_SSN, null);
@@ -727,7 +723,10 @@
Message resp;
mVmNumber = voiceMailNumber;
resp = obtainMessage(EVENT_SET_VM_NUMBER_DONE, 0, 0, onComplete);
- mIccRecords.setVoiceMailNumber(alphaTag, mVmNumber, resp);
+ IccRecords r = mIccRecords.get();
+ if (r != null) {
+ r.setVoiceMailNumber(alphaTag, mVmNumber, resp);
+ }
}
public String getVoiceMailNumber() {
@@ -749,7 +748,8 @@
* @hide
*/
public int getVoiceMessageCount() {
- int voicemailCount = mIccRecords.getVoiceMessageCount();
+ IccRecords r = mIccRecords.get();
+ int voicemailCount = (r != null) ? r.getVoiceMessageCount() : 0;
// If mRuimRecords.getVoiceMessageCount returns zero, then there is possibility
// that phone was power cycled and would have lost the voicemail count.
// So get the count from preferences.
@@ -1064,6 +1064,39 @@
}
}
+ @Override
+ protected void onUpdateIccAvailability() {
+ if (mUiccController == null ) {
+ return;
+ }
+
+ IccCard newIccCard = mUiccController.getIccCard();
+
+ IccCard c = mIccCard.get();
+ if (c != newIccCard) {
+ if (c != null) {
+ log("Removing stale icc objects.");
+ if (mIccRecords.get() != null) {
+ unregisterForRuimRecordEvents();
+ if (mRuimPhoneBookInterfaceManager != null) {
+ mRuimPhoneBookInterfaceManager.updateIccRecords(null);
+ }
+ }
+ mIccRecords.set(null);
+ mIccCard.set(null);
+ }
+ if (newIccCard != null) {
+ log("New card found");
+ mIccCard.set(newIccCard);
+ mIccRecords.set(newIccCard.getIccRecords());
+ registerForRuimRecordEvents();
+ if (mRuimPhoneBookInterfaceManager != null) {
+ mRuimPhoneBookInterfaceManager.updateIccRecords(mIccRecords.get());
+ }
+ }
+ }
+ }
+
private void processIccRecordEvents(int eventCode) {
switch (eventCode) {
case RuimRecords.EVENT_MWI:
@@ -1462,14 +1495,22 @@
return mEriManager.isEriFileLoaded();
}
- private void registerForRuimRecordEvents() {
- mIccRecords.registerForRecordsEvents(this, EVENT_ICC_RECORD_EVENTS, null);
- mIccRecords.registerForRecordsLoaded(this, EVENT_RUIM_RECORDS_LOADED, null);
+ protected void registerForRuimRecordEvents() {
+ IccRecords r = mIccRecords.get();
+ if (r == null) {
+ return;
+ }
+ r.registerForRecordsEvents(this, EVENT_ICC_RECORD_EVENTS, null);
+ r.registerForRecordsLoaded(this, EVENT_RUIM_RECORDS_LOADED, null);
}
- private void unregisterForRuimRecordEvents() {
- mIccRecords.unregisterForRecordsEvents(this);
- mIccRecords.unregisterForRecordsLoaded(this);
+ protected void unregisterForRuimRecordEvents() {
+ IccRecords r = mIccRecords.get();
+ if (r == null) {
+ return;
+ }
+ r.unregisterForRecordsEvents(this);
+ r.unregisterForRecordsLoaded(this);
}
protected void log(String s) {
diff --git a/telephony/java/com/android/internal/telephony/cdma/CdmaDataConnectionTracker.java b/telephony/java/com/android/internal/telephony/cdma/CdmaDataConnectionTracker.java
index 7e5e707..d05ed624 100644
--- a/telephony/java/com/android/internal/telephony/cdma/CdmaDataConnectionTracker.java
+++ b/telephony/java/com/android/internal/telephony/cdma/CdmaDataConnectionTracker.java
@@ -40,6 +40,8 @@
import com.android.internal.telephony.DataConnectionAc;
import com.android.internal.telephony.DataConnectionTracker;
import com.android.internal.telephony.EventLogTags;
+import com.android.internal.telephony.IccCard;
+import com.android.internal.telephony.IccRecords;
import com.android.internal.telephony.RetryManager;
import com.android.internal.telephony.RILConstants;
import com.android.internal.telephony.Phone;
@@ -110,7 +112,6 @@
p.mCM.registerForAvailable (this, EVENT_RADIO_AVAILABLE, null);
p.mCM.registerForOffOrNotAvailable(this, EVENT_RADIO_OFF_OR_NOT_AVAILABLE, null);
- p.mIccRecords.registerForRecordsLoaded(this, EVENT_RECORDS_LOADED, null);
p.mCM.registerForDataNetworkStateChanged (this, EVENT_DATA_STATE_CHANGED, null);
p.mCT.registerForVoiceCallEnded (this, EVENT_VOICE_CALL_ENDED, null);
p.mCT.registerForVoiceCallStarted (this, EVENT_VOICE_CALL_STARTED, null);
@@ -152,7 +153,8 @@
// Unregister from all events
mPhone.mCM.unregisterForAvailable(this);
mPhone.mCM.unregisterForOffOrNotAvailable(this);
- mCdmaPhone.mIccRecords.unregisterForRecordsLoaded(this);
+ IccRecords r = mIccRecords.get();
+ if (r != null) { r.unregisterForRecordsLoaded(this);}
mPhone.mCM.unregisterForDataNetworkStateChanged(this);
mCdmaPhone.mCT.unregisterForVoiceCallEnded(this);
mCdmaPhone.mCT.unregisterForVoiceCallStarted(this);
@@ -222,11 +224,12 @@
boolean subscriptionFromNv = (mCdmaSSM.getCdmaSubscriptionSource()
== CdmaSubscriptionSourceManager.SUBSCRIPTION_FROM_NV);
+ IccRecords r = mIccRecords.get();
boolean allowed =
(psState == ServiceState.STATE_IN_SERVICE ||
mAutoAttachOnCreation) &&
(subscriptionFromNv ||
- mCdmaPhone.mIccRecords.getRecordsLoaded()) &&
+ (r != null && r.getRecordsLoaded())) &&
(mCdmaPhone.mSST.isConcurrentVoiceAndDataAllowed() ||
mPhone.getState() == Phone.State.IDLE) &&
!roaming &&
@@ -241,7 +244,7 @@
reason += " - psState= " + psState;
}
if (!subscriptionFromNv &&
- !mCdmaPhone.mIccRecords.getRecordsLoaded()) {
+ !(r != null && r.getRecordsLoaded())) {
reason += " - RUIM not loaded";
}
if (!(mCdmaPhone.mSST.isConcurrentVoiceAndDataAllowed() ||
@@ -1006,6 +1009,33 @@
}
@Override
+ protected void onUpdateIcc() {
+ if (mUiccController == null ) {
+ return;
+ }
+
+ IccCard newIccCard = mUiccController.getIccCard();
+ IccRecords newIccRecords = null;
+ if (newIccCard != null) {
+ newIccRecords = newIccCard.getIccRecords();
+ }
+
+ IccRecords r = mIccRecords.get();
+ if (r != newIccRecords) {
+ if (r != null) {
+ log("Removing stale icc objects.");
+ r.unregisterForRecordsLoaded(this);
+ mIccRecords.set(null);
+ }
+ if (newIccCard != null) {
+ log("New card found");
+ mIccRecords.set(newIccRecords);
+ newIccRecords.registerForRecordsLoaded(this, EVENT_RECORDS_LOADED, null);
+ }
+ }
+ }
+
+ @Override
public boolean isDisconnected() {
return ((mState == State.IDLE) || (mState == State.FAILED));
}
diff --git a/telephony/java/com/android/internal/telephony/cdma/CdmaLteServiceStateTracker.java b/telephony/java/com/android/internal/telephony/cdma/CdmaLteServiceStateTracker.java
index ff7a0810..9a82f57 100644
--- a/telephony/java/com/android/internal/telephony/cdma/CdmaLteServiceStateTracker.java
+++ b/telephony/java/com/android/internal/telephony/cdma/CdmaLteServiceStateTracker.java
@@ -65,7 +65,7 @@
handlePollStateResult(msg.what, ar);
break;
case EVENT_RUIM_RECORDS_LOADED:
- CdmaLteUiccRecords sim = (CdmaLteUiccRecords)phone.mIccRecords;
+ CdmaLteUiccRecords sim = (CdmaLteUiccRecords)mIccRecords;
if ((sim != null) && sim.isProvisioned()) {
mMdn = sim.getMdn();
mMin = sim.getMin();
@@ -353,16 +353,18 @@
ss.setOperatorAlphaLong(eriText);
}
- if (phone.getIccCard().getState() == IccCard.State.READY) {
+ if (mIccCard != null && mIccCard.getState() == IccCard.State.READY &&
+ mIccRecords != null) {
// SIM is found on the device. If ERI roaming is OFF, and SID/NID matches
// one configfured in SIM, use operator name from CSIM record.
boolean showSpn =
- ((CdmaLteUiccRecords)phone.mIccRecords).getCsimSpnDisplayCondition();
+ ((CdmaLteUiccRecords)mIccRecords).getCsimSpnDisplayCondition();
int iconIndex = ss.getCdmaEriIconIndex();
if (showSpn && (iconIndex == EriInfo.ROAMING_INDICATOR_OFF) &&
- isInHomeSidNid(ss.getSystemId(), ss.getNetworkId())) {
- ss.setOperatorAlphaLong(phone.mIccRecords.getServiceProviderName());
+ isInHomeSidNid(ss.getSystemId(), ss.getNetworkId()) &&
+ mIccRecords != null) {
+ ss.setOperatorAlphaLong(mIccRecords.getServiceProviderName());
}
}
diff --git a/telephony/java/com/android/internal/telephony/cdma/CdmaServiceStateTracker.java b/telephony/java/com/android/internal/telephony/cdma/CdmaServiceStateTracker.java
index b694e0a..16ff70e 100755
--- a/telephony/java/com/android/internal/telephony/cdma/CdmaServiceStateTracker.java
+++ b/telephony/java/com/android/internal/telephony/cdma/CdmaServiceStateTracker.java
@@ -115,12 +115,6 @@
long mSavedTime;
long mSavedAtTime;
- /**
- * We can't register for SIM_RECORDS_LOADED immediately because the
- * SIMRecords object may not be instantiated yet.
- */
- private boolean mNeedToRegForRuimLoaded = false;
-
/** Wake lock used while setting time of day. */
private PowerManager.WakeLock mWakeLock;
private static final String WAKELOCK_TAG = "ServiceStateTracker";
@@ -162,11 +156,10 @@
};
public CdmaServiceStateTracker(CDMAPhone phone) {
- super();
+ super(phone, phone.mCM);
this.phone = phone;
cr = phone.getContext().getContentResolver();
- cm = phone.mCM;
ss = new ServiceState();
newSS = new ServiceState();
cellLoc = new CdmaCellLocation();
@@ -203,18 +196,17 @@
Settings.System.getUriFor(Settings.System.AUTO_TIME_ZONE), true,
mAutoTimeZoneObserver);
setSignalStrengthDefaultValues();
-
- mNeedToRegForRuimLoaded = true;
}
public void dispose() {
+ checkCorrectThread();
// Unregister for all events.
cm.unregisterForRadioStateChanged(this);
cm.unregisterForVoiceNetworkStateChanged(this);
- phone.getIccCard().unregisterForReady(this);
cm.unregisterForCdmaOtaProvision(this);
phone.unregisterForEriFileLoaded(this);
- phone.mIccRecords.unregisterForRecordsLoaded(this);
+ if (mIccCard != null) {mIccCard.unregisterForReady(this);}
+ if (mIccRecords != null) {mIccRecords.unregisterForRecordsLoaded(this);}
cm.unSetOnSignalStrengthUpdate(this);
cm.unSetOnNITZTime(this);
cr.unregisterContentObserver(mAutoTimeObserver);
@@ -285,14 +277,6 @@
case EVENT_RUIM_READY:
// TODO: Consider calling setCurrentPreferredNetworkType as we do in GsmSST.
// cm.setCurrentPreferredNetworkType();
-
- // The RUIM is now ready i.e if it was locked it has been
- // unlocked. At this stage, the radio is already powered on.
- if (mNeedToRegForRuimLoaded) {
- phone.mIccRecords.registerForRecordsLoaded(this,
- EVENT_RUIM_RECORDS_LOADED, null);
- mNeedToRegForRuimLoaded = false;
- }
if (DBG) log("Receive EVENT_RUIM_READY and Send Request getCDMASubscription.");
getSubscriptionInfoAndStartPollingThreads();
phone.prepareEri();
@@ -405,8 +389,16 @@
mIsMinInfoReady = true;
updateOtaspState();
- phone.getIccCard().broadcastIccStateChangedIntent(IccCard.INTENT_VALUE_ICC_IMSI,
- null);
+ if (mIccCard != null) {
+ if (DBG) log("GET_CDMA_SUBSCRIPTION broadcast Icc state changed");
+ mIccCard.broadcastIccStateChangedIntent(IccCard.INTENT_VALUE_ICC_IMSI,
+ null);
+ } else {
+ if (DBG) {
+ log("GET_CDMA_SUBSCRIPTION mIccCard is null (probably NV type device)" +
+ " can't broadcast Icc state changed");
+ }
+ }
} else {
if (DBG) {
log("GET_CDMA_SUBSCRIPTION: error parsing cdmaSubscription params num="
@@ -498,8 +490,6 @@
if (!isSubscriptionFromRuim) {
// NV is ready when subscription source is NV
sendMessage(obtainMessage(EVENT_NV_READY));
- } else {
- phone.getIccCard().registerForReady(this, EVENT_RUIM_READY, null);
}
}
@@ -1695,6 +1685,38 @@
}
@Override
+ protected void onUpdateIccAvailability() {
+ if (mUiccController == null ) {
+ return;
+ }
+
+ IccCard newIccCard = mUiccController.getIccCard();
+
+ if (mIccCard != newIccCard) {
+ if (mIccCard != null) {
+ log("Removing stale icc objects.");
+ mIccCard.unregisterForReady(this);
+ if (mIccRecords != null) {
+ mIccRecords.unregisterForRecordsLoaded(this);
+ }
+ mIccRecords = null;
+ mIccCard = null;
+ }
+ if (newIccCard != null) {
+ log("New card found");
+ mIccCard = newIccCard;
+ mIccRecords = mIccCard.getIccRecords();
+ if (isSubscriptionFromRuim) {
+ mIccCard.registerForReady(this, EVENT_RUIM_READY, null);
+ if (mIccRecords != null) {
+ mIccRecords.registerForRecordsLoaded(this, EVENT_RUIM_RECORDS_LOADED, null);
+ }
+ }
+ }
+ }
+ }
+
+ @Override
protected void log(String s) {
Log.d(LOG_TAG, "[CdmaSST] " + s);
}
@@ -1727,7 +1749,6 @@
pw.println(" mSavedTimeZone=" + mSavedTimeZone);
pw.println(" mSavedTime=" + mSavedTime);
pw.println(" mSavedAtTime=" + mSavedAtTime);
- pw.println(" mNeedToRegForRuimLoaded=" + mNeedToRegForRuimLoaded);
pw.println(" mWakeLock=" + mWakeLock);
pw.println(" mCurPlmn=" + mCurPlmn);
pw.println(" mMdn=" + mMdn);
diff --git a/telephony/java/com/android/internal/telephony/cdma/RuimPhoneBookInterfaceManager.java b/telephony/java/com/android/internal/telephony/cdma/RuimPhoneBookInterfaceManager.java
index 04ee2dd8..e919245 100644
--- a/telephony/java/com/android/internal/telephony/cdma/RuimPhoneBookInterfaceManager.java
+++ b/telephony/java/com/android/internal/telephony/cdma/RuimPhoneBookInterfaceManager.java
@@ -21,6 +21,7 @@
import android.os.Message;
import android.util.Log;
+import com.android.internal.telephony.IccFileHandler;
import com.android.internal.telephony.IccPhoneBookInterfaceManager;
/**
@@ -34,7 +35,6 @@
public RuimPhoneBookInterfaceManager(CDMAPhone phone) {
super(phone);
- adnCache = phone.mIccRecords.getAdnCache();
//NOTE service "simphonebook" added by IccSmsInterfaceManagerProxy
}
@@ -61,8 +61,12 @@
AtomicBoolean status = new AtomicBoolean(false);
Message response = mBaseHandler.obtainMessage(EVENT_GET_SIZE_DONE, status);
- phone.getIccFileHandler().getEFLinearRecordSize(efid, response);
- waitForResult(status);
+ IccFileHandler fh = phone.getIccFileHandler();
+ //IccFileHandler can be null if there is no icc card present.
+ if (fh != null) {
+ fh.getEFLinearRecordSize(efid, response);
+ waitForResult(status);
+ }
}
return recordSize;
diff --git a/telephony/java/com/android/internal/telephony/cdma/RuimRecords.java b/telephony/java/com/android/internal/telephony/cdma/RuimRecords.java
index 2fefa3f..80183c6 100755
--- a/telephony/java/com/android/internal/telephony/cdma/RuimRecords.java
+++ b/telephony/java/com/android/internal/telephony/cdma/RuimRecords.java
@@ -199,7 +199,7 @@
boolean isRecordLoadResponse = false;
- if (mDestroyed) {
+ if (mDestroyed.get()) {
loge("Received message " + msg +
"[" + msg.what + "] while being destroyed. Ignoring.");
return;
@@ -317,18 +317,20 @@
// One record loaded successfully or failed, In either case
// we need to update the recordsToLoad count
recordsToLoad -= 1;
- if (DBG) log("RuimRecords:onRecordLoaded " + recordsToLoad + " requested: " + recordsRequested);
+ if (DBG) log("onRecordLoaded " + recordsToLoad + " requested: " + recordsRequested);
if (recordsToLoad == 0 && recordsRequested == true) {
onAllRecordsLoaded();
} else if (recordsToLoad < 0) {
- loge("RuimRecords: recordsToLoad <0, programmer error suspected");
+ loge("recordsToLoad <0, programmer error suspected");
recordsToLoad = 0;
}
}
@Override
protected void onAllRecordsLoaded() {
+ if (DBG) log("record load complete");
+
// Further records that can be inserted are Operator/OEM dependent
String operator = getRUIMOperatorNumeric();
@@ -348,13 +350,6 @@
@Override
public void onReady() {
- /* broadcast intent ICC_READY here so that we can make sure
- READY is sent before IMSI ready
- */
-
- mParentCard.broadcastIccStateChangedIntent(
- IccCard.INTENT_VALUE_ICC_READY, null);
-
fetchRuimRecords();
mCi.getCDMASubscription(obtainMessage(EVENT_GET_CDMA_SUBSCRIPTION_DONE));
@@ -364,7 +359,7 @@
private void fetchRuimRecords() {
recordsRequested = true;
- Log.v(LOG_TAG, "RuimRecords:fetchRuimRecords " + recordsToLoad);
+ if (DBG) log("fetchRuimRecords " + recordsToLoad);
mCi.getIMSI(obtainMessage(EVENT_GET_IMSI_DONE));
recordsToLoad++;
@@ -373,7 +368,7 @@
obtainMessage(EVENT_GET_ICCID_DONE));
recordsToLoad++;
- log("RuimRecords:fetchRuimRecords " + recordsToLoad + " requested: " + recordsRequested);
+ if (DBG) log("fetchRuimRecords " + recordsToLoad + " requested: " + recordsRequested);
// Further records that can be inserted are Operator/OEM dependent
}
diff --git a/telephony/java/com/android/internal/telephony/gsm/GSMPhone.java b/telephony/java/com/android/internal/telephony/gsm/GSMPhone.java
index 6e9cd51..8dda74b 100644
--- a/telephony/java/com/android/internal/telephony/gsm/GSMPhone.java
+++ b/telephony/java/com/android/internal/telephony/gsm/GSMPhone.java
@@ -59,6 +59,7 @@
import com.android.internal.telephony.IccCard;
import com.android.internal.telephony.IccFileHandler;
import com.android.internal.telephony.IccPhoneBookInterfaceManager;
+import com.android.internal.telephony.IccRecords;
import com.android.internal.telephony.IccSmsInterfaceManager;
import com.android.internal.telephony.MmiCode;
import com.android.internal.telephony.OperatorInfo;
@@ -137,13 +138,11 @@
if (ci instanceof SimulatedRadioControl) {
mSimulatedRadioControl = (SimulatedRadioControl) ci;
}
-
mCM.setPhoneType(Phone.PHONE_TYPE_GSM);
- mIccCard.set(UiccController.getInstance(this).getIccCard());
- mIccRecords = mIccCard.get().getIccRecords();
mCT = new GsmCallTracker(this);
mSST = new GsmServiceStateTracker (this);
mSMS = new GsmSMSDispatcher(this, mSmsStorageMonitor, mSmsUsageMonitor);
+
mDataConnectionTracker = new GsmDataConnectionTracker (this);
if (!unitTestMode) {
mSimPhoneBookIntManager = new SimPhoneBookInterfaceManager(this);
@@ -152,7 +151,6 @@
}
mCM.registerForAvailable(this, EVENT_RADIO_AVAILABLE, null);
- registerForSimRecordEvents();
mCM.registerForOffOrNotAvailable(this, EVENT_RADIO_OFF_OR_NOT_AVAILABLE, null);
mCM.registerForOn(this, EVENT_RADIO_ON, null);
mCM.setOnUSSD(this, EVENT_USSD, null);
@@ -796,7 +794,8 @@
public String getVoiceMailNumber() {
// Read from the SIM. If its null, try reading from the shared preference area.
- String number = mIccRecords.getVoiceMailNumber();
+ IccRecords r = mIccRecords.get();
+ String number = (r != null) ? r.getVoiceMailNumber() : "";
if (TextUtils.isEmpty(number)) {
SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(getContext());
number = sp.getString(VM_NUMBER, null);
@@ -818,8 +817,9 @@
public String getVoiceMailAlphaTag() {
String ret;
+ IccRecords r = mIccRecords.get();
- ret = mIccRecords.getVoiceMailAlphaTag();
+ ret = (r != null) ? r.getVoiceMailAlphaTag() : "";
if (ret == null || ret.length() == 0) {
return mContext.getText(
@@ -852,24 +852,31 @@
}
public String getSubscriberId() {
- return mIccRecords.getIMSI();
+ IccRecords r = mIccRecords.get();
+ return (r != null) ? r.getIMSI() : "";
}
public String getLine1Number() {
- return mIccRecords.getMsisdnNumber();
+ IccRecords r = mIccRecords.get();
+ return (r != null) ? r.getMsisdnNumber() : "";
}
@Override
public String getMsisdn() {
- return mIccRecords.getMsisdnNumber();
+ IccRecords r = mIccRecords.get();
+ return (r != null) ? r.getMsisdnNumber() : "";
}
public String getLine1AlphaTag() {
- return mIccRecords.getMsisdnAlphaTag();
+ IccRecords r = mIccRecords.get();
+ return (r != null) ? r.getMsisdnAlphaTag() : "";
}
public void setLine1Number(String alphaTag, String number, Message onComplete) {
- mIccRecords.setMsisdnNumber(alphaTag, number, onComplete);
+ IccRecords r = mIccRecords.get();
+ if (r != null) {
+ r.setMsisdnNumber(alphaTag, number, onComplete);
+ }
}
public void setVoiceMailNumber(String alphaTag,
@@ -879,7 +886,10 @@
Message resp;
mVmNumber = voiceMailNumber;
resp = obtainMessage(EVENT_SET_VM_NUMBER_DONE, 0, 0, onComplete);
- mIccRecords.setVoiceMailNumber(alphaTag, mVmNumber, resp);
+ IccRecords r = mIccRecords.get();
+ if (r != null) {
+ r.setVoiceMailNumber(alphaTag, mVmNumber, resp);
+ }
}
private boolean isValidCommandInterfaceCFReason (int commandInterfaceCFReason) {
@@ -1247,8 +1257,9 @@
case EVENT_SET_CALL_FORWARD_DONE:
ar = (AsyncResult)msg.obj;
- if (ar.exception == null) {
- mIccRecords.setVoiceCallForwardingFlag(1, msg.arg1 == 1);
+ IccRecords r = mIccRecords.get();
+ if (ar.exception == null && r != null) {
+ r.setVoiceCallForwardingFlag(1, msg.arg1 == 1);
}
onComplete = (Message) ar.userObj;
if (onComplete != null) {
@@ -1321,12 +1332,41 @@
}
}
+ @Override
+ protected void onUpdateIccAvailability() {
+ if (mUiccController == null ) {
+ return;
+ }
+
+ IccCard newIccCard = mUiccController.getIccCard();
+
+ IccCard c = mIccCard.get();
+ if (c != newIccCard) {
+ if (c != null) {
+ if (LOCAL_DEBUG) log("Removing stale icc objects.");
+ if (mIccRecords.get() != null) {
+ unregisterForSimRecordEvents();
+ mSimPhoneBookIntManager.updateIccRecords(null);
+ }
+ mIccRecords.set(null);
+ mIccCard.set(null);
+ }
+ if (newIccCard != null) {
+ if (LOCAL_DEBUG) log("New card found");
+ mIccCard.set(newIccCard);
+ mIccRecords.set(newIccCard.getIccRecords());
+ registerForSimRecordEvents();
+ mSimPhoneBookIntManager.updateIccRecords(mIccRecords.get());
+ }
+ }
+ }
+
private void processIccRecordEvents(int eventCode) {
switch (eventCode) {
- case SIMRecords.EVENT_CFI:
+ case IccRecords.EVENT_CFI:
notifyCallForwardingIndicator();
break;
- case SIMRecords.EVENT_MWI:
+ case IccRecords.EVENT_MWI:
notifyMessageWaitingIndicator();
break;
}
@@ -1338,11 +1378,12 @@
* @return true for success; false otherwise.
*/
boolean updateCurrentCarrierInProvider() {
- if (mIccRecords != null) {
+ IccRecords r = mIccRecords.get();
+ if (r != null) {
try {
Uri uri = Uri.withAppendedPath(Telephony.Carriers.CONTENT_URI, "current");
ContentValues map = new ContentValues();
- map.put(Telephony.Carriers.NUMERIC, mIccRecords.getOperatorNumeric());
+ map.put(Telephony.Carriers.NUMERIC, r.getOperatorNumeric());
mContext.getContentResolver().insert(uri, map);
return true;
} catch (SQLException e) {
@@ -1404,16 +1445,19 @@
}
private void handleCfuQueryResult(CallForwardInfo[] infos) {
- if (infos == null || infos.length == 0) {
- // Assume the default is not active
- // Set unconditional CFF in SIM to false
- mIccRecords.setVoiceCallForwardingFlag(1, false);
- } else {
- for (int i = 0, s = infos.length; i < s; i++) {
- if ((infos[i].serviceClass & SERVICE_CLASS_VOICE) != 0) {
- mIccRecords.setVoiceCallForwardingFlag(1, (infos[i].status == 1));
- // should only have the one
- break;
+ IccRecords r = mIccRecords.get();
+ if (r != null) {
+ if (infos == null || infos.length == 0) {
+ // Assume the default is not active
+ // Set unconditional CFF in SIM to false
+ r.setVoiceCallForwardingFlag(1, false);
+ } else {
+ for (int i = 0, s = infos.length; i < s; i++) {
+ if ((infos[i].serviceClass & SERVICE_CLASS_VOICE) != 0) {
+ r.setVoiceCallForwardingFlag(1, (infos[i].status == 1));
+ // should only have the one
+ break;
+ }
}
}
}
@@ -1472,22 +1516,35 @@
}
public boolean isCspPlmnEnabled() {
- return mIccRecords.isCspPlmnEnabled();
+ IccRecords r = mIccRecords.get();
+ return (r != null) ? r.isCspPlmnEnabled() : false;
}
private void registerForSimRecordEvents() {
- mIccRecords.registerForNetworkSelectionModeAutomatic(
+ IccRecords r = mIccRecords.get();
+ if (r == null) {
+ return;
+ }
+ r.registerForNetworkSelectionModeAutomatic(
this, EVENT_SET_NETWORK_AUTOMATIC, null);
- mIccRecords.registerForNewSms(this, EVENT_NEW_ICC_SMS, null);
- mIccRecords.registerForRecordsEvents(this, EVENT_ICC_RECORD_EVENTS, null);
- mIccRecords.registerForRecordsLoaded(this, EVENT_SIM_RECORDS_LOADED, null);
+ r.registerForNewSms(this, EVENT_NEW_ICC_SMS, null);
+ r.registerForRecordsEvents(this, EVENT_ICC_RECORD_EVENTS, null);
+ r.registerForRecordsLoaded(this, EVENT_SIM_RECORDS_LOADED, null);
}
private void unregisterForSimRecordEvents() {
- mIccRecords.unregisterForNetworkSelectionModeAutomatic(this);
- mIccRecords.unregisterForNewSms(this);
- mIccRecords.unregisterForRecordsEvents(this);
- mIccRecords.unregisterForRecordsLoaded(this);
+ IccRecords r = mIccRecords.get();
+ if (r == null) {
+ return;
+ }
+ r.unregisterForNetworkSelectionModeAutomatic(this);
+ r.unregisterForNewSms(this);
+ r.unregisterForRecordsEvents(this);
+ r.unregisterForRecordsLoaded(this);
+ }
+
+ protected void log(String s) {
+ Log.d(LOG_TAG, "[GSMPhone] " + s);
}
@Override
diff --git a/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java b/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java
index 40ee58c..b44ba0b 100644
--- a/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java
+++ b/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java
@@ -59,6 +59,8 @@
import com.android.internal.telephony.DataConnectionAc;
import com.android.internal.telephony.DataConnectionTracker;
import com.android.internal.telephony.EventLogTags;
+import com.android.internal.telephony.IccCard;
+import com.android.internal.telephony.IccRecords;
import com.android.internal.telephony.Phone;
import com.android.internal.telephony.PhoneBase;
import com.android.internal.telephony.RILConstants;
@@ -178,7 +180,6 @@
p.mCM.registerForAvailable (this, EVENT_RADIO_AVAILABLE, null);
p.mCM.registerForOffOrNotAvailable(this, EVENT_RADIO_OFF_OR_NOT_AVAILABLE, null);
- p.mIccRecords.registerForRecordsLoaded(this, EVENT_RECORDS_LOADED, null);
p.mCM.registerForDataNetworkStateChanged (this, EVENT_DATA_STATE_CHANGED, null);
p.getCallTracker().registerForVoiceCallEnded (this, EVENT_VOICE_CALL_ENDED, null);
p.getCallTracker().registerForVoiceCallStarted (this, EVENT_VOICE_CALL_STARTED, null);
@@ -219,7 +220,8 @@
//Unregister for all events
mPhone.mCM.unregisterForAvailable(this);
mPhone.mCM.unregisterForOffOrNotAvailable(this);
- mPhone.mIccRecords.unregisterForRecordsLoaded(this);
+ IccRecords r = mIccRecords.get();
+ if (r != null) { r.unregisterForRecordsLoaded(this);}
mPhone.mCM.unregisterForDataNetworkStateChanged(this);
mPhone.getCallTracker().unregisterForVoiceCallEnded(this);
mPhone.getCallTracker().unregisterForVoiceCallStarted(this);
@@ -620,10 +622,12 @@
int gprsState = mPhone.getServiceStateTracker().getCurrentDataConnectionState();
boolean desiredPowerState = mPhone.getServiceStateTracker().getDesiredPowerState();
+ IccRecords r = mIccRecords.get();
+ boolean recordsLoaded = (r != null) ? r.getRecordsLoaded() : false;
boolean allowed =
(gprsState == ServiceState.STATE_IN_SERVICE || mAutoAttachOnCreation) &&
- mPhone.mIccRecords.getRecordsLoaded() &&
+ recordsLoaded &&
(mPhone.getState() == Phone.State.IDLE ||
mPhone.getServiceStateTracker().isConcurrentVoiceAndDataAllowed()) &&
internalDataEnabled &&
@@ -635,7 +639,7 @@
if (!((gprsState == ServiceState.STATE_IN_SERVICE) || mAutoAttachOnCreation)) {
reason += " - gprs= " + gprsState;
}
- if (!mPhone.mIccRecords.getRecordsLoaded()) reason += " - SIM not loaded";
+ if (!recordsLoaded) reason += " - SIM not loaded";
if (mPhone.getState() != Phone.State.IDLE &&
!mPhone.getServiceStateTracker().isConcurrentVoiceAndDataAllowed()) {
reason += " - PhoneState= " + mPhone.getState();
@@ -1896,7 +1900,8 @@
log("onRadioAvailable: We're on the simulator; assuming data is connected");
}
- if (mPhone.mIccRecords.getRecordsLoaded()) {
+ IccRecords r = mIccRecords.get();
+ if (r != null && r.getRecordsLoaded()) {
notifyOffApnsOfAvailability(null);
}
@@ -2208,7 +2213,8 @@
*/
private void createAllApnList() {
mAllApns = new ArrayList<ApnSetting>();
- String operator = mPhone.mIccRecords.getOperatorNumeric();
+ IccRecords r = mIccRecords.get();
+ String operator = (r != null) ? r.getOperatorNumeric() : "";
if (operator != null) {
String selection = "numeric = '" + operator + "'";
// query only enabled apn.
@@ -2319,8 +2325,9 @@
}
}
- String operator = mPhone.mIccRecords.getOperatorNumeric();
- int networkType = mPhone.getServiceState().getNetworkType();
+ IccRecords r = mIccRecords.get();
+ String operator = (r != null) ? r.getOperatorNumeric() : "";
+ int radioTech = mPhone.getServiceState().getRadioTechnology();
if (requestedApnType.equals(Phone.APN_TYPE_DEFAULT)) {
if (canSetPreferApn && mPreferredApn != null) {
@@ -2329,7 +2336,7 @@
+ mPreferredApn.numeric + ":" + mPreferredApn);
}
if (mPreferredApn.numeric.equals(operator)) {
- if (mPreferredApn.bearer == 0 || mPreferredApn.bearer == networkType) {
+ if (mPreferredApn.bearer == 0 || mPreferredApn.bearer == radioTech) {
apnList.add(mPreferredApn);
if (DBG) log("buildWaitingApns: X added preferred apnList=" + apnList);
return apnList;
@@ -2348,7 +2355,7 @@
if (mAllApns != null) {
for (ApnSetting apn : mAllApns) {
if (apn.canHandleType(requestedApnType)) {
- if (apn.bearer == 0 || apn.bearer == networkType) {
+ if (apn.bearer == 0 || apn.bearer == radioTech) {
if (DBG) log("apn info : " +apn.toString());
apnList.add(apn);
}
@@ -2556,6 +2563,33 @@
}
@Override
+ protected void onUpdateIcc() {
+ if (mUiccController == null ) {
+ return;
+ }
+
+ IccCard newIccCard = mUiccController.getIccCard();
+ IccRecords newIccRecords = null;
+ if (newIccCard != null) {
+ newIccRecords = newIccCard.getIccRecords();
+ }
+
+ IccRecords r = mIccRecords.get();
+ if (r != newIccRecords) {
+ if (r != null) {
+ log("Removing stale icc objects.");
+ r.unregisterForRecordsLoaded(this);
+ mIccRecords.set(null);
+ }
+ if (newIccCard != null) {
+ log("New card found");
+ mIccRecords.set(newIccRecords);
+ newIccRecords.registerForRecordsLoaded(this, EVENT_RECORDS_LOADED, null);
+ }
+ }
+ }
+
+ @Override
protected void log(String s) {
Log.d(LOG_TAG, "[GsmDCT] "+ s);
}
diff --git a/telephony/java/com/android/internal/telephony/gsm/GsmMmiCode.java b/telephony/java/com/android/internal/telephony/gsm/GsmMmiCode.java
index 9b3d5cd..9e34b6a 100644
--- a/telephony/java/com/android/internal/telephony/gsm/GsmMmiCode.java
+++ b/telephony/java/com/android/internal/telephony/gsm/GsmMmiCode.java
@@ -885,7 +885,10 @@
*/
if ((ar.exception == null) && (msg.arg1 == 1)) {
boolean cffEnabled = (msg.arg2 == 1);
- phone.mIccRecords.setVoiceCallForwardingFlag(1, cffEnabled);
+ IccRecords r = phone.mIccRecords.get();
+ if (r != null) {
+ r.setVoiceCallForwardingFlag(1, cffEnabled);
+ }
}
onSetComplete(ar);
@@ -1203,7 +1206,10 @@
(info.serviceClass & serviceClassMask)
== CommandsInterface.SERVICE_CLASS_VOICE) {
boolean cffEnabled = (info.status == 1);
- phone.mIccRecords.setVoiceCallForwardingFlag(1, cffEnabled);
+ IccRecords r = phone.mIccRecords.get();
+ if (r != null) {
+ r.setVoiceCallForwardingFlag(1, cffEnabled);
+ }
}
return TextUtils.replace(template, sources, destinations);
@@ -1228,7 +1234,10 @@
sb.append(context.getText(com.android.internal.R.string.serviceDisabled));
// Set unconditional CFF in SIM to false
- phone.mIccRecords.setVoiceCallForwardingFlag(1, false);
+ IccRecords r = phone.mIccRecords.get();
+ if (r != null) {
+ r.setVoiceCallForwardingFlag(1, false);
+ }
} else {
SpannableStringBuilder tb = new SpannableStringBuilder();
diff --git a/telephony/java/com/android/internal/telephony/gsm/GsmServiceStateTracker.java b/telephony/java/com/android/internal/telephony/gsm/GsmServiceStateTracker.java
index c0acf5b..7c03d03 100644
--- a/telephony/java/com/android/internal/telephony/gsm/GsmServiceStateTracker.java
+++ b/telephony/java/com/android/internal/telephony/gsm/GsmServiceStateTracker.java
@@ -124,12 +124,6 @@
long mSavedTime;
long mSavedAtTime;
- /**
- * We can't register for SIM_RECORDS_LOADED immediately because the
- * SIMRecords object may not be instantiated yet.
- */
- private boolean mNeedToRegForSimLoaded;
-
/** Started the recheck process after finding gprs should registered but not. */
private boolean mStartedGprsRegCheck = false;
@@ -192,10 +186,9 @@
};
public GsmServiceStateTracker(GSMPhone phone) {
- super();
+ super(phone, phone.mCM);
this.phone = phone;
- cm = phone.mCM;
ss = new ServiceState();
newSS = new ServiceState();
cellLoc = new GsmCellLocation();
@@ -213,7 +206,6 @@
cm.setOnNITZTime(this, EVENT_NITZ_TIME, null);
cm.setOnSignalStrengthUpdate(this, EVENT_SIGNAL_STRENGTH_UPDATE, null);
cm.setOnRestrictedStateChanged(this, EVENT_RESTRICTED_STATE_CHANGED, null);
- phone.getIccCard().registerForReady(this, EVENT_SIM_READY, null);
// system setting property AIRPLANE_MODE_ON is set in Settings.
int airplaneMode = Settings.System.getInt(
@@ -230,7 +222,6 @@
mAutoTimeZoneObserver);
setSignalStrengthDefaultValues();
- mNeedToRegForSimLoaded = true;
// Monitor locale change
IntentFilter filter = new IntentFilter();
@@ -242,12 +233,13 @@
}
public void dispose() {
+ checkCorrectThread();
// Unregister for all events.
cm.unregisterForAvailable(this);
cm.unregisterForRadioStateChanged(this);
cm.unregisterForVoiceNetworkStateChanged(this);
- phone.getIccCard().unregisterForReady(this);
- phone.mIccRecords.unregisterForRecordsLoaded(this);
+ if (mIccCard != null) {mIccCard.unregisterForReady(this);}
+ if (mIccRecords != null) {mIccRecords.unregisterForRecordsLoaded(this);}
cm.unSetOnSignalStrengthUpdate(this);
cm.unSetOnRestrictedStateChanged(this);
cm.unSetOnNITZTime(this);
@@ -285,15 +277,6 @@
// Set the network type, in case the radio does not restore it.
cm.setCurrentPreferredNetworkType();
- // The SIM is now ready i.e if it was locked
- // it has been unlocked. At this stage, the radio is already
- // powered on.
- if (mNeedToRegForSimLoaded) {
- phone.mIccRecords.registerForRecordsLoaded(this,
- EVENT_SIM_RECORDS_LOADED, null);
- mNeedToRegForSimLoaded = false;
- }
-
boolean skipRestoringSelection = phone.getContext().getResources().getBoolean(
com.android.internal.R.bool.skip_restoring_network_selection);
@@ -495,8 +478,11 @@
}
protected void updateSpnDisplay() {
- int rule = phone.mIccRecords.getDisplayRule(ss.getOperatorNumeric());
- String spn = phone.mIccRecords.getServiceProviderName();
+ if (mIccRecords == null) {
+ return;
+ }
+ int rule = mIccRecords.getDisplayRule(ss.getOperatorNumeric());
+ String spn = mIccRecords.getServiceProviderName();
String plmn = ss.getOperatorAlphaLong();
// For emergency calls only, pass the EmergencyCallsOnly string via EXTRA_PLMN
@@ -1145,7 +1131,7 @@
((state & RILConstants.RIL_RESTRICTED_STATE_CS_EMERGENCY) != 0) ||
((state & RILConstants.RIL_RESTRICTED_STATE_CS_ALL) != 0) );
//ignore the normal call and data restricted state before SIM READY
- if (phone.getIccCard().getState() == IccCard.State.READY) {
+ if (mIccCard.getState() == IccCard.State.READY) {
newRs.setCsNormalRestricted(
((state & RILConstants.RIL_RESTRICTED_STATE_CS_NORMAL) != 0) ||
((state & RILConstants.RIL_RESTRICTED_STATE_CS_ALL) != 0) );
@@ -1672,6 +1658,35 @@
}
@Override
+ protected void onUpdateIccAvailability() {
+ if (mUiccController == null ) {
+ return;
+ }
+
+ IccCard newIccCard = mUiccController.getIccCard();
+
+ if (mIccCard != newIccCard) {
+ if (mIccCard != null) {
+ log("Removing stale icc objects.");
+ mIccCard.unregisterForReady(this);
+ if (mIccRecords != null) {
+ mIccRecords.unregisterForRecordsLoaded(this);
+ }
+ mIccRecords = null;
+ mIccCard = null;
+ }
+ if (newIccCard != null) {
+ log("New card found");
+ mIccCard = newIccCard;
+ mIccRecords = mIccCard.getIccRecords();
+ mIccCard.registerForReady(this, EVENT_SIM_READY, null);
+ if (mIccRecords != null) {
+ mIccRecords.registerForRecordsLoaded(this, EVENT_SIM_RECORDS_LOADED, null);
+ }
+ }
+ }
+ }
+ @Override
protected void log(String s) {
Log.d(LOG_TAG, "[GsmSST] " + s);
}
@@ -1711,7 +1726,6 @@
pw.println(" mSavedTimeZone=" + mSavedTimeZone);
pw.println(" mSavedTime=" + mSavedTime);
pw.println(" mSavedAtTime=" + mSavedAtTime);
- pw.println(" mNeedToRegForSimLoaded=" + mNeedToRegForSimLoaded);
pw.println(" mStartedGprsRegCheck=" + mStartedGprsRegCheck);
pw.println(" mReportedGprsNoReg=" + mReportedGprsNoReg);
pw.println(" mNotification=" + mNotification);
diff --git a/telephony/java/com/android/internal/telephony/gsm/SIMRecords.java b/telephony/java/com/android/internal/telephony/gsm/SIMRecords.java
index 80988fd..3077995 100755
--- a/telephony/java/com/android/internal/telephony/gsm/SIMRecords.java
+++ b/telephony/java/com/android/internal/telephony/gsm/SIMRecords.java
@@ -521,7 +521,7 @@
boolean isRecordLoadResponse = false;
- if (mDestroyed) {
+ if (mDestroyed.get()) {
loge("Received message " + msg + "[" + msg.what + "] " +
" while being destroyed. Ignoring.");
return;
@@ -1299,12 +1299,6 @@
@Override
public void onReady() {
- /* broadcast intent SIM_READY here so that we can make sure
- READY is sent before IMSI ready
- */
- mParentCard.broadcastIccStateChangedIntent(
- IccCard.INTENT_VALUE_ICC_READY, null);
-
fetchSimRecords();
}
diff --git a/telephony/java/com/android/internal/telephony/gsm/SimPhoneBookInterfaceManager.java b/telephony/java/com/android/internal/telephony/gsm/SimPhoneBookInterfaceManager.java
index 35ba0d1..37f9a4f 100644
--- a/telephony/java/com/android/internal/telephony/gsm/SimPhoneBookInterfaceManager.java
+++ b/telephony/java/com/android/internal/telephony/gsm/SimPhoneBookInterfaceManager.java
@@ -21,6 +21,7 @@
import android.os.Message;
import android.util.Log;
+import com.android.internal.telephony.IccFileHandler;
import com.android.internal.telephony.IccPhoneBookInterfaceManager;
/**
@@ -34,7 +35,6 @@
public SimPhoneBookInterfaceManager(GSMPhone phone) {
super(phone);
- adnCache = phone.mIccRecords.getAdnCache();
//NOTE service "simphonebook" added by IccSmsInterfaceManagerProxy
}
@@ -61,8 +61,11 @@
AtomicBoolean status = new AtomicBoolean(false);
Message response = mBaseHandler.obtainMessage(EVENT_GET_SIZE_DONE, status);
- phone.getIccFileHandler().getEFLinearRecordSize(efid, response);
- waitForResult(status);
+ IccFileHandler fh = phone.getIccFileHandler();
+ if (fh != null) {
+ fh.getEFLinearRecordSize(efid, response);
+ waitForResult(status);
+ }
}
return recordSize;
diff --git a/telephony/java/com/android/internal/telephony/sip/SipPhoneBase.java b/telephony/java/com/android/internal/telephony/sip/SipPhoneBase.java
index 5c4b446..0243522 100755
--- a/telephony/java/com/android/internal/telephony/sip/SipPhoneBase.java
+++ b/telephony/java/com/android/internal/telephony/sip/SipPhoneBase.java
@@ -461,4 +461,8 @@
notifyPhoneStateChanged();
}
}
+
+ @Override
+ protected void onUpdateIccAvailability() {
+ }
}
diff --git a/telephony/java/com/android/internal/telephony/uicc/UiccController.java b/telephony/java/com/android/internal/telephony/uicc/UiccController.java
index 5961efd..4e12d6d 100644
--- a/telephony/java/com/android/internal/telephony/uicc/UiccController.java
+++ b/telephony/java/com/android/internal/telephony/uicc/UiccController.java
@@ -16,78 +16,150 @@
package com.android.internal.telephony.uicc;
+import com.android.internal.telephony.CommandsInterface;
import com.android.internal.telephony.IccCard;
+import com.android.internal.telephony.IccCardStatus;
+import com.android.internal.telephony.IccCardStatus.CardState;
import com.android.internal.telephony.PhoneBase;
-import com.android.internal.telephony.cdma.CDMALTEPhone;
-import com.android.internal.telephony.cdma.CDMAPhone;
-import com.android.internal.telephony.gsm.GSMPhone;
+import android.os.AsyncResult;
+import android.os.Handler;
+import android.os.Message;
+import android.os.Registrant;
+import android.os.RegistrantList;
import android.util.Log;
/* This class is responsible for keeping all knowledge about
* ICCs in the system. It is also used as API to get appropriate
* applications to pass them to phone and service trackers.
*/
-public class UiccController {
+public class UiccController extends Handler {
private static final boolean DBG = true;
private static final String LOG_TAG = "RIL_UiccController";
+ private static final int EVENT_ICC_STATUS_CHANGED = 1;
+ private static final int EVENT_GET_ICC_STATUS_DONE = 2;
+
private static UiccController mInstance;
private PhoneBase mCurrentPhone;
- private boolean mIsCurrentCard3gpp;
+ private CommandsInterface mCi;
private IccCard mIccCard;
+ private boolean mRegisteredWithCi = false;
+
+ private RegistrantList mIccChangedRegistrants = new RegistrantList();
public static synchronized UiccController getInstance(PhoneBase phone) {
if (mInstance == null) {
mInstance = new UiccController(phone);
- } else {
+ } else if (phone != null) {
mInstance.setNewPhone(phone);
}
return mInstance;
}
- public IccCard getIccCard() {
+ // This method is not synchronized as getInstance(PhoneBase) is.
+ public static UiccController getInstance() {
+ return getInstance(null);
+ }
+
+ public synchronized IccCard getIccCard() {
return mIccCard;
}
+ //Notifies when card status changes
+ public void registerForIccChanged(Handler h, int what, Object obj) {
+ Registrant r = new Registrant (h, what, obj);
+ mIccChangedRegistrants.add(r);
+ //Notify registrant right after registering, so that it will get the latest ICC status,
+ //otherwise which may not happen until there is an actual change in ICC status.
+ r.notifyRegistrant();
+ }
+ public void unregisterForIccChanged(Handler h) {
+ mIccChangedRegistrants.remove(h);
+ }
+
+ @Override
+ public void handleMessage (Message msg) {
+ switch (msg.what) {
+ case EVENT_ICC_STATUS_CHANGED:
+ if (DBG) log("Received EVENT_ICC_STATUS_CHANGED, calling getIccCardStatus");
+ mCi.getIccCardStatus(obtainMessage(EVENT_GET_ICC_STATUS_DONE));
+ break;
+ case EVENT_GET_ICC_STATUS_DONE:
+ if (DBG) log("Received EVENT_GET_ICC_STATUS_DONE");
+ AsyncResult ar = (AsyncResult)msg.obj;
+ onGetIccCardStatusDone(ar);
+ break;
+ default:
+ Log.e(LOG_TAG, " Unknown Event " + msg.what);
+ }
+ }
+
private UiccController(PhoneBase phone) {
if (DBG) log("Creating UiccController");
setNewPhone(phone);
}
- private void setNewPhone(PhoneBase phone) {
- mCurrentPhone = phone;
- if (phone instanceof GSMPhone) {
- if (DBG) log("New phone is GSMPhone");
- updateCurrentCard(IccCard.CARD_IS_3GPP);
- } else if (phone instanceof CDMALTEPhone){
- if (DBG) log("New phone type is CDMALTEPhone");
- updateCurrentCard(IccCard.CARD_IS_3GPP);
- } else if (phone instanceof CDMAPhone){
- if (DBG) log("New phone type is CDMAPhone");
- updateCurrentCard(IccCard.CARD_IS_NOT_3GPP);
- } else {
- Log.e(LOG_TAG, "Unhandled phone type. Critical error!");
- }
- }
-
- private void updateCurrentCard(boolean isNewCard3gpp) {
- if (mIsCurrentCard3gpp == isNewCard3gpp && mIccCard != null) {
+ private synchronized void onGetIccCardStatusDone(AsyncResult ar) {
+ if (ar.exception != null) {
+ Log.e(LOG_TAG,"Error getting ICC status. "
+ + "RIL_REQUEST_GET_ICC_STATUS should "
+ + "never return an error", ar.exception);
return;
}
- if (mIccCard != null) {
+ IccCardStatus status = (IccCardStatus)ar.result;
+
+ //Update already existing card
+ if (mIccCard != null && status.getCardState() == CardState.CARDSTATE_PRESENT) {
+ mIccCard.update(mCurrentPhone, status);
+ }
+
+ //Dispose of removed card
+ if (mIccCard != null && status.getCardState() != CardState.CARDSTATE_PRESENT) {
mIccCard.dispose();
mIccCard = null;
}
- mIsCurrentCard3gpp = isNewCard3gpp;
- mIccCard = new IccCard(mCurrentPhone, mCurrentPhone.getPhoneName(),
- isNewCard3gpp, DBG);
+ //Create new card
+ if (mIccCard == null && status.getCardState() == CardState.CARDSTATE_PRESENT) {
+ mIccCard = new IccCard(mCurrentPhone, status, mCurrentPhone.getPhoneName(), true);
+ }
+
+ if (DBG) log("Notifying IccChangedRegistrants");
+ mIccChangedRegistrants.notifyRegistrants();
+ }
+
+ private void setNewPhone(PhoneBase phone) {
+ if (phone == null) {
+ throw new RuntimeException("Phone can't be null in UiccController");
+ }
+
+ if (DBG) log("setNewPhone");
+ if (mCurrentPhone != phone) {
+ if (mIccCard != null) {
+ // Refresh card if phone changed
+ // TODO: Remove once card is simplified
+ if (DBG) log("Disposing card since phone object changed");
+ mIccCard.dispose();
+ mIccCard = null;
+ }
+ sendMessage(obtainMessage(EVENT_ICC_STATUS_CHANGED));
+ mCurrentPhone = phone;
+
+ if (!mRegisteredWithCi) {
+ // This needs to be done only once after we have valid phone object
+ mCi = mCurrentPhone.mCM;
+ mCi.registerForIccStatusChanged(this, EVENT_ICC_STATUS_CHANGED, null);
+ // TODO remove this once modem correctly notifies the unsols
+ mCi.registerForOn(this, EVENT_ICC_STATUS_CHANGED, null);
+ mRegisteredWithCi = true;
+ }
+ }
}
private void log(String string) {
Log.d(LOG_TAG, string);
}
-}
\ No newline at end of file
+}
diff --git a/tests/GridLayoutTest/AndroidManifest.xml b/tests/GridLayoutTest/AndroidManifest.xml
index 141e8fa..677220d 100644
--- a/tests/GridLayoutTest/AndroidManifest.xml
+++ b/tests/GridLayoutTest/AndroidManifest.xml
@@ -83,6 +83,13 @@
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
+
+ <activity android:name="LayoutInsetsTest" android:label="LayoutInsetsTest">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
+ </intent-filter>
+ </activity>
</application>
diff --git a/tests/GridLayoutTest/res/drawable/btn_default.xml b/tests/GridLayoutTest/res/drawable/btn_default.xml
new file mode 100644
index 0000000..c6cfda0
--- /dev/null
+++ b/tests/GridLayoutTest/res/drawable/btn_default.xml
@@ -0,0 +1,33 @@
+<?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.
+-->
+
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:state_window_focused="false" android:state_enabled="true"
+ android:drawable="@drawable/my_btn_default_normal" />
+ <item android:state_window_focused="false" android:state_enabled="false"
+ android:drawable="@drawable/my_btn_default_normal" />
+ <item android:state_pressed="true"
+ android:drawable="@drawable/my_btn_default_pressed" />
+ <item android:state_focused="true" android:state_enabled="true"
+ android:drawable="@drawable/my_btn_default_selected" />
+ <item android:state_enabled="true"
+ android:drawable="@drawable/my_btn_default_normal" />
+ <item android:state_focused="true"
+ android:drawable="@drawable/my_btn_default_normal_disable_focused" />
+ <item
+ android:drawable="@drawable/my_btn_default_normal_disable" />
+</selector>
diff --git a/tests/GridLayoutTest/res/drawable/my_btn_default_normal.9.png b/tests/GridLayoutTest/res/drawable/my_btn_default_normal.9.png
new file mode 100644
index 0000000..cd0b7d5
--- /dev/null
+++ b/tests/GridLayoutTest/res/drawable/my_btn_default_normal.9.png
Binary files differ
diff --git a/tests/GridLayoutTest/res/drawable/my_btn_default_normal_disable.9.png b/tests/GridLayoutTest/res/drawable/my_btn_default_normal_disable.9.png
new file mode 100755
index 0000000..f4f01c7
--- /dev/null
+++ b/tests/GridLayoutTest/res/drawable/my_btn_default_normal_disable.9.png
Binary files differ
diff --git a/tests/GridLayoutTest/res/drawable/my_btn_default_normal_disable_focused.9.png b/tests/GridLayoutTest/res/drawable/my_btn_default_normal_disable_focused.9.png
new file mode 100755
index 0000000..5376db2
--- /dev/null
+++ b/tests/GridLayoutTest/res/drawable/my_btn_default_normal_disable_focused.9.png
Binary files differ
diff --git a/tests/GridLayoutTest/res/drawable/my_btn_default_pressed.9.png b/tests/GridLayoutTest/res/drawable/my_btn_default_pressed.9.png
new file mode 100755
index 0000000..4312c27
--- /dev/null
+++ b/tests/GridLayoutTest/res/drawable/my_btn_default_pressed.9.png
Binary files differ
diff --git a/tests/GridLayoutTest/res/drawable/my_btn_default_selected.9.png b/tests/GridLayoutTest/res/drawable/my_btn_default_selected.9.png
new file mode 100755
index 0000000..06b7790
--- /dev/null
+++ b/tests/GridLayoutTest/res/drawable/my_btn_default_selected.9.png
Binary files differ
diff --git a/tests/GridLayoutTest/res/layout/grid7.xml b/tests/GridLayoutTest/res/layout/grid7.xml
index b9e58d7..0e5be0c 100644
--- a/tests/GridLayoutTest/res/layout/grid7.xml
+++ b/tests/GridLayoutTest/res/layout/grid7.xml
@@ -17,7 +17,7 @@
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
- android:columnCount="2"
+
<Space
android:layout_row="0"
android:layout_column="0"
diff --git a/tests/GridLayoutTest/src/com/android/test/layout/LayoutInsetsTest.java b/tests/GridLayoutTest/src/com/android/test/layout/LayoutInsetsTest.java
new file mode 100644
index 0000000..74daccc
--- /dev/null
+++ b/tests/GridLayoutTest/src/com/android/test/layout/LayoutInsetsTest.java
@@ -0,0 +1,59 @@
+package com.android.test.layout;
+
+import android.app.Activity;
+import android.content.Context;
+import android.graphics.Rect;
+import android.graphics.drawable.Drawable;
+import android.os.Build;
+import android.os.Bundle;
+import android.view.View;
+import android.widget.Button;
+import android.widget.EditText;
+import android.widget.GridLayout;
+import android.widget.Space;
+import android.widget.TextView;
+
+import static android.text.InputType.TYPE_CLASS_TEXT;
+import static android.text.InputType.TYPE_TEXT_VARIATION_EMAIL_ADDRESS;
+import static android.text.InputType.TYPE_TEXT_VARIATION_PASSWORD;
+import static android.widget.GridLayout.*;
+import static android.widget.GridLayout.FILL;
+import static android.widget.GridLayout.spec;
+
+public class LayoutInsetsTest extends Activity {
+ public static View create(Context context) {
+ GridLayout p = new GridLayout(context);
+ p.setUseDefaultMargins(true);
+ p.setAlignmentMode(ALIGN_BOUNDS);
+ p.setOrientation(VERTICAL);
+
+ {
+ TextView c = new TextView(context);
+ c.setTextSize(32);
+ c.setText("Email setup");
+ p.addView(c);
+ }
+ {
+ Button c = new Button(context);
+ c.setBackgroundResource(R.drawable.btn_default);
+ c.setText("Manual setup");
+ p.addView(c);
+ c.setOnClickListener(new OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ Button b = (Button) v;
+ b.setEnabled(false);
+ }
+ });
+ }
+
+ return p;
+ }
+
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ //getApplicationInfo().targetSdkVersion = Build.VERSION_CODES.ICE_CREAM_SANDWICH;
+ getApplicationInfo().targetSdkVersion = Build.VERSION_CODES.JELLY_BEAN;
+ setContentView(create(this));
+ }
+}
diff --git a/tests/RenderScriptTests/tests/src/com/android/rs/test/element.rs b/tests/RenderScriptTests/tests/src/com/android/rs/test/element.rs
index 0c42d84..419ce07 100644
--- a/tests/RenderScriptTests/tests/src/com/android/rs/test/element.rs
+++ b/tests/RenderScriptTests/tests/src/com/android/rs/test/element.rs
@@ -101,7 +101,7 @@
_RS_ASSERT(rsElementGetDataKind(complexElem) == RS_KIND_USER);
_RS_ASSERT(rsElementGetDataType(complexElem) == RS_TYPE_NONE);
_RS_ASSERT(rsElementGetVectorSize(complexElem) == 1);
- _RS_ASSERT(rsElementGetSizeBytes(complexElem) == sizeof(*complexStruct));
+ _RS_ASSERT(rsElementGetBytesSize(complexElem) == sizeof(*complexStruct));
char buffer[64];
for (uint32_t i = 0; i < subElemCount; i ++) {
diff --git a/tests/RenderScriptTests/tests/src/com/android/rs/test/program_raster.rs b/tests/RenderScriptTests/tests/src/com/android/rs/test/program_raster.rs
index 11b8c30..3d6b502 100644
--- a/tests/RenderScriptTests/tests/src/com/android/rs/test/program_raster.rs
+++ b/tests/RenderScriptTests/tests/src/com/android/rs/test/program_raster.rs
@@ -7,10 +7,10 @@
static bool test_program_raster_getters() {
bool failed = false;
- _RS_ASSERT(rsgProgramRasterGetPointSpriteEnabled(pointSpriteEnabled) == true);
+ _RS_ASSERT(rsgProgramRasterIsPointSpriteEnabled(pointSpriteEnabled) == true);
_RS_ASSERT(rsgProgramRasterGetCullMode(pointSpriteEnabled) == RS_CULL_BACK);
- _RS_ASSERT(rsgProgramRasterGetPointSpriteEnabled(cullMode) == false);
+ _RS_ASSERT(rsgProgramRasterIsPointSpriteEnabled(cullMode) == false);
_RS_ASSERT(rsgProgramRasterGetCullMode(cullMode) == RS_CULL_FRONT);
if (failed) {
diff --git a/tests/RenderScriptTests/tests/src/com/android/rs/test/program_store.rs b/tests/RenderScriptTests/tests/src/com/android/rs/test/program_store.rs
index 3cd8a20..2ae5636 100644
--- a/tests/RenderScriptTests/tests/src/com/android/rs/test/program_store.rs
+++ b/tests/RenderScriptTests/tests/src/com/android/rs/test/program_store.rs
@@ -15,92 +15,92 @@
bool failed = false;
_RS_ASSERT(rsgProgramStoreGetDepthFunc(depthFunc) == RS_DEPTH_FUNC_GREATER);
- _RS_ASSERT(rsgProgramStoreGetDepthMask(depthFunc) == false);
- _RS_ASSERT(rsgProgramStoreGetColorMaskR(depthFunc) == false);
- _RS_ASSERT(rsgProgramStoreGetColorMaskG(depthFunc) == false);
- _RS_ASSERT(rsgProgramStoreGetColorMaskB(depthFunc) == false);
- _RS_ASSERT(rsgProgramStoreGetColorMaskA(depthFunc) == false);
- _RS_ASSERT(rsgProgramStoreGetDitherEnabled(depthFunc) == false);
+ _RS_ASSERT(rsgProgramStoreIsDepthMaskEnabled(depthFunc) == false);
+ _RS_ASSERT(rsgProgramStoreIsColorMaskRedEnabled(depthFunc) == false);
+ _RS_ASSERT(rsgProgramStoreIsColorMaskGreenEnabled(depthFunc) == false);
+ _RS_ASSERT(rsgProgramStoreIsColorMaskBlueEnabled(depthFunc) == false);
+ _RS_ASSERT(rsgProgramStoreIsColorMaskAlphaEnabled( depthFunc) == false);
+ _RS_ASSERT(rsgProgramStoreIsDitherEnabled(depthFunc) == false);
_RS_ASSERT(rsgProgramStoreGetBlendSrcFunc(depthFunc) == RS_BLEND_SRC_ZERO);
_RS_ASSERT(rsgProgramStoreGetBlendDstFunc(depthFunc) == RS_BLEND_DST_ZERO);
_RS_ASSERT(rsgProgramStoreGetDepthFunc(depthWriteEnable) == RS_DEPTH_FUNC_ALWAYS);
- _RS_ASSERT(rsgProgramStoreGetDepthMask(depthWriteEnable) == true);
- _RS_ASSERT(rsgProgramStoreGetColorMaskR(depthWriteEnable) == false);
- _RS_ASSERT(rsgProgramStoreGetColorMaskG(depthWriteEnable) == false);
- _RS_ASSERT(rsgProgramStoreGetColorMaskB(depthWriteEnable) == false);
- _RS_ASSERT(rsgProgramStoreGetColorMaskA(depthWriteEnable) == false);
- _RS_ASSERT(rsgProgramStoreGetDitherEnabled(depthWriteEnable) == false);
+ _RS_ASSERT(rsgProgramStoreIsDepthMaskEnabled(depthWriteEnable) == true);
+ _RS_ASSERT(rsgProgramStoreIsColorMaskRedEnabled(depthWriteEnable) == false);
+ _RS_ASSERT(rsgProgramStoreIsColorMaskGreenEnabled(depthWriteEnable) == false);
+ _RS_ASSERT(rsgProgramStoreIsColorMaskBlueEnabled(depthWriteEnable) == false);
+ _RS_ASSERT(rsgProgramStoreIsColorMaskAlphaEnabled( depthWriteEnable) == false);
+ _RS_ASSERT(rsgProgramStoreIsDitherEnabled(depthWriteEnable) == false);
_RS_ASSERT(rsgProgramStoreGetBlendSrcFunc(depthWriteEnable) == RS_BLEND_SRC_ZERO);
_RS_ASSERT(rsgProgramStoreGetBlendDstFunc(depthWriteEnable) == RS_BLEND_DST_ZERO);
_RS_ASSERT(rsgProgramStoreGetDepthFunc(colorRWriteEnable) == RS_DEPTH_FUNC_ALWAYS);
- _RS_ASSERT(rsgProgramStoreGetDepthMask(colorRWriteEnable) == false);
- _RS_ASSERT(rsgProgramStoreGetColorMaskR(colorRWriteEnable) == true);
- _RS_ASSERT(rsgProgramStoreGetColorMaskG(colorRWriteEnable) == false);
- _RS_ASSERT(rsgProgramStoreGetColorMaskB(colorRWriteEnable) == false);
- _RS_ASSERT(rsgProgramStoreGetColorMaskA(colorRWriteEnable) == false);
- _RS_ASSERT(rsgProgramStoreGetDitherEnabled(colorRWriteEnable) == false);
+ _RS_ASSERT(rsgProgramStoreIsDepthMaskEnabled(colorRWriteEnable) == false);
+ _RS_ASSERT(rsgProgramStoreIsColorMaskRedEnabled(colorRWriteEnable) == true);
+ _RS_ASSERT(rsgProgramStoreIsColorMaskGreenEnabled(colorRWriteEnable) == false);
+ _RS_ASSERT(rsgProgramStoreIsColorMaskBlueEnabled(colorRWriteEnable) == false);
+ _RS_ASSERT(rsgProgramStoreIsColorMaskAlphaEnabled( colorRWriteEnable) == false);
+ _RS_ASSERT(rsgProgramStoreIsDitherEnabled(colorRWriteEnable) == false);
_RS_ASSERT(rsgProgramStoreGetBlendSrcFunc(colorRWriteEnable) == RS_BLEND_SRC_ZERO);
_RS_ASSERT(rsgProgramStoreGetBlendDstFunc(colorRWriteEnable) == RS_BLEND_DST_ZERO);
_RS_ASSERT(rsgProgramStoreGetDepthFunc(colorGWriteEnable) == RS_DEPTH_FUNC_ALWAYS);
- _RS_ASSERT(rsgProgramStoreGetDepthMask(colorGWriteEnable) == false);
- _RS_ASSERT(rsgProgramStoreGetColorMaskR(colorGWriteEnable) == false);
- _RS_ASSERT(rsgProgramStoreGetColorMaskG(colorGWriteEnable) == true);
- _RS_ASSERT(rsgProgramStoreGetColorMaskB(colorGWriteEnable) == false);
- _RS_ASSERT(rsgProgramStoreGetColorMaskA(colorGWriteEnable) == false);
- _RS_ASSERT(rsgProgramStoreGetDitherEnabled(colorGWriteEnable) == false);
+ _RS_ASSERT(rsgProgramStoreIsDepthMaskEnabled(colorGWriteEnable) == false);
+ _RS_ASSERT(rsgProgramStoreIsColorMaskRedEnabled(colorGWriteEnable) == false);
+ _RS_ASSERT(rsgProgramStoreIsColorMaskGreenEnabled(colorGWriteEnable) == true);
+ _RS_ASSERT(rsgProgramStoreIsColorMaskBlueEnabled(colorGWriteEnable) == false);
+ _RS_ASSERT(rsgProgramStoreIsColorMaskAlphaEnabled( colorGWriteEnable) == false);
+ _RS_ASSERT(rsgProgramStoreIsDitherEnabled(colorGWriteEnable) == false);
_RS_ASSERT(rsgProgramStoreGetBlendSrcFunc(colorGWriteEnable) == RS_BLEND_SRC_ZERO);
_RS_ASSERT(rsgProgramStoreGetBlendDstFunc(colorGWriteEnable) == RS_BLEND_DST_ZERO);
_RS_ASSERT(rsgProgramStoreGetDepthFunc(colorBWriteEnable) == RS_DEPTH_FUNC_ALWAYS);
- _RS_ASSERT(rsgProgramStoreGetDepthMask(colorBWriteEnable) == false);
- _RS_ASSERT(rsgProgramStoreGetColorMaskR(colorBWriteEnable) == false);
- _RS_ASSERT(rsgProgramStoreGetColorMaskG(colorBWriteEnable) == false);
- _RS_ASSERT(rsgProgramStoreGetColorMaskB(colorBWriteEnable) == true);
- _RS_ASSERT(rsgProgramStoreGetColorMaskA(colorBWriteEnable) == false);
- _RS_ASSERT(rsgProgramStoreGetDitherEnabled(colorBWriteEnable) == false);
+ _RS_ASSERT(rsgProgramStoreIsDepthMaskEnabled(colorBWriteEnable) == false);
+ _RS_ASSERT(rsgProgramStoreIsColorMaskRedEnabled(colorBWriteEnable) == false);
+ _RS_ASSERT(rsgProgramStoreIsColorMaskGreenEnabled(colorBWriteEnable) == false);
+ _RS_ASSERT(rsgProgramStoreIsColorMaskBlueEnabled(colorBWriteEnable) == true);
+ _RS_ASSERT(rsgProgramStoreIsColorMaskAlphaEnabled( colorBWriteEnable) == false);
+ _RS_ASSERT(rsgProgramStoreIsDitherEnabled(colorBWriteEnable) == false);
_RS_ASSERT(rsgProgramStoreGetBlendSrcFunc(colorBWriteEnable) == RS_BLEND_SRC_ZERO);
_RS_ASSERT(rsgProgramStoreGetBlendDstFunc(colorBWriteEnable) == RS_BLEND_DST_ZERO);
_RS_ASSERT(rsgProgramStoreGetDepthFunc(colorAWriteEnable) == RS_DEPTH_FUNC_ALWAYS);
- _RS_ASSERT(rsgProgramStoreGetDepthMask(colorAWriteEnable) == false);
- _RS_ASSERT(rsgProgramStoreGetColorMaskR(colorAWriteEnable) == false);
- _RS_ASSERT(rsgProgramStoreGetColorMaskG(colorAWriteEnable) == false);
- _RS_ASSERT(rsgProgramStoreGetColorMaskB(colorAWriteEnable) == false);
- _RS_ASSERT(rsgProgramStoreGetColorMaskA(colorAWriteEnable) == true);
- _RS_ASSERT(rsgProgramStoreGetDitherEnabled(colorAWriteEnable) == false);
+ _RS_ASSERT(rsgProgramStoreIsDepthMaskEnabled(colorAWriteEnable) == false);
+ _RS_ASSERT(rsgProgramStoreIsColorMaskRedEnabled(colorAWriteEnable) == false);
+ _RS_ASSERT(rsgProgramStoreIsColorMaskGreenEnabled(colorAWriteEnable) == false);
+ _RS_ASSERT(rsgProgramStoreIsColorMaskBlueEnabled(colorAWriteEnable) == false);
+ _RS_ASSERT(rsgProgramStoreIsColorMaskAlphaEnabled( colorAWriteEnable) == true);
+ _RS_ASSERT(rsgProgramStoreIsDitherEnabled(colorAWriteEnable) == false);
_RS_ASSERT(rsgProgramStoreGetBlendSrcFunc(colorAWriteEnable) == RS_BLEND_SRC_ZERO);
_RS_ASSERT(rsgProgramStoreGetBlendDstFunc(colorAWriteEnable) == RS_BLEND_DST_ZERO);
_RS_ASSERT(rsgProgramStoreGetDepthFunc(ditherEnable) == RS_DEPTH_FUNC_ALWAYS);
- _RS_ASSERT(rsgProgramStoreGetDepthMask(ditherEnable) == false);
- _RS_ASSERT(rsgProgramStoreGetColorMaskR(ditherEnable) == false);
- _RS_ASSERT(rsgProgramStoreGetColorMaskG(ditherEnable) == false);
- _RS_ASSERT(rsgProgramStoreGetColorMaskB(ditherEnable) == false);
- _RS_ASSERT(rsgProgramStoreGetColorMaskA(ditherEnable) == false);
- _RS_ASSERT(rsgProgramStoreGetDitherEnabled(ditherEnable) == true);
+ _RS_ASSERT(rsgProgramStoreIsDepthMaskEnabled(ditherEnable) == false);
+ _RS_ASSERT(rsgProgramStoreIsColorMaskRedEnabled(ditherEnable) == false);
+ _RS_ASSERT(rsgProgramStoreIsColorMaskGreenEnabled(ditherEnable) == false);
+ _RS_ASSERT(rsgProgramStoreIsColorMaskBlueEnabled(ditherEnable) == false);
+ _RS_ASSERT(rsgProgramStoreIsColorMaskAlphaEnabled( ditherEnable) == false);
+ _RS_ASSERT(rsgProgramStoreIsDitherEnabled(ditherEnable) == true);
_RS_ASSERT(rsgProgramStoreGetBlendSrcFunc(ditherEnable) == RS_BLEND_SRC_ZERO);
_RS_ASSERT(rsgProgramStoreGetBlendDstFunc(ditherEnable) == RS_BLEND_DST_ZERO);
_RS_ASSERT(rsgProgramStoreGetDepthFunc(blendSrc) == RS_DEPTH_FUNC_ALWAYS);
- _RS_ASSERT(rsgProgramStoreGetDepthMask(blendSrc) == false);
- _RS_ASSERT(rsgProgramStoreGetColorMaskR(blendSrc) == false);
- _RS_ASSERT(rsgProgramStoreGetColorMaskG(blendSrc) == false);
- _RS_ASSERT(rsgProgramStoreGetColorMaskB(blendSrc) == false);
- _RS_ASSERT(rsgProgramStoreGetColorMaskA(blendSrc) == false);
- _RS_ASSERT(rsgProgramStoreGetDitherEnabled(blendSrc) == false);
+ _RS_ASSERT(rsgProgramStoreIsDepthMaskEnabled(blendSrc) == false);
+ _RS_ASSERT(rsgProgramStoreIsColorMaskRedEnabled(blendSrc) == false);
+ _RS_ASSERT(rsgProgramStoreIsColorMaskGreenEnabled(blendSrc) == false);
+ _RS_ASSERT(rsgProgramStoreIsColorMaskBlueEnabled(blendSrc) == false);
+ _RS_ASSERT(rsgProgramStoreIsColorMaskAlphaEnabled( blendSrc) == false);
+ _RS_ASSERT(rsgProgramStoreIsDitherEnabled(blendSrc) == false);
_RS_ASSERT(rsgProgramStoreGetBlendSrcFunc(blendSrc) == RS_BLEND_SRC_DST_COLOR);
_RS_ASSERT(rsgProgramStoreGetBlendDstFunc(blendSrc) == RS_BLEND_DST_ZERO);
_RS_ASSERT(rsgProgramStoreGetDepthFunc(blendDst) == RS_DEPTH_FUNC_ALWAYS);
- _RS_ASSERT(rsgProgramStoreGetDepthMask(blendDst) == false);
- _RS_ASSERT(rsgProgramStoreGetColorMaskR(blendDst) == false);
- _RS_ASSERT(rsgProgramStoreGetColorMaskG(blendDst) == false);
- _RS_ASSERT(rsgProgramStoreGetColorMaskB(blendDst) == false);
- _RS_ASSERT(rsgProgramStoreGetColorMaskA(blendDst) == false);
- _RS_ASSERT(rsgProgramStoreGetDitherEnabled(blendDst) == false);
+ _RS_ASSERT(rsgProgramStoreIsDepthMaskEnabled(blendDst) == false);
+ _RS_ASSERT(rsgProgramStoreIsColorMaskRedEnabled(blendDst) == false);
+ _RS_ASSERT(rsgProgramStoreIsColorMaskGreenEnabled(blendDst) == false);
+ _RS_ASSERT(rsgProgramStoreIsColorMaskBlueEnabled(blendDst) == false);
+ _RS_ASSERT(rsgProgramStoreIsColorMaskAlphaEnabled( blendDst) == false);
+ _RS_ASSERT(rsgProgramStoreIsDitherEnabled(blendDst) == false);
_RS_ASSERT(rsgProgramStoreGetBlendSrcFunc(blendDst) == RS_BLEND_SRC_ZERO);
_RS_ASSERT(rsgProgramStoreGetBlendDstFunc(blendDst) == RS_BLEND_DST_DST_ALPHA);
diff --git a/tests/SmokeTest/Android.mk b/tests/SmokeTest/Android.mk
index 0adfd4c..591a84e 100644
--- a/tests/SmokeTest/Android.mk
+++ b/tests/SmokeTest/Android.mk
@@ -6,11 +6,11 @@
# This builds "SmokeTestApp"
LOCAL_SRC_FILES := $(call all-java-files-under, src)
-LOCAL_JAVA_LIBRARIES := android.test.runner
-
LOCAL_PACKAGE_NAME := SmokeTestApp
+LOCAL_SDK_VERSION := 8
+
include $(BUILD_PACKAGE)
# This builds "SmokeTest"
-include $(call all-makefiles-under,$(LOCAL_PATH))
\ No newline at end of file
+include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/tests/SmokeTest/tests/Android.mk b/tests/SmokeTest/tests/Android.mk
index 86bf23d..18e682e 100644
--- a/tests/SmokeTest/tests/Android.mk
+++ b/tests/SmokeTest/tests/Android.mk
@@ -4,8 +4,6 @@
# We only want this apk build for tests.
LOCAL_MODULE_TAGS := tests
-LOCAL_JAVA_LIBRARIES := android.test.runner
-
# Include all test java files.
LOCAL_SRC_FILES := $(call all-java-files-under, src)
@@ -17,5 +15,7 @@
LOCAL_INSTRUMENTATION_FOR := SmokeTestApp
+LOCAL_SDK_VERSION := 8
+
include $(BUILD_PACKAGE)
diff --git a/tests/TileBenchmark/AndroidManifest.xml b/tests/TileBenchmark/AndroidManifest.xml
index f125c70..c569ff4 100644
--- a/tests/TileBenchmark/AndroidManifest.xml
+++ b/tests/TileBenchmark/AndroidManifest.xml
@@ -3,6 +3,7 @@
android:versionCode="1"
android:versionName="1.0" package="com.test.tilebenchmark">
<uses-permission android:name="android.permission.INTERNET"/>
+ <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<application android:icon="@drawable/icon"
android:label="@string/app_name"
android:hardwareAccelerated="true">
diff --git a/tools/aapt/Command.cpp b/tools/aapt/Command.cpp
index cbd591f..a4473c8 100644
--- a/tools/aapt/Command.cpp
+++ b/tools/aapt/Command.cpp
@@ -1192,10 +1192,14 @@
if (targetSdk < 4) {
if (!hasWriteExternalStoragePermission) {
printf("uses-permission:'android.permission.WRITE_EXTERNAL_STORAGE'\n");
+ printf("uses-implied-permission:'android.permission.WRITE_EXTERNAL_STORAGE'," \
+ "'targetSdkVersion < 4'\n");
hasWriteExternalStoragePermission = true;
}
if (!hasReadPhoneStatePermission) {
printf("uses-permission:'android.permission.READ_PHONE_STATE'\n");
+ printf("uses-implied-permission:'android.permission.READ_PHONE_STATE'," \
+ "'targetSdkVersion < 4'\n");
}
}
@@ -1203,15 +1207,21 @@
// force them to always take READ_EXTERNAL_STORAGE as well.
if (!hasReadExternalStoragePermission && hasWriteExternalStoragePermission) {
printf("uses-permission:'android.permission.READ_EXTERNAL_STORAGE'\n");
+ printf("uses-implied-permission:'android.permission.READ_EXTERNAL_STORAGE'," \
+ "'requested WRITE_EXTERNAL_STORAGE'\n");
}
// Pre-JellyBean call log permission compatibility.
if (targetSdk < 16) {
if (!hasReadCallLogPermission && hasReadContactsPermission) {
printf("uses-permission:'android.permission.READ_CALL_LOG'\n");
+ printf("uses-implied-permission:'android.permission.READ_CALL_LOG'," \
+ "'targetSdkVersion < 16 and requested READ_CONTACTS'\n");
}
if (!hasWriteCallLogPermission && hasWriteContactsPermission) {
printf("uses-permission:'android.permission.WRITE_CALL_LOG'\n");
+ printf("uses-implied-permission:'android.permission.WRITE_CALL_LOG'," \
+ "'targetSdkVersion < 16 and requested WRITE_CONTACTS'\n");
}
}
@@ -1223,10 +1233,18 @@
*/
// Camera-related back-compatibility logic
if (!specCameraFeature) {
- if (reqCameraFlashFeature || reqCameraAutofocusFeature) {
+ if (reqCameraFlashFeature) {
// if app requested a sub-feature (autofocus or flash) and didn't
// request the base camera feature, we infer that it meant to
printf("uses-feature:'android.hardware.camera'\n");
+ printf("uses-implied-feature:'android.hardware.camera'," \
+ "'requested android.hardware.camera.flash feature'\n");
+ } else if (reqCameraAutofocusFeature) {
+ // if app requested a sub-feature (autofocus or flash) and didn't
+ // request the base camera feature, we infer that it meant to
+ printf("uses-feature:'android.hardware.camera'\n");
+ printf("uses-implied-feature:'android.hardware.camera'," \
+ "'requested android.hardware.camera.autofocus feature'\n");
} else if (hasCameraPermission) {
// if app wants to use camera but didn't request the feature, we infer
// that it meant to, and further that it wants autofocus
@@ -1234,6 +1252,8 @@
printf("uses-feature:'android.hardware.camera'\n");
if (!specCameraAutofocusFeature) {
printf("uses-feature:'android.hardware.camera.autofocus'\n");
+ printf("uses-implied-feature:'android.hardware.camera.autofocus'," \
+ "'requested android.permission.CAMERA permission'\n");
}
}
}
@@ -1245,16 +1265,22 @@
// if app either takes a location-related permission or requests one of the
// sub-features, we infer that it also meant to request the base location feature
printf("uses-feature:'android.hardware.location'\n");
+ printf("uses-implied-feature:'android.hardware.location'," \
+ "'requested a location access permission'\n");
}
if (!specGpsFeature && hasGpsPermission) {
// if app takes GPS (FINE location) perm but does not request the GPS
// feature, we infer that it meant to
printf("uses-feature:'android.hardware.location.gps'\n");
+ printf("uses-implied-feature:'android.hardware.location.gps'," \
+ "'requested android.permission.ACCESS_FINE_LOCATION permission'\n");
}
if (!specNetworkLocFeature && hasCoarseLocPermission) {
// if app takes Network location (COARSE location) perm but does not request the
// network location feature, we infer that it meant to
printf("uses-feature:'android.hardware.location.network'\n");
+ printf("uses-implied-feature:'android.hardware.location.network'," \
+ "'requested android.permission.ACCESS_COURSE_LOCATION permission'\n");
}
// Bluetooth-related compatibility logic
@@ -1262,6 +1288,9 @@
// if app takes a Bluetooth permission but does not request the Bluetooth
// feature, we infer that it meant to
printf("uses-feature:'android.hardware.bluetooth'\n");
+ printf("uses-implied-feature:'android.hardware.bluetooth'," \
+ "'requested android.permission.BLUETOOTH or android.permission.BLUETOOTH_ADMIN " \
+ "permission and targetSdkVersion > 4'\n");
}
// Microphone-related compatibility logic
@@ -1269,6 +1298,8 @@
// if app takes the record-audio permission but does not request the microphone
// feature, we infer that it meant to
printf("uses-feature:'android.hardware.microphone'\n");
+ printf("uses-implied-feature:'android.hardware.microphone'," \
+ "'requested android.permission.RECORD_AUDIO permission'\n");
}
// WiFi-related compatibility logic
@@ -1276,6 +1307,10 @@
// if app takes one of the WiFi permissions but does not request the WiFi
// feature, we infer that it meant to
printf("uses-feature:'android.hardware.wifi'\n");
+ printf("uses-implied-feature:'android.hardware.wifi'," \
+ "'requested android.permission.ACCESS_WIFI_STATE, " \
+ "android.permission.CHANGE_WIFI_STATE, or " \
+ "android.permission.CHANGE_WIFI_MULTICAST_STATE permission'\n");
}
// Telephony-related compatibility logic
@@ -1283,6 +1318,8 @@
// if app takes one of the telephony permissions or requests a sub-feature but
// does not request the base telephony feature, we infer that it meant to
printf("uses-feature:'android.hardware.telephony'\n");
+ printf("uses-implied-feature:'android.hardware.telephony'," \
+ "'requested a telephony-related permission or feature'\n");
}
// Touchscreen-related back-compatibility logic
@@ -1292,11 +1329,15 @@
// Note that specTouchscreenFeature is true if the tag is present, regardless
// of whether its value is true or false, so this is safe
printf("uses-feature:'android.hardware.touchscreen'\n");
+ printf("uses-implied-feature:'android.hardware.touchscreen'," \
+ "'assumed you require a touch screen unless explicitly made optional'\n");
}
if (!specMultitouchFeature && reqDistinctMultitouchFeature) {
// if app takes one of the telephony permissions or requests a sub-feature but
// does not request the base telephony feature, we infer that it meant to
printf("uses-feature:'android.hardware.touchscreen.multitouch'\n");
+ printf("uses-implied-feature:'android.hardware.touchscreen.multitouch'," \
+ "'requested android.hardware.touchscreen.multitouch.distinct feature'\n");
}
// Landscape/portrait-related compatibility logic
@@ -1306,9 +1347,13 @@
// orientation is required.
if (reqScreenLandscapeFeature) {
printf("uses-feature:'android.hardware.screen.landscape'\n");
+ printf("uses-implied-feature:'android.hardware.screen.landscape'," \
+ "'one or more activities have specified a landscape orientation'\n");
}
if (reqScreenPortraitFeature) {
printf("uses-feature:'android.hardware.screen.portrait'\n");
+ printf("uses-implied-feature:'android.hardware.screen.portrait'," \
+ "'one or more activities have specified a portrait orientation'\n");
}
}
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeWindowManager.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeWindowManager.java
index e6c9351..44d28fa 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeWindowManager.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeWindowManager.java
@@ -229,6 +229,12 @@
}
@Override
+ public void overridePendingAppTransitionScaleUp(int startX, int startY, int startWidth,
+ int startHeight) throws RemoteException {
+ // TODO Auto-generated method stub
+ }
+
+ @Override
public void overridePendingAppTransitionThumb(Bitmap srcThumb, int startX, int startY,
IRemoteCallback startedCallback) throws RemoteException {
// TODO Auto-generated method stub
diff --git a/tools/validatekeymaps/Main.cpp b/tools/validatekeymaps/Main.cpp
index 563225e..91e4fda 100644
--- a/tools/validatekeymaps/Main.cpp
+++ b/tools/validatekeymaps/Main.cpp
@@ -89,7 +89,8 @@
case FILETYPE_KEYCHARACTERMAP: {
sp<KeyCharacterMap> map;
- status_t status = KeyCharacterMap::load(String8(filename), &map);
+ status_t status = KeyCharacterMap::load(String8(filename),
+ KeyCharacterMap::FORMAT_ANY, &map);
if (status) {
fprintf(stderr, "Error %d parsing key character map file.\n\n", status);
return false;
diff --git a/wifi/java/android/net/wifi/StateChangeResult.java b/wifi/java/android/net/wifi/StateChangeResult.java
index 8ab5982..b15c4a6 100644
--- a/wifi/java/android/net/wifi/StateChangeResult.java
+++ b/wifi/java/android/net/wifi/StateChangeResult.java
@@ -23,12 +23,15 @@
* @hide
*/
public class StateChangeResult {
- StateChangeResult(int networkId, String BSSID, SupplicantState state) {
+ StateChangeResult(int networkId, String SSID, String BSSID, SupplicantState state) {
this.state = state;
+ this.SSID = SSID;
this.BSSID = BSSID;
this.networkId = networkId;
}
+
int networkId;
+ String SSID;
String BSSID;
SupplicantState state;
}
diff --git a/wifi/java/android/net/wifi/WifiMonitor.java b/wifi/java/android/net/wifi/WifiMonitor.java
index 3bd03f5..a447c86 100644
--- a/wifi/java/android/net/wifi/WifiMonitor.java
+++ b/wifi/java/android/net/wifi/WifiMonitor.java
@@ -637,6 +637,9 @@
* id=network-id state=new-state
*/
private void handleSupplicantStateChange(String dataString) {
+ String SSID = null;
+ int index = dataString.lastIndexOf("SSID=");
+ if (index != -1) SSID = dataString.substring(index + 5);
String[] dataTokens = dataString.split(" ");
String BSSID = null;
@@ -657,7 +660,6 @@
try {
value = Integer.parseInt(nameValue[1]);
} catch (NumberFormatException e) {
- Log.w(TAG, "STATE-CHANGE non-integer parameter: " + token);
continue;
}
@@ -680,7 +682,7 @@
if (newSupplicantState == SupplicantState.INVALID) {
Log.w(TAG, "Invalid supplicant state: " + newState);
}
- notifySupplicantStateChange(networkId, BSSID, newSupplicantState);
+ notifySupplicantStateChange(networkId, SSID, BSSID, newSupplicantState);
}
}
@@ -729,11 +731,13 @@
* Send the state machine a notification that the state of the supplicant
* has changed.
* @param networkId the configured network on which the state change occurred
+ * @param SSID network name
+ * @param BSSID network address
* @param newState the new {@code SupplicantState}
*/
- void notifySupplicantStateChange(int networkId, String BSSID, SupplicantState newState) {
+ void notifySupplicantStateChange(int networkId, String SSID, String BSSID, SupplicantState newState) {
mStateMachine.sendMessage(mStateMachine.obtainMessage(SUPPLICANT_STATE_CHANGE_EVENT,
- new StateChangeResult(networkId, BSSID, newState)));
+ new StateChangeResult(networkId, SSID, BSSID, newState)));
}
/**
diff --git a/wifi/java/android/net/wifi/WifiStateMachine.java b/wifi/java/android/net/wifi/WifiStateMachine.java
index cc0df52..2f14098 100644
--- a/wifi/java/android/net/wifi/WifiStateMachine.java
+++ b/wifi/java/android/net/wifi/WifiStateMachine.java
@@ -669,6 +669,7 @@
setInitialState(mInitialState);
+ setProcessedMessagesSize(100);
if (DBG) setDbg(true);
//start the state machine
@@ -1121,6 +1122,37 @@
return sb.toString();
}
+ @Override
+ protected boolean recordProcessedMessage(Message msg) {
+ //Ignore screen on/off & common messages when driver has started
+ if (getCurrentState() == mConnectedState || getCurrentState() == mDisconnectedState) {
+ switch (msg.what) {
+ case CMD_LOAD_DRIVER:
+ case CMD_START_SUPPLICANT:
+ case CMD_START_DRIVER:
+ case CMD_SET_SCAN_MODE:
+ case CMD_SET_HIGH_PERF_MODE:
+ case CMD_SET_SUSPEND_OPTIMIZATIONS:
+ case CMD_CLEAR_SUSPEND_OPTIMIZATIONS:
+ case CMD_ENABLE_BACKGROUND_SCAN:
+ case CMD_ENABLE_ALL_NETWORKS:
+ return false;
+ }
+ }
+
+ switch (msg.what) {
+ case CMD_START_SCAN:
+ case CMD_ENABLE_RSSI_POLL:
+ case CMD_RSSI_POLL:
+ case CMD_DELAYED_STOP_DRIVER:
+ case WifiMonitor.SCAN_RESULTS_EVENT:
+ case WifiWatchdogStateMachine.RSSI_FETCH:
+ return false;
+ default:
+ return true;
+ }
+ }
+
/*********************************************************
* Internal private functions
********************************************************/
@@ -1409,23 +1441,6 @@
mScanResults = scanList;
}
- private String fetchSSID() {
- String status = mWifiNative.status();
- if (status == null) {
- return null;
- }
- // extract ssid from a series of "name=value"
- String[] lines = status.split("\n");
- for (String line : lines) {
- String[] prop = line.split(" *= *");
- if (prop.length < 2) continue;
- String name = prop[0];
- String value = prop[1];
- if (name.equalsIgnoreCase("ssid")) return value;
- }
- return null;
- }
-
/*
* Fetch RSSI and linkspeed on current connection
*/
@@ -1586,6 +1601,7 @@
/* BSSID is valid only in ASSOCIATING state */
mWifiInfo.setBSSID(stateChangeResult.BSSID);
}
+ mWifiInfo.setSSID(stateChangeResult.SSID);
mSupplicantStateTracker.sendMessage(Message.obtain(message));
@@ -2015,7 +2031,6 @@
default:
return NOT_HANDLED;
}
- EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what);
return HANDLED;
}
}
@@ -2068,7 +2083,6 @@
default:
return NOT_HANDLED;
}
- EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what);
return HANDLED;
}
}
@@ -2148,7 +2162,6 @@
default:
return NOT_HANDLED;
}
- EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what);
return HANDLED;
}
}
@@ -2169,7 +2182,6 @@
default:
return NOT_HANDLED;
}
- EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what);
return HANDLED;
}
}
@@ -2250,7 +2262,6 @@
default:
return NOT_HANDLED;
}
- EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what);
return HANDLED;
}
}
@@ -2274,7 +2285,6 @@
public boolean processMessage(Message message) {
if (DBG) log(getName() + message.toString() + "\n");
WifiConfiguration config;
- boolean eventLoggingEnabled = true;
switch(message.what) {
case CMD_STOP_SUPPLICANT: /* Supplicant stopped by user */
transitionTo(mSupplicantStoppingState);
@@ -2291,7 +2301,6 @@
sendMessageDelayed(CMD_START_SUPPLICANT, SUPPLICANT_RESTART_INTERVAL_MSECS);
break;
case WifiMonitor.SCAN_RESULTS_EVENT:
- eventLoggingEnabled = false;
setScanResults(mWifiNative.scanResults());
sendScanResultsAvailableBroadcast();
mScanResultIsPending = false;
@@ -2381,9 +2390,6 @@
default:
return NOT_HANDLED;
}
- if (eventLoggingEnabled) {
- EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what);
- }
return HANDLED;
}
@@ -2459,7 +2465,6 @@
default:
return NOT_HANDLED;
}
- EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what);
return HANDLED;
}
}
@@ -2505,7 +2510,6 @@
default:
return NOT_HANDLED;
}
- EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what);
return HANDLED;
}
}
@@ -2564,14 +2568,12 @@
@Override
public boolean processMessage(Message message) {
if (DBG) log(getName() + message.toString() + "\n");
- boolean eventLoggingEnabled = true;
switch(message.what) {
case CMD_SET_SCAN_TYPE:
mSetScanActive = (message.arg1 == SCAN_ACTIVE);
mWifiNative.setScanMode(mSetScanActive);
break;
case CMD_START_SCAN:
- eventLoggingEnabled = false;
boolean forceActive = (message.arg1 == SCAN_ACTIVE);
if (forceActive && !mSetScanActive) {
mWifiNative.setScanMode(forceActive);
@@ -2681,9 +2683,6 @@
default:
return NOT_HANDLED;
}
- if (eventLoggingEnabled) {
- EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what);
- }
return HANDLED;
}
@Override
@@ -2731,7 +2730,6 @@
default:
return NOT_HANDLED;
}
- EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what);
return HANDLED;
}
}
@@ -2764,7 +2762,6 @@
default:
return NOT_HANDLED;
}
- EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what);
return HANDLED;
}
}
@@ -2801,7 +2798,6 @@
default:
return NOT_HANDLED;
}
- EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what);
return HANDLED;
}
}
@@ -2923,8 +2919,6 @@
mLastNetworkId = message.arg1;
mLastBssid = (String) message.obj;
- //TODO: make supplicant modification to push this in events
- mWifiInfo.setSSID(fetchSSID());
mWifiInfo.setBSSID(mLastBssid);
mWifiInfo.setNetworkId(mLastNetworkId);
/* send event to CM & network change broadcast */
@@ -2940,7 +2934,6 @@
default:
return NOT_HANDLED;
}
- EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what);
return HANDLED;
}
}
@@ -2959,7 +2952,6 @@
@Override
public boolean processMessage(Message message) {
if (DBG) log(getName() + message.toString() + "\n");
- boolean eventLoggingEnabled = true;
switch (message.what) {
case DhcpStateMachine.CMD_PRE_DHCP_ACTION:
handlePreDhcpSetup();
@@ -2988,7 +2980,6 @@
}
break;
case CMD_START_SCAN:
- eventLoggingEnabled = false;
/* When the network is connected, re-scanning can trigger
* a reconnection. Put it in scan-only mode during scan.
* When scan results are received, the mode is switched
@@ -3031,7 +3022,6 @@
case WifiMonitor.NETWORK_CONNECTION_EVENT:
break;
case CMD_RSSI_POLL:
- eventLoggingEnabled = false;
if (message.arg1 == mRssiPollToken) {
// Get Info and continue polling
fetchRssiAndLinkSpeedNative();
@@ -3052,7 +3042,6 @@
}
break;
case WifiWatchdogStateMachine.RSSI_FETCH:
- eventLoggingEnabled = false;
fetchRssiAndLinkSpeedNative();
replyToMessage(message, WifiWatchdogStateMachine.RSSI_FETCH_SUCCEEDED,
mWifiInfo.getRssi());
@@ -3061,9 +3050,6 @@
return NOT_HANDLED;
}
- if (eventLoggingEnabled) {
- EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what);
- }
return HANDLED;
}
@@ -3131,7 +3117,6 @@
default:
return NOT_HANDLED;
}
- EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what);
return HANDLED;
}
}
@@ -3168,7 +3153,6 @@
default:
return NOT_HANDLED;
}
- EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what);
return HANDLED;
}
}
@@ -3202,7 +3186,6 @@
default:
return NOT_HANDLED;
}
- EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what);
return HANDLED;
}
@Override
@@ -3240,7 +3223,6 @@
default:
return NOT_HANDLED;
}
- EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what);
return HANDLED;
}
}
@@ -3343,7 +3325,6 @@
default:
return NOT_HANDLED;
}
- EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what);
return HANDLED;
}
@@ -3432,7 +3413,6 @@
default:
return NOT_HANDLED;
}
- EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what);
return HANDLED;
}
@@ -3504,7 +3484,6 @@
default:
return NOT_HANDLED;
}
- EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what);
return HANDLED;
}
}
@@ -3548,7 +3527,6 @@
default:
return NOT_HANDLED;
}
- EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what);
return HANDLED;
}
}
@@ -3598,7 +3576,6 @@
default:
return NOT_HANDLED;
}
- EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what);
return HANDLED;
}
}
@@ -3629,7 +3606,6 @@
default:
return NOT_HANDLED;
}
- EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what);
return HANDLED;
}
}
@@ -3692,7 +3668,6 @@
default:
return NOT_HANDLED;
}
- EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what);
return HANDLED;
}
}
diff --git a/wifi/java/android/net/wifi/p2p/WifiP2pManager.java b/wifi/java/android/net/wifi/p2p/WifiP2pManager.java
index 35f37a8..df14bb9 100644
--- a/wifi/java/android/net/wifi/p2p/WifiP2pManager.java
+++ b/wifi/java/android/net/wifi/p2p/WifiP2pManager.java
@@ -22,8 +22,8 @@
import android.net.ConnectivityManager;
import android.net.IConnectivityManager;
import android.net.nsd.DnsSdTxtRecord;
-import android.net.wifi.p2p.nsd.WifiP2pBonjourServiceInfo;
-import android.net.wifi.p2p.nsd.WifiP2pBonjourServiceResponse;
+import android.net.wifi.p2p.nsd.WifiP2pDnsSdServiceInfo;
+import android.net.wifi.p2p.nsd.WifiP2pDnsSdServiceResponse;
import android.net.wifi.p2p.nsd.WifiP2pServiceInfo;
import android.net.wifi.p2p.nsd.WifiP2pServiceRequest;
import android.net.wifi.p2p.nsd.WifiP2pServiceResponse;
@@ -56,21 +56,20 @@
* callbacks provided by the application. The application needs to do an initialization with
* {@link #initialize} before doing any p2p operation.
*
- * <p> Application actions {@link #discoverPeers}, {@link #connect}, {@link #cancelConnect},
- * {@link #createGroup} and {@link #removeGroup} need a {@link ActionListener} instance for
- * receiving callbacks {@link ActionListener#onSuccess} or {@link ActionListener#onFailure}.
- * Action callbacks indicate whether the initiation of the action was a success or a failure.
+ * <p> Most application calls need a {@link ActionListener} instance for receiving callbacks
+ * {@link ActionListener#onSuccess} or {@link ActionListener#onFailure}. Action callbacks
+ * indicate whether the initiation of the action was a success or a failure.
* Upon failure, the reason of failure can be one of {@link #ERROR}, {@link #P2P_UNSUPPORTED}
* or {@link #BUSY}.
*
* <p> An application can initiate discovery of peers with {@link #discoverPeers}. An initiated
* discovery request from an application stays active until the device starts connecting to a peer
- * or forms a p2p group. The {@link ActionListener} callbacks provide feedback on whether the
- * discovery initiation was successful or failure. Additionally, applications can listen
- * to {@link #WIFI_P2P_PEERS_CHANGED_ACTION} intent action to know when the peer list changes.
+ * ,forms a p2p group or there is an explicit {@link #stopPeerDiscovery}.
+ * Applications can listen to {@link #WIFI_P2P_DISCOVERY_CHANGED_ACTION} to know if a peer-to-peer
+ * discovery is running or stopped. Additionally, {@link #WIFI_P2P_PEERS_CHANGED_ACTION} indicates
+ * if the peer list has changed.
*
- * <p> When the peer list change intent {@link #WIFI_P2P_PEERS_CHANGED_ACTION} is received
- * or when an application needs to fetch the current list of peers, it can request the list
+ * <p> When an application needs to fetch the current list of peers, it can request the list
* of peers with {@link #requestPeers}. When the peer list is available
* {@link PeerListListener#onPeersAvailable} is called with the device list.
*
@@ -78,7 +77,7 @@
* {@link WifiP2pConfig} for details on setting up the configuration. For communication with legacy
* Wi-Fi devices that do not support p2p, an app can create a group using {@link #createGroup}
* which creates an access point whose details can be fetched with {@link #requestGroupInfo}.
-*
+ *
* <p> After a successful group formation through {@link #createGroup} or through {@link #connect},
* use {@link #requestConnectionInfo} to fetch the connection details. The connection info
* {@link WifiP2pInfo} contains the address of the group owner
@@ -86,8 +85,36 @@
* if the current device is a p2p group owner. A p2p client can thus communicate with
* the p2p group owner through a socket connection.
*
- * <p> Android has no platform support for service discovery yet, so applications could
- * run a service discovery protocol to discover services on the peer-to-peer netework.
+ * <p> With peer discovery using {@link #discoverPeers}, an application discovers the neighboring
+ * peers, but has no good way to figure out which peer to establish a connection with. For example,
+ * if a game application is interested in finding all the neighboring peers that are also running
+ * the same game, it has no way to find out until after the connection is setup. Pre-association
+ * service discovery is meant to address this issue of filtering the peers based on the running
+ * services.
+ *
+ * <p>With pre-association service discovery, an application can advertise a service for a
+ * application on a peer device prior to a connection setup between the devices.
+ * Currently, DNS based service discovery (Bonjour) and Upnp are the higher layer protocols
+ * supported. Get Bonjour resources at dns-sd.org and Upnp resources at upnp.org
+ * As an example, a video application can discover a Upnp capable media renderer
+ * prior to setting up a Wi-fi p2p connection with the device.
+ *
+ * <p> An application can advertise a Upnp or a Bonjour service with a call to
+ * {@link #addLocalService}. After a local service is added,
+ * the framework automatically responds to a peer application discovering the service prior
+ * to establishing a p2p connection. A call to {@link #removeLocalService} removes a local
+ * service and {@link #clearLocalServices} can be used to clear all local services.
+ *
+ * <p> An application that is looking for peer devices that support certain services
+ * can do so with a call to {@link #discoverServices}. Prior to initiating the discovery,
+ * application can add service discovery request with a call to {@link #addServiceRequest},
+ * remove a service discovery request with a call to {@link #removeServiceRequest} or clear
+ * all requests with a call to {@link #clearServiceRequests}. When no service requests remain,
+ * a previously running service discovery will stop.
+ *
+ * The application is notified of a result of service discovery request through listener callbacks
+ * set through {@link #setDnsSdResponseListeners} for Bonjour or
+ * {@link #setUpnpServiceResponseListener} for Upnp.
*
* <p class="note"><strong>Note:</strong>
* Registering an application handler with {@link #initialize} requires the permissions
@@ -443,30 +470,28 @@
/**
* Interface for callback invocation when service discovery response other than
- * UPnP or Bonjour is received
- * @hide
+ * Upnp or Bonjour is received
*/
public interface ServiceResponseListener {
/**
* The requested service response is available.
*
- * @param serviceType service type. see the service type of
- * {@link WifiP2pServiceInfo}
+ * @param protocolType protocol type. currently only
+ * {@link WifiP2pServiceInfo#SERVICE_TYPE_VENDOR_SPECIFIC}.
* @param responseData service discovery response data based on the requested
* service protocol type. The format depends on the service type.
* @param srcDevice source device.
*/
- public void onServiceAvailable(int serviceType,
+ public void onServiceAvailable(int protocolType,
byte[] responseData, WifiP2pDevice srcDevice);
}
/**
* Interface for callback invocation when Bonjour service discovery response
* is received
- * @hide
*/
- public interface BonjourServiceResponseListener {
+ public interface DnsSdServiceResponseListener {
/**
* The requested Bonjour service response is available.
@@ -479,7 +504,7 @@
* e.g) "_ipp._tcp.local."
* @param srcDevice source device.
*/
- public void onBonjourServiceAvailable(String instanceName,
+ public void onDnsSdServiceAvailable(String instanceName,
String registrationType, WifiP2pDevice srcDevice);
}
@@ -487,9 +512,8 @@
/**
* Interface for callback invocation when Bonjour TXT record is available
* for a service
- * @hide
*/
- public interface BonjourTxtRecordListener {
+ public interface DnsSdTxtRecordListener {
/**
* The requested Bonjour service response is available.
*
@@ -501,7 +525,7 @@
* @param record txt record.
* @param srcDevice source device.
*/
- public void onBonjourTxtRecordAvailable(String fullDomainName,
+ public void onDnsSdTxtRecordAvailable(String fullDomainName,
DnsSdTxtRecord record,
WifiP2pDevice srcDevice);
}
@@ -509,7 +533,6 @@
/**
* Interface for callback invocation when upnp service discovery response
* is received
- * @hide
* */
public interface UpnpServiceResponseListener {
@@ -542,8 +565,8 @@
private final static int INVALID_LISTENER_KEY = 0;
private ChannelListener mChannelListener;
private ServiceResponseListener mServRspListener;
- private BonjourServiceResponseListener mBonjourServRspListener;
- private BonjourTxtRecordListener mBonjourTxtListener;
+ private DnsSdServiceResponseListener mDnsSdServRspListener;
+ private DnsSdTxtRecordListener mDnsSdTxtListener;
private UpnpServiceResponseListener mUpnpServRspListener;
private HashMap<Integer, Object> mListenerMap = new HashMap<Integer, Object>();
private Object mListenerMapLock = new Object();
@@ -632,8 +655,8 @@
}
private void handleServiceResponse(WifiP2pServiceResponse resp) {
- if (resp instanceof WifiP2pBonjourServiceResponse) {
- handleBonjourServiceResponse((WifiP2pBonjourServiceResponse)resp);
+ if (resp instanceof WifiP2pDnsSdServiceResponse) {
+ handleDnsSdServiceResponse((WifiP2pDnsSdServiceResponse)resp);
} else if (resp instanceof WifiP2pUpnpServiceResponse) {
if (mUpnpServRspListener != null) {
handleUpnpServiceResponse((WifiP2pUpnpServiceResponse)resp);
@@ -651,17 +674,17 @@
resp.getSrcDevice());
}
- private void handleBonjourServiceResponse(WifiP2pBonjourServiceResponse resp) {
- if (resp.getDnsType() == WifiP2pBonjourServiceInfo.DNS_TYPE_PTR) {
- if (mBonjourServRspListener != null) {
- mBonjourServRspListener.onBonjourServiceAvailable(
+ private void handleDnsSdServiceResponse(WifiP2pDnsSdServiceResponse resp) {
+ if (resp.getDnsType() == WifiP2pDnsSdServiceInfo.DNS_TYPE_PTR) {
+ if (mDnsSdServRspListener != null) {
+ mDnsSdServRspListener.onDnsSdServiceAvailable(
resp.getInstanceName(),
resp.getDnsQueryName(),
resp.getSrcDevice());
}
- } else if (resp.getDnsType() == WifiP2pBonjourServiceInfo.DNS_TYPE_TXT) {
- if (mBonjourTxtListener != null) {
- mBonjourTxtListener.onBonjourTxtRecordAvailable(
+ } else if (resp.getDnsType() == WifiP2pDnsSdServiceInfo.DNS_TYPE_TXT) {
+ if (mDnsSdTxtListener != null) {
+ mDnsSdTxtListener.onDnsSdTxtRecordAvailable(
resp.getDnsQueryName(),
resp.getTxtRecord(),
resp.getSrcDevice());
@@ -749,10 +772,16 @@
c.mAsyncChannel.sendMessage(DISCOVER_PEERS, 0, c.putListener(listener));
}
- /**
- * TODO: Add more documentation before opening up
- * Cancel peer discovery
- * @hide
+ /**
+ * Stop an ongoing peer discovery
+ *
+ * <p> The function call immediately returns after sending a stop request
+ * to the framework. The application is notified of a success or failure to initiate
+ * stop through listener callbacks {@link ActionListener#onSuccess} or
+ * {@link ActionListener#onFailure}.
+ *
+ * @param c is the channel created at {@link #initialize}
+ * @param listener for callbacks on success or failure. Can be null.
*/
public void stopPeerDiscovery(Channel c, ActionListener listener) {
checkChannel(c);
@@ -843,27 +872,25 @@
}
/**
- * Register a local service of service discovery.
+ * Register a local service for service discovery. If a local service is registered,
+ * the framework automatically responds to a service discovery request from a peer.
*
* <p> The function call immediately returns after sending a request to add a local
* service to the framework. The application is notified of a success or failure to
* add service through listener callbacks {@link ActionListener#onSuccess} or
* {@link ActionListener#onFailure}.
*
- * <p>The service information is set through the subclass of {@link WifiP2pServiceInfo}.<br>
- * e.g ) {@link WifiP2pUpnpServiceInfo#newInstance} or
- * {@link WifiP2pBonjourServiceInfo#newInstance}
+ * <p>The service information is set through {@link WifiP2pServiceInfo}.<br>
+ * or its subclass calls {@link WifiP2pUpnpServiceInfo#newInstance} or
+ * {@link WifiP2pDnsSdServiceInfo#newInstance} for a Upnp or Bonjour service
+ * respectively
*
- * <p>If a local service is added, the framework responds the appropriate service discovery
- * request automatically.
- *
- * <p>These service information will be clear when p2p is disabled or call
+ * <p>The service information can be cleared with calls to
* {@link #removeLocalService} or {@link #clearLocalServices}.
*
* @param c is the channel created at {@link #initialize}
* @param servInfo is a local service information.
* @param listener for callbacks on success or failure. Can be null.
- * @hide
*/
public void addLocalService(Channel c, WifiP2pServiceInfo servInfo, ActionListener listener) {
checkChannel(c);
@@ -872,7 +899,7 @@
}
/**
- * Unregister a specified local service of service discovery.
+ * Remove a registered local service added with {@link #addLocalService}
*
* <p> The function call immediately returns after sending a request to remove a
* local service to the framework. The application is notified of a success or failure to
@@ -882,7 +909,6 @@
* @param c is the channel created at {@link #initialize}
* @param servInfo is the local service information.
* @param listener for callbacks on success or failure. Can be null.
- * @hide
*/
public void removeLocalService(Channel c, WifiP2pServiceInfo servInfo,
ActionListener listener) {
@@ -901,7 +927,6 @@
*
* @param c is the channel created at {@link #initialize}
* @param listener for callbacks on success or failure. Can be null.
- * @hide
*/
public void clearLocalServices(Channel c, ActionListener listener) {
checkChannel(c);
@@ -910,12 +935,14 @@
/**
* Register a callback to be invoked on receiving service discovery response.
+ * Used only for vendor specific protocol right now. For Bonjour or Upnp, use
+ * {@link #setDnsSdResponseListeners} or {@link #setUpnpServiceResponseListener}
+ * respectively.
*
* <p> see {@link #discoverServices} for the detail.
*
* @param c is the channel created at {@link #initialize}
* @param listener for callbacks on receiving service discovery response.
- * @hide
*/
public void setServiceResponseListener(Channel c,
ServiceResponseListener listener) {
@@ -930,15 +957,14 @@
* <p> see {@link #discoverServices} for the detail.
*
* @param c
- * @param servlistener is for listening to a Bonjour service response
- * @param txtListener is for listening to a Bonjour TXT record
- * @hide
+ * @param servListener is for listening to a Bonjour service response
+ * @param txtListener is for listening to a Bonjour TXT record response
*/
- public void setBonjourResponseListeners(Channel c,
- BonjourServiceResponseListener servListener, BonjourTxtRecordListener txtListener) {
+ public void setDnsSdResponseListeners(Channel c,
+ DnsSdServiceResponseListener servListener, DnsSdTxtRecordListener txtListener) {
checkChannel(c);
- c.mBonjourServRspListener = servListener;
- c.mBonjourTxtListener = txtListener;
+ c.mDnsSdServRspListener = servListener;
+ c.mDnsSdTxtListener = txtListener;
}
/**
@@ -949,7 +975,6 @@
*
* @param c is the channel created at {@link #initialize}
* @param listener for callbacks on receiving service discovery response.
- * @hide
*/
public void setUpnpServiceResponseListener(Channel c,
UpnpServiceResponseListener listener) {
@@ -971,11 +996,10 @@
*
* <p>The application is notified of the response against the service discovery request
* through listener callbacks registered by {@link #setServiceResponseListener} or
- * {@link #setBonjourServiceResponseListener}, or {@link #setUpnpServiceResponseListener}.
+ * {@link #setDnsSdResponseListeners}, or {@link #setUpnpServiceResponseListener}.
*
* @param c is the channel created at {@link #initialize}
* @param listener for callbacks on success or failure. Can be null.
- * @hide
*/
public void discoverServices(Channel c, ActionListener listener) {
checkChannel(c);
@@ -993,14 +1017,13 @@
* <p>After service discovery request is added, you can initiate service discovery by
* {@link #discoverServices}.
*
- * <p>These information will be clear when wifi p2p is disabled or
+ * <p>The added service requests can be cleared with calls to
* {@link #removeServiceRequest(Channel, WifiP2pServiceRequest, ActionListener)} or
- * {@link #clearServiceRequests(Channel, ActionListener)} is called.
+ * {@link #clearServiceRequests(Channel, ActionListener)}.
*
* @param c is the channel created at {@link #initialize}
* @param req is the service discovery request.
* @param listener for callbacks on success or failure. Can be null.
- * @hide
*/
public void addServiceRequest(Channel c,
WifiP2pServiceRequest req, ActionListener listener) {
@@ -1011,7 +1034,7 @@
}
/**
- * Remove a specified service discovery request.
+ * Remove a specified service discovery request added with {@link #addServiceRequest}
*
* <p> The function call immediately returns after sending a request to remove service
* discovery request to the framework. The application is notified of a success or failure to
@@ -1021,7 +1044,6 @@
* @param c is the channel created at {@link #initialize}
* @param req is the service discovery request.
* @param listener for callbacks on success or failure. Can be null.
- * @hide
*/
public void removeServiceRequest(Channel c, WifiP2pServiceRequest req,
ActionListener listener) {
@@ -1041,7 +1063,6 @@
*
* @param c is the channel created at {@link #initialize}
* @param listener for callbacks on success or failure. Can be null.
- * @hide
*/
public void clearServiceRequests(Channel c, ActionListener listener) {
checkChannel(c);
diff --git a/wifi/java/android/net/wifi/p2p/nsd/WifiP2pBonjourServiceRequest.java b/wifi/java/android/net/wifi/p2p/nsd/WifiP2pBonjourServiceRequest.java
deleted file mode 100644
index d1635f1..0000000
--- a/wifi/java/android/net/wifi/p2p/nsd/WifiP2pBonjourServiceRequest.java
+++ /dev/null
@@ -1,102 +0,0 @@
-/*
- * Copyright (C) 2012 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.net.wifi.p2p.nsd;
-
-
-/**
- * A class for a request of bonjour service discovery.
- * @hide
- */
-public class WifiP2pBonjourServiceRequest extends WifiP2pServiceRequest {
-
- /**
- * This constructor is only used in newInstance().
- *
- * @param query The part of service specific query.
- * @hide
- */
- private WifiP2pBonjourServiceRequest(String query) {
- super(WifiP2pServiceInfo.SERVICE_TYPE_BONJOUR, query);
- }
-
- /**
- * This constructor is only used in newInstance().
- * @hide
- */
- private WifiP2pBonjourServiceRequest() {
- super(WifiP2pServiceInfo.SERVICE_TYPE_BONJOUR, null);
- }
-
- private WifiP2pBonjourServiceRequest(String registrationType, int dnsType, int version) {
- super(WifiP2pServiceInfo.SERVICE_TYPE_BONJOUR, WifiP2pBonjourServiceInfo.createRequest(
- registrationType,
- WifiP2pBonjourServiceInfo.DNS_TYPE_PTR,
- WifiP2pBonjourServiceInfo.VERSION_1));
- }
-
- /**
- * Create a service discovery request to search all Bonjour services.
- *
- * @return service request for Bonjour.
- */
- public static WifiP2pBonjourServiceRequest newInstance() {
- return new WifiP2pBonjourServiceRequest();
- }
-
- /**
- * Create a service discovery request to resolve the instance name with the specified
- * registration type.
- *
- * @param registrationType registration type. Cannot be null <br>
- * e.g) <br>
- * "_afpovertcp._tcp.local."(Apple File Sharing over TCP)<br>
- * "_ipp._tcp.local." (IP Printing over TCP)<br>
- * @return service request for Bonjour.
- */
- public static WifiP2pBonjourServiceRequest newInstance(String registrationType) {
- if (registrationType == null) {
- throw new IllegalArgumentException("registration type cannot be null");
- }
- return new WifiP2pBonjourServiceRequest(registrationType,
- WifiP2pBonjourServiceInfo.DNS_TYPE_PTR,
- WifiP2pBonjourServiceInfo.VERSION_1);
- }
-
- /**
- * Create a service discovery request to get the TXT data from the specified
- * service.
- *
- * @param instanceName instance name. Cannot be null. <br>
- * "MyPrinter"
- * @param registrationType registration type. Cannot be null. <br>
- * e.g) <br>
- * "_afpovertcp._tcp.local."(Apple File Sharing over TCP)<br>
- * "_ipp._tcp.local." (IP Printing over TCP)<br>
- * @return service request for Bonjour.
- */
- public static WifiP2pBonjourServiceRequest newInstance(String instanceName,
- String registrationType) {
- if (instanceName == null || registrationType == null) {
- throw new IllegalArgumentException(
- "instance name or registration type cannot be null");
- }
- String fullDomainName = instanceName + "." + registrationType;
- return new WifiP2pBonjourServiceRequest(fullDomainName,
- WifiP2pBonjourServiceInfo.DNS_TYPE_TXT,
- WifiP2pBonjourServiceInfo.VERSION_1);
- }
-}
diff --git a/wifi/java/android/net/wifi/p2p/nsd/WifiP2pBonjourServiceInfo.java b/wifi/java/android/net/wifi/p2p/nsd/WifiP2pDnsSdServiceInfo.java
similarity index 78%
rename from wifi/java/android/net/wifi/p2p/nsd/WifiP2pBonjourServiceInfo.java
rename to wifi/java/android/net/wifi/p2p/nsd/WifiP2pDnsSdServiceInfo.java
index ed278d5..54b7ac4 100644
--- a/wifi/java/android/net/wifi/p2p/nsd/WifiP2pBonjourServiceInfo.java
+++ b/wifi/java/android/net/wifi/p2p/nsd/WifiP2pDnsSdServiceInfo.java
@@ -25,10 +25,15 @@
import java.util.Map;
/**
- * A class for Bonjour service information.
- * @hide
+ * A class for storing Bonjour service information that is advertised
+ * over a Wi-Fi peer-to-peer setup.
+ *
+ * {@see android.net.wifi.p2p.WifiP2pManager#addLocalService}
+ * {@see android.net.wifi.p2p.WifiP2pManager#removeLocalService}
+ * {@see WifiP2pServiceInfo}
+ * {@see WifiP2pUpnpServiceInfo}
*/
-public class WifiP2pBonjourServiceInfo extends WifiP2pServiceInfo {
+public class WifiP2pDnsSdServiceInfo extends WifiP2pServiceInfo {
/**
* Bonjour version 1.
@@ -67,25 +72,26 @@
*
* @param queryList
*/
- private WifiP2pBonjourServiceInfo(List<String> queryList) {
+ private WifiP2pDnsSdServiceInfo(List<String> queryList) {
super(queryList);
}
/**
- * Create Bonjour service information object.
+ * Create a Bonjour service information object.
*
* @param instanceName instance name.<br>
* e.g) "MyPrinter"
- * @param registrationType registration type.<br>
- * e.g) "_ipp._tcp.local."
- * @param txtRecord text record.
+ * @param serviceType service type.<br>
+ * e.g) "_ipp._tcp"
+ * @param txtRecord TXT record as defined at
+ * http://files.dns-sd.org/draft-cheshire-dnsext-dns-sd.txt
* @return Bonjour service information object
*/
- public static WifiP2pBonjourServiceInfo newInstance(String instanceName,
- String registrationType, DnsSdTxtRecord txtRecord) {
- if (TextUtils.isEmpty(instanceName) || TextUtils.isEmpty(registrationType)) {
+ public static WifiP2pDnsSdServiceInfo newInstance(String instanceName,
+ String serviceType, DnsSdTxtRecord txtRecord) {
+ if (TextUtils.isEmpty(instanceName) || TextUtils.isEmpty(serviceType)) {
throw new IllegalArgumentException(
- "instance name or registration type cannot be empty");
+ "instance name or service type cannot be empty");
}
if (txtRecord == null) {
@@ -93,10 +99,10 @@
}
ArrayList<String> queries = new ArrayList<String>();
- queries.add(createPtrServiceQuery(instanceName, registrationType));
- queries.add(createTxtServiceQuery(instanceName, registrationType, txtRecord));
+ queries.add(createPtrServiceQuery(instanceName, serviceType));
+ queries.add(createTxtServiceQuery(instanceName, serviceType, txtRecord));
- return new WifiP2pBonjourServiceInfo(queries);
+ return new WifiP2pDnsSdServiceInfo(queries);
}
/**
@@ -104,16 +110,16 @@
*
* @param instanceName instance name.<br>
* e.g) "MyPrinter"
- * @param registrationType registration type.<br>
- * e.g) "_ipp._tcp.local."
+ * @param serviceType service type.<br>
+ * e.g) "_ipp._tcp"
* @return wpa_supplicant service query.
*/
private static String createPtrServiceQuery(String instanceName,
- String registrationType) {
+ String serviceType) {
StringBuffer sb = new StringBuffer();
sb.append("bonjour ");
- sb.append(createRequest(registrationType, DNS_TYPE_PTR, VERSION_1));
+ sb.append(createRequest(serviceType + ".local.", DNS_TYPE_PTR, VERSION_1));
sb.append(" ");
byte[] data = instanceName.getBytes();
@@ -130,20 +136,20 @@
*
* @param instanceName instance name.<br>
* e.g) "MyPrinter"
- * @param registrationType registration type.<br>
- * e.g) "_ipp._tcp.local."
+ * @param serviceType service type.<br>
+ * e.g) "_ipp._tcp"
* @param txtRecord TXT record.<br>
* @return wpa_supplicant service query.
*/
- public static String createTxtServiceQuery(String instanceName,
- String registrationType,
+ private static String createTxtServiceQuery(String instanceName,
+ String serviceType,
DnsSdTxtRecord txtRecord) {
StringBuffer sb = new StringBuffer();
sb.append("bonjour ");
- sb.append(createRequest((instanceName + "." + registrationType),
+ sb.append(createRequest((instanceName + "." + serviceType + ".local."),
DNS_TYPE_TXT, VERSION_1));
sb.append(" ");
byte[] rawData = txtRecord.getRawData();
@@ -173,7 +179,7 @@
* ________________________________________________
* | Type (2) | Version (1) |
*/
- if (dnsType == WifiP2pBonjourServiceInfo.DNS_TYPE_TXT) {
+ if (dnsType == WifiP2pDnsSdServiceInfo.DNS_TYPE_TXT) {
dnsName = dnsName.toLowerCase();
}
sb.append(compressDnsName(dnsName));
diff --git a/wifi/java/android/net/wifi/p2p/nsd/WifiP2pDnsSdServiceRequest.java b/wifi/java/android/net/wifi/p2p/nsd/WifiP2pDnsSdServiceRequest.java
new file mode 100644
index 0000000..d5415e0
--- /dev/null
+++ b/wifi/java/android/net/wifi/p2p/nsd/WifiP2pDnsSdServiceRequest.java
@@ -0,0 +1,107 @@
+/*
+ * Copyright (C) 2012 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.net.wifi.p2p.nsd;
+
+import android.net.wifi.p2p.WifiP2pManager;
+
+/**
+ * A class for creating a Bonjour service discovery request for use with
+ * {@link WifiP2pManager#addServiceRequest} and {@link WifiP2pManager#removeServiceRequest}
+ *
+ * {@see WifiP2pManager}
+ * {@see WifiP2pServiceRequest}
+ * {@see WifiP2pUpnpServiceRequest}
+ */
+public class WifiP2pDnsSdServiceRequest extends WifiP2pServiceRequest {
+
+ /**
+ * This constructor is only used in newInstance().
+ *
+ * @param query The part of service specific query.
+ * @hide
+ */
+ private WifiP2pDnsSdServiceRequest(String query) {
+ super(WifiP2pServiceInfo.SERVICE_TYPE_BONJOUR, query);
+ }
+
+ /**
+ * This constructor is only used in newInstance().
+ * @hide
+ */
+ private WifiP2pDnsSdServiceRequest() {
+ super(WifiP2pServiceInfo.SERVICE_TYPE_BONJOUR, null);
+ }
+
+ private WifiP2pDnsSdServiceRequest(String dnsQuery, int dnsType, int version) {
+ super(WifiP2pServiceInfo.SERVICE_TYPE_BONJOUR, WifiP2pDnsSdServiceInfo.createRequest(
+ dnsQuery,
+ dnsType,
+ version));
+ }
+
+ /**
+ * Create a service discovery request to search all Bonjour services.
+ *
+ * @return service request for Bonjour.
+ */
+ public static WifiP2pDnsSdServiceRequest newInstance() {
+ return new WifiP2pDnsSdServiceRequest();
+ }
+
+ /**
+ * Create a service discovery to search for Bonjour services with the specified
+ * service type.
+ *
+ * @param serviceType service type. Cannot be null <br>
+ * "_afpovertcp._tcp."(Apple File Sharing over TCP)<br>
+ * "_ipp._tcp" (IP Printing over TCP)<br>
+ * "_http._tcp" (http service)
+ * @return service request for DnsSd.
+ */
+ public static WifiP2pDnsSdServiceRequest newInstance(String serviceType) {
+ if (serviceType == null) {
+ throw new IllegalArgumentException("service type cannot be null");
+ }
+ return new WifiP2pDnsSdServiceRequest(serviceType + ".local.",
+ WifiP2pDnsSdServiceInfo.DNS_TYPE_PTR,
+ WifiP2pDnsSdServiceInfo.VERSION_1);
+ }
+
+ /**
+ * Create a service discovery request to get the TXT data from the specified
+ * Bonjour service.
+ *
+ * @param instanceName instance name. Cannot be null. <br>
+ * "MyPrinter"
+ * @param serviceType service type. Cannot be null. <br>
+ * e.g) <br>
+ * "_afpovertcp._tcp"(Apple File Sharing over TCP)<br>
+ * "_ipp._tcp" (IP Printing over TCP)<br>
+ * @return service request for Bonjour.
+ */
+ public static WifiP2pDnsSdServiceRequest newInstance(String instanceName,
+ String serviceType) {
+ if (instanceName == null || serviceType == null) {
+ throw new IllegalArgumentException(
+ "instance name or service type cannot be null");
+ }
+ String fullDomainName = instanceName + "." + serviceType + ".local.";
+ return new WifiP2pDnsSdServiceRequest(fullDomainName,
+ WifiP2pDnsSdServiceInfo.DNS_TYPE_TXT,
+ WifiP2pDnsSdServiceInfo.VERSION_1);
+ }
+}
diff --git a/wifi/java/android/net/wifi/p2p/nsd/WifiP2pBonjourServiceResponse.java b/wifi/java/android/net/wifi/p2p/nsd/WifiP2pDnsSdServiceResponse.java
similarity index 88%
rename from wifi/java/android/net/wifi/p2p/nsd/WifiP2pBonjourServiceResponse.java
rename to wifi/java/android/net/wifi/p2p/nsd/WifiP2pDnsSdServiceResponse.java
index c511569..c053c8a 100644
--- a/wifi/java/android/net/wifi/p2p/nsd/WifiP2pBonjourServiceResponse.java
+++ b/wifi/java/android/net/wifi/p2p/nsd/WifiP2pDnsSdServiceResponse.java
@@ -30,7 +30,7 @@
*
* @hide
*/
-public class WifiP2pBonjourServiceResponse extends WifiP2pServiceResponse {
+public class WifiP2pDnsSdServiceResponse extends WifiP2pServiceResponse {
/**
* DNS query name.
@@ -46,27 +46,27 @@
* Service instance name.
* e.g) "MyPrinter"
* This field is only used when the dns type equals to
- * {@link WifiP2pBonjourServiceInfo#DNS_TYPE_PTR}.
+ * {@link WifiP2pDnsSdServiceInfo#DNS_TYPE_PTR}.
*/
private String mInstanceName;
/**
* DNS Type.
- * Should be {@link WifiP2pBonjourServiceInfo#DNS_TYPE_PTR} or
- * {@link WifiP2pBonjourServiceInfo#DNS_TYPE_TXT}.
+ * Should be {@link WifiP2pDnsSdServiceInfo#DNS_TYPE_PTR} or
+ * {@link WifiP2pDnsSdServiceInfo#DNS_TYPE_TXT}.
*/
private int mDnsType;
/**
- * Bonjour version number.
- * Should be {@link WifiP2pBonjourServiceInfo#VERSION_1}.
+ * DnsSd version number.
+ * Should be {@link WifiP2pDnsSdServiceInfo#VERSION_1}.
*/
private int mVersion;
/**
* Txt record.
* This field is only used when the dns type equals to
- * {@link WifiP2pBonjourServiceInfo#DNS_TYPE_TXT}.
+ * {@link WifiP2pDnsSdServiceInfo#DNS_TYPE_TXT}.
*/
private DnsSdTxtRecord mTxtRecord;
@@ -128,7 +128,7 @@
@Override
public String toString() {
StringBuffer sbuf = new StringBuffer();
- sbuf.append("serviceType:Bonjour(").append(mServiceType).append(")");
+ sbuf.append("serviceType:DnsSd(").append(mServiceType).append(")");
sbuf.append(" status:").append(Status.toString(mStatus));
sbuf.append(" srcAddr:").append(mDevice.deviceAddress);
sbuf.append(" version:").append(String.format("%02x", mVersion));
@@ -149,7 +149,7 @@
* @param data RDATA.
* @hide
*/
- protected WifiP2pBonjourServiceResponse(int status,
+ protected WifiP2pDnsSdServiceResponse(int status,
int tranId, WifiP2pDevice dev, byte[] data) {
super(WifiP2pServiceInfo.SERVICE_TYPE_BONJOUR,
status, tranId, dev, data);
@@ -159,7 +159,7 @@
}
/**
- * Parse Bonjour service discovery response.
+ * Parse DnsSd service discovery response.
*
* @return {@code true} if the operation succeeded
*/
@@ -193,7 +193,7 @@
return false;
}
- if (mDnsType == WifiP2pBonjourServiceInfo.DNS_TYPE_PTR) {
+ if (mDnsType == WifiP2pDnsSdServiceInfo.DNS_TYPE_PTR) {
String rData = readDnsName(dis);
if (rData == null) {
return false;
@@ -204,7 +204,7 @@
mInstanceName = rData.substring(0,
rData.length() - mDnsQueryName.length() -1);
- } else if (mDnsType == WifiP2pBonjourServiceInfo.DNS_TYPE_TXT) {
+ } else if (mDnsType == WifiP2pDnsSdServiceInfo.DNS_TYPE_TXT) {
mTxtRecord = readTxtData(dis);
if (mTxtRecord == null) {
return false;
@@ -287,23 +287,23 @@
}
/**
- * Creates Bonjour service response.
+ * Creates DnsSd service response.
* This is only called from WifiP2pServiceResponse
*
* @param status status code.
* @param dev source device.
- * @param data Bonjour response data.
- * @return Bonjour service response data.
+ * @param data DnsSd response data.
+ * @return DnsSd service response data.
* @hide
*/
- static WifiP2pBonjourServiceResponse newInstance(int status,
+ static WifiP2pDnsSdServiceResponse newInstance(int status,
int transId, WifiP2pDevice dev, byte[] data) {
if (status != WifiP2pServiceResponse.Status.SUCCESS) {
- return new WifiP2pBonjourServiceResponse(status,
+ return new WifiP2pDnsSdServiceResponse(status,
transId, dev, null);
}
try {
- return new WifiP2pBonjourServiceResponse(status,
+ return new WifiP2pDnsSdServiceResponse(status,
transId, dev, data);
} catch (IllegalArgumentException e) {
e.printStackTrace();
diff --git a/wifi/java/android/net/wifi/p2p/nsd/WifiP2pServiceInfo.java b/wifi/java/android/net/wifi/p2p/nsd/WifiP2pServiceInfo.java
index aed5616..b931475 100644
--- a/wifi/java/android/net/wifi/p2p/nsd/WifiP2pServiceInfo.java
+++ b/wifi/java/android/net/wifi/p2p/nsd/WifiP2pServiceInfo.java
@@ -23,13 +23,11 @@
import java.util.List;
/**
- * The class for service information.
- *
- * <p>Currently UPnP and Bonjour are only supported.
+ * A class for storing service information that is advertised
+ * over a Wi-Fi peer-to-peer setup
*
* @see WifiP2pUpnpServiceInfo
- * @see WifiP2pBonjourServiceInfo
- * @hide
+ * @see WifiP2pDnsSdServiceInfo
*/
public class WifiP2pServiceInfo implements Parcelable {
@@ -39,7 +37,7 @@
public static final int SERVICE_TYPE_ALL = 0;
/**
- * Bonjour protocol.
+ * DNS based service discovery protocol.
*/
public static final int SERVICE_TYPE_BONJOUR = 1;
@@ -50,6 +48,7 @@
/**
* WS-Discovery protocol
+ * @hide
*/
public static final int SERVICE_TYPE_WS_DISCOVERY = 3;
diff --git a/wifi/java/android/net/wifi/p2p/nsd/WifiP2pServiceRequest.java b/wifi/java/android/net/wifi/p2p/nsd/WifiP2pServiceRequest.java
index e41d9aa..c7f0e5f 100644
--- a/wifi/java/android/net/wifi/p2p/nsd/WifiP2pServiceRequest.java
+++ b/wifi/java/android/net/wifi/p2p/nsd/WifiP2pServiceRequest.java
@@ -21,24 +21,26 @@
import android.os.Parcelable;
/**
- * A class for a request of service discovery.
+ * A class for creating a service discovery request for use with
+ * {@link WifiP2pManager#addServiceRequest} and {@link WifiP2pManager#removeServiceRequest}
*
- * <p>This class is used when you create customized service discovery request.
- * e.g) vendor specific request/ws discovery etc.
+ * <p>This class is used to create service discovery request for custom
+ * vendor specific service discovery protocol {@link WifiP2pServiceInfo#SERVICE_TYPE_VENDOR_SPECIFIC}
+ * or to search all service protocols {@link WifiP2pServiceInfo#SERVICE_TYPE_ALL}.
*
- * <p>If you want to create UPnP or Bonjour service request, then you had better
- * use {@link WifiP2pUpnpServiceRequest} or {@link WifiP2pBonjourServiceRequest}.
+ * <p>For the purpose of creating a UPnP or Bonjour service request, use
+ * {@link WifiP2pUpnpServiceRequest} or {@link WifiP2pDnsSdServiceRequest} respectively.
*
- * @see WifiP2pUpnpServiceRequest
- * @see WifiP2pBonjourServiceRequest
- * @hide
+ * {@see WifiP2pManager}
+ * {@see WifiP2pUpnpServiceRequest}
+ * {@see WifiP2pDnsSdServiceRequest}
*/
public class WifiP2pServiceRequest implements Parcelable {
/**
- * Service type. It's defined in table63 in Wi-Fi Direct specification.
+ * Service discovery protocol. It's defined in table63 in Wi-Fi Direct specification.
*/
- private int mServiceType;
+ private int mProtocolType;
/**
* The length of the service request TLV.
@@ -56,7 +58,7 @@
/**
* The hex dump string of query data for the requested service information.
*
- * e.g) Bonjour apple file sharing over tcp (dns name=_afpovertcp._tcp.local.)
+ * e.g) DnsSd apple file sharing over tcp (dns name=_afpovertcp._tcp.local.)
* 0b5f6166706f766572746370c00c000c01
*/
private String mQuery;
@@ -64,14 +66,14 @@
/**
* This constructor is only used in newInstance().
*
- * @param serviceType service discovery type.
+ * @param protocolType service discovery protocol.
* @param query The part of service specific query.
* @hide
*/
- protected WifiP2pServiceRequest(int serviceType, String query) {
+ protected WifiP2pServiceRequest(int protocolType, String query) {
validateQuery(query);
- mServiceType = serviceType;
+ mProtocolType = protocolType;
mQuery = query;
if (query != null) {
mLength = query.length()/2 + 2;
@@ -90,7 +92,7 @@
*/
private WifiP2pServiceRequest(int serviceType, int length,
int transId, String query) {
- mServiceType = serviceType;
+ mProtocolType = serviceType;
mLength = length;
mTransId = transId;
mQuery = query;
@@ -134,7 +136,7 @@
// length is retained as little endian format.
sb.append(String.format("%02x", (mLength) & 0xff));
sb.append(String.format("%02x", (mLength >> 8) & 0xff));
- sb.append(String.format("%02x", mServiceType));
+ sb.append(String.format("%02x", mProtocolType));
sb.append(String.format("%02x", mTransId));
if (mQuery != null) {
sb.append(mQuery);
@@ -177,42 +179,34 @@
}
/**
- * Create service discovery request.
+ * Create a service discovery request.
*
- * <p>The created instance is set to framework by
- * {@link WifiP2pManager#addLocalService}.
+ * @param protocolType can be {@link WifiP2pServiceInfo#SERVICE_TYPE_ALL}
+ * or {@link WifiP2pServiceInfo#SERVICE_TYPE_VENDOR_SPECIFIC}.
+ * In order to create a UPnP or Bonjour service request, use
+ * {@link WifiP2pUpnpServiceRequest} or {@link WifiP2pDnsSdServiceRequest}
+ * respectively
*
- * @param serviceType service type.<br>
- * e.g) {@link WifiP2pServiceInfo#SERVICE_TYPE_ALL},
- * {@link WifiP2pServiceInfo#SERVICE_TYPE_WS_DISCOVERY},
- * {@link WifiP2pServiceInfo#SERVICE_TYPE_VENDOR_SPECIFIC}.
- * If you want to use UPnP or Bonjour, you create the request by
- * {@link WifiP2pUpnpServiceRequest} or {@link WifiP2pBonjourServiceRequest}
- *
- * @param query hex string. if null, all specified services are requested.
+ * @param queryData hex string that is vendor specific. Can be null.
* @return service discovery request.
*/
- public static WifiP2pServiceRequest newInstance(int serviceType, String query) {
- return new WifiP2pServiceRequest(serviceType, query);
+ public static WifiP2pServiceRequest newInstance(int protocolType, String queryData) {
+ return new WifiP2pServiceRequest(protocolType, queryData);
}
/**
- * Create all service discovery request.
+ * Create a service discovery request.
*
- * <p>The created instance is set to framework by
- * {@link WifiP2pManager#addLocalService}.
- *
- * @param serviceType service type.<br>
- * e.g) {@link WifiP2pServiceInfo#SERVICE_TYPE_ALL},
- * {@link WifiP2pServiceInfo#SERVICE_TYPE_WS_DISCOVERY},
- * {@link WifiP2pServiceInfo#SERVICE_TYPE_VENDOR_SPECIFIC}.
- * If you want to use UPnP or Bonjour, you create the request by
- * {@link WifiP2pUpnpServiceRequest} or {@link WifiP2pBonjourServiceRequest}
+ * @param protocolType can be {@link WifiP2pServiceInfo#SERVICE_TYPE_ALL}
+ * or {@link WifiP2pServiceInfo#SERVICE_TYPE_VENDOR_SPECIFIC}.
+ * In order to create a UPnP or Bonjour service request, use
+ * {@link WifiP2pUpnpServiceRequest} or {@link WifiP2pDnsSdServiceRequest}
+ * respectively
*
* @return service discovery request.
*/
- public static WifiP2pServiceRequest newInstance(int serviceType) {
- return new WifiP2pServiceRequest(serviceType, null);
+ public static WifiP2pServiceRequest newInstance(int protocolType ) {
+ return new WifiP2pServiceRequest(protocolType, null);
}
@Override
@@ -230,7 +224,7 @@
* Not compare transaction id.
* Transaction id may be changed on each service discovery operation.
*/
- if ((req.mServiceType != mServiceType) ||
+ if ((req.mProtocolType != mProtocolType) ||
(req.mLength != mLength)) {
return false;
}
@@ -246,7 +240,7 @@
@Override
public int hashCode() {
int result = 17;
- result = 31 * result + mServiceType;
+ result = 31 * result + mProtocolType;
result = 31 * result + mLength;
result = 31 * result + (mQuery == null ? 0 : mQuery.hashCode());
return result;
@@ -259,7 +253,7 @@
/** Implement the Parcelable interface {@hide} */
public void writeToParcel(Parcel dest, int flags) {
- dest.writeInt(mServiceType);
+ dest.writeInt(mProtocolType);
dest.writeInt(mLength);
dest.writeInt(mTransId);
dest.writeString(mQuery);
diff --git a/wifi/java/android/net/wifi/p2p/nsd/WifiP2pServiceResponse.java b/wifi/java/android/net/wifi/p2p/nsd/WifiP2pServiceResponse.java
index 0855eae..ac31663 100644
--- a/wifi/java/android/net/wifi/p2p/nsd/WifiP2pServiceResponse.java
+++ b/wifi/java/android/net/wifi/p2p/nsd/WifiP2pServiceResponse.java
@@ -246,7 +246,7 @@
WifiP2pServiceResponse resp;
if (type == WifiP2pServiceInfo.SERVICE_TYPE_BONJOUR) {
- resp = WifiP2pBonjourServiceResponse.newInstance(status,
+ resp = WifiP2pDnsSdServiceResponse.newInstance(status,
transId, dev, data);
} else if (type == WifiP2pServiceInfo.SERVICE_TYPE_UPNP) {
resp = WifiP2pUpnpServiceResponse.newInstance(status,
@@ -373,7 +373,7 @@
in.readByteArray(data);
}
if (type == WifiP2pServiceInfo.SERVICE_TYPE_BONJOUR) {
- return WifiP2pBonjourServiceResponse.newInstance(status,
+ return WifiP2pDnsSdServiceResponse.newInstance(status,
transId, dev, data);
} else if (type == WifiP2pServiceInfo.SERVICE_TYPE_UPNP) {
return WifiP2pUpnpServiceResponse.newInstance(status,
diff --git a/wifi/java/android/net/wifi/p2p/nsd/WifiP2pUpnpServiceInfo.java b/wifi/java/android/net/wifi/p2p/nsd/WifiP2pUpnpServiceInfo.java
index 4d40e81..40a0d61 100644
--- a/wifi/java/android/net/wifi/p2p/nsd/WifiP2pUpnpServiceInfo.java
+++ b/wifi/java/android/net/wifi/p2p/nsd/WifiP2pUpnpServiceInfo.java
@@ -21,8 +21,13 @@
import java.util.UUID;
/**
- * The class for UPnP service information.
- * @hide
+ * A class for storing Upnp service information that is advertised
+ * over a Wi-Fi peer-to-peer setup.
+ *
+ * {@see android.net.wifi.p2p.WifiP2pManager#addLocalService}
+ * {@see android.net.wifi.p2p.WifiP2pManager#removeLocalService}
+ * {@see WifiP2pServiceInfo}
+ * {@see WifiP2pDnsSdServiceInfo}
*/
public class WifiP2pUpnpServiceInfo extends WifiP2pServiceInfo {
diff --git a/wifi/java/android/net/wifi/p2p/nsd/WifiP2pUpnpServiceRequest.java b/wifi/java/android/net/wifi/p2p/nsd/WifiP2pUpnpServiceRequest.java
index b97637a..b5cf144 100644
--- a/wifi/java/android/net/wifi/p2p/nsd/WifiP2pUpnpServiceRequest.java
+++ b/wifi/java/android/net/wifi/p2p/nsd/WifiP2pUpnpServiceRequest.java
@@ -16,9 +16,15 @@
package android.net.wifi.p2p.nsd;
+import android.net.wifi.p2p.WifiP2pManager;
+
/**
- * The class for a request of upnp service discovery.
- * @hide
+ * A class for creating a Upnp service discovery request for use with
+ * {@link WifiP2pManager#addServiceRequest} and {@link WifiP2pManager#removeServiceRequest}
+ *
+ * {@see WifiP2pManager}
+ * {@see WifiP2pServiceRequest}
+ * {@see WifiP2pDnsSdServiceRequest}
*/
public class WifiP2pUpnpServiceRequest extends WifiP2pServiceRequest {