Merge "Adding mobile microbenchmark tests." into ics-mr1
diff --git a/api/current.txt b/api/current.txt
index f07e66b..f33c6cb 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -10696,6 +10696,7 @@
field public static final int METADATA_KEY_GENRE = 6; // 0x6
field public static final int METADATA_KEY_HAS_AUDIO = 16; // 0x10
field public static final int METADATA_KEY_HAS_VIDEO = 17; // 0x11
+ field public static final int METADATA_KEY_LOCATION = 23; // 0x17
field public static final int METADATA_KEY_MIMETYPE = 12; // 0xc
field public static final int METADATA_KEY_NUM_TRACKS = 10; // 0xa
field public static final int METADATA_KEY_TITLE = 7; // 0x7
@@ -17432,7 +17433,6 @@
field public static final java.lang.String LOCK_PATTERN_TACTILE_FEEDBACK_ENABLED = "lock_pattern_tactile_feedback_enabled";
field public static final java.lang.String LOCK_PATTERN_VISIBLE = "lock_pattern_visible_pattern";
field public static final deprecated java.lang.String LOGGING_ID = "logging_id";
- field public static final java.lang.String MESSAGING_APP_NOTIFICATIONS = "messaging_app_notifications";
field public static final java.lang.String NETWORK_PREFERENCE = "network_preference";
field public static final java.lang.String PARENTAL_CONTROL_ENABLED = "parental_control_enabled";
field public static final java.lang.String PARENTAL_CONTROL_LAST_UPDATE = "parental_control_last_update";
@@ -18891,7 +18891,8 @@
method public int playSilence(long, int, java.util.HashMap<java.lang.String, java.lang.String>);
method public deprecated int setEngineByPackageName(java.lang.String);
method public int setLanguage(java.util.Locale);
- method public int setOnUtteranceCompletedListener(android.speech.tts.TextToSpeech.OnUtteranceCompletedListener);
+ method public deprecated int setOnUtteranceCompletedListener(android.speech.tts.TextToSpeech.OnUtteranceCompletedListener);
+ method public int setOnUtteranceProgressListener(android.speech.tts.UtteranceProgressListener);
method public int setPitch(float);
method public int setSpeechRate(float);
method public void shutdown();
@@ -18964,6 +18965,13 @@
method protected abstract void onSynthesizeText(android.speech.tts.SynthesisRequest, android.speech.tts.SynthesisCallback);
}
+ public abstract class UtteranceProgressListener {
+ ctor public UtteranceProgressListener();
+ method public abstract void onDone(java.lang.String);
+ method public abstract void onError(java.lang.String);
+ method public abstract void onStart(java.lang.String);
+ }
+
}
package android.telephony {
diff --git a/cmds/bootanimation/BootAnimation.cpp b/cmds/bootanimation/BootAnimation.cpp
index d816e7c..154dbb8 100644
--- a/cmds/bootanimation/BootAnimation.cpp
+++ b/cmds/bootanimation/BootAnimation.cpp
@@ -42,6 +42,7 @@
#include <surfaceflinger/ISurfaceComposerClient.h>
#include <core/SkBitmap.h>
+#include <core/SkStream.h>
#include <images/SkImageDecoder.h>
#include <GLES/gl.h>
@@ -150,9 +151,15 @@
//StopWatch watch("blah");
SkBitmap bitmap;
- SkImageDecoder::DecodeMemory(buffer, len,
- &bitmap, SkBitmap::kRGB_565_Config,
- SkImageDecoder::kDecodePixels_Mode);
+ SkMemoryStream stream(buffer, len);
+ SkImageDecoder* codec = SkImageDecoder::Factory(&stream);
+ codec->setDitherImage(false);
+ if (codec) {
+ codec->decode(&stream, &bitmap,
+ SkBitmap::kRGB_565_Config,
+ SkImageDecoder::kDecodePixels_Mode);
+ delete codec;
+ }
// ensure we can call getPixels(). No need to call unlock, since the
// bitmap will go out of scope when we return from this method.
diff --git a/core/java/android/animation/LayoutTransition.java b/core/java/android/animation/LayoutTransition.java
index f383af9..7f0ea99 100644
--- a/core/java/android/animation/LayoutTransition.java
+++ b/core/java/android/animation/LayoutTransition.java
@@ -657,6 +657,15 @@
*/
private void setupChangeAnimation(final ViewGroup parent, final int changeReason,
Animator baseAnimator, final long duration, final View child) {
+
+ // If we already have a listener for this child, then we've already set up the
+ // changing animation we need. Multiple calls for a child may occur when several
+ // add/remove operations are run at once on a container; each one will trigger
+ // changes for the existing children in the container.
+ if (layoutChangeListenerMap.get(child) != null) {
+ return;
+ }
+
// Make a copy of the appropriate animation
final Animator anim = baseAnimator.clone();
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index a4714ca..f9896f7 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -45,6 +45,7 @@
import android.net.IConnectivityManager;
import android.net.Proxy;
import android.net.ProxyProperties;
+import android.opengl.GLUtils;
import android.os.AsyncTask;
import android.os.Bundle;
import android.os.Debug;
@@ -3714,6 +3715,24 @@
}
}
+ private void setupGraphicsSupport(LoadedApk info) {
+ try {
+ int uid = Process.myUid();
+ String[] packages = getPackageManager().getPackagesForUid(uid);
+
+ // If there are several packages in this application we won't
+ // initialize the graphics disk caches
+ if (packages.length == 1) {
+ ContextImpl appContext = new ContextImpl();
+ appContext.init(info, null, this);
+
+ HardwareRenderer.setupDiskCache(appContext.getCacheDir());
+ }
+ } catch (RemoteException e) {
+ // Ignore
+ }
+ }
+
private void handleBindApplication(AppBindData data) {
mBoundApplication = data;
mConfiguration = new Configuration(data.config);
@@ -3737,7 +3756,7 @@
HardwareRenderer.disable(false);
}
}
-
+
if (mProfiler.profileFd != null) {
mProfiler.startProfiling();
}
@@ -3773,6 +3792,8 @@
data.info = getPackageInfoNoCheck(data.appInfo, data.compatInfo);
+ setupGraphicsSupport(data.info);
+
/**
* For system applications on userdebug/eng builds, log stack
* traces of disk and network access to dropbox for analysis.
diff --git a/core/java/android/app/LoadedApk.java b/core/java/android/app/LoadedApk.java
index 522f477..0c6baeb 100644
--- a/core/java/android/app/LoadedApk.java
+++ b/core/java/android/app/LoadedApk.java
@@ -901,6 +901,7 @@
private RuntimeException mUnbindLocation;
private boolean mDied;
+ private boolean mForgotten;
private static class ConnectionInfo {
IBinder binder;
@@ -959,6 +960,7 @@
ci.binder.unlinkToDeath(ci.deathMonitor, 0);
}
mActiveConnections.clear();
+ mForgotten = true;
}
}
@@ -1020,6 +1022,11 @@
ServiceDispatcher.ConnectionInfo info;
synchronized (this) {
+ if (mForgotten) {
+ // We unbound before receiving the connection; ignore
+ // any connection received.
+ return;
+ }
old = mActiveConnections.get(name);
if (old != null && old.binder == service) {
// Huh, already have this one. Oh well!
diff --git a/core/java/android/app/WallpaperManager.java b/core/java/android/app/WallpaperManager.java
index f81ea81..b1c1f30 100644
--- a/core/java/android/app/WallpaperManager.java
+++ b/core/java/android/app/WallpaperManager.java
@@ -212,7 +212,11 @@
*/
mHandler.sendEmptyMessage(MSG_CLEAR_WALLPAPER);
}
-
+
+ public Handler getHandler() {
+ return mHandler;
+ }
+
public Bitmap peekWallpaperBitmap(Context context, boolean returnDefault) {
synchronized (this) {
if (mWallpaper != null) {
@@ -604,7 +608,7 @@
// Ignore
}
}
-
+
/**
* Set the position of the current wallpaper within any larger space, when
* that wallpaper is visible behind the given window. The X and Y offsets
@@ -619,16 +623,26 @@
* @param yOffset The offset along the Y dimension, from 0 to 1.
*/
public void setWallpaperOffsets(IBinder windowToken, float xOffset, float yOffset) {
- try {
- //Log.v(TAG, "Sending new wallpaper offsets from app...");
- ViewRootImpl.getWindowSession(mContext.getMainLooper()).setWallpaperPosition(
- windowToken, xOffset, yOffset, mWallpaperXStep, mWallpaperYStep);
- //Log.v(TAG, "...app returning after sending offsets!");
- } catch (RemoteException e) {
- // Ignore.
- }
+ final IBinder fWindowToken = windowToken;
+ final float fXOffset = xOffset;
+ final float fYOffset = yOffset;
+ sGlobals.getHandler().post(new Runnable() {
+ public void run() {
+ try {
+ //Log.v(TAG, "Sending new wallpaper offsets from app...");
+ ViewRootImpl.getWindowSession(mContext.getMainLooper()).setWallpaperPosition(
+ fWindowToken, fXOffset, fYOffset, mWallpaperXStep, mWallpaperYStep);
+ //Log.v(TAG, "...app returning after sending offsets!");
+ } catch (RemoteException e) {
+ // Ignore.
+ } catch (IllegalArgumentException e) {
+ // Since this is being posted, it's possible that this windowToken is no longer
+ // valid, for example, if setWallpaperOffsets is called just before rotation.
+ }
+ }
+ });
}
-
+
/**
* For applications that use multiple virtual screens showing a wallpaper,
* specify the step size between virtual screens. For example, if the
diff --git a/core/java/android/bluetooth/BluetoothDeviceProfileState.java b/core/java/android/bluetooth/BluetoothDeviceProfileState.java
index 7addd4a..b1d0070 100644
--- a/core/java/android/bluetooth/BluetoothDeviceProfileState.java
+++ b/core/java/android/bluetooth/BluetoothDeviceProfileState.java
@@ -86,7 +86,7 @@
private static final int CONNECTION_ACCESS_REQUEST_REPLY = 104;
private static final int CONNECTION_ACCESS_REQUEST_EXPIRY = 105;
- private static final int CONNECT_OTHER_PROFILES_DELAY = 4000; // 4 secs
+ public static final int CONNECT_OTHER_PROFILES_DELAY = 4000; // 4 secs
private static final int CONNECTION_ACCESS_REQUEST_EXPIRY_TIMEOUT = 7000; // 7 secs
private static final int CONNECTION_ACCESS_UNDEFINED = -1;
private static final long INIT_INCOMING_REJECT_TIMER = 1000; // 1 sec
diff --git a/core/java/android/bluetooth/IBluetooth.aidl b/core/java/android/bluetooth/IBluetooth.aidl
index fefeb93..deea2b8 100644
--- a/core/java/android/bluetooth/IBluetooth.aidl
+++ b/core/java/android/bluetooth/IBluetooth.aidl
@@ -90,7 +90,7 @@
boolean connectHeadset(String address);
boolean disconnectHeadset(String address);
- boolean notifyIncomingConnection(String address);
+ boolean notifyIncomingConnection(String address, boolean rejected);
// HID profile APIs
boolean connectInputDevice(in BluetoothDevice device);
diff --git a/core/java/android/content/res/XmlBlock.java b/core/java/android/content/res/XmlBlock.java
index ad1bfb2..bea6529 100644
--- a/core/java/android/content/res/XmlBlock.java
+++ b/core/java/android/content/res/XmlBlock.java
@@ -484,7 +484,7 @@
private final AssetManager mAssets;
private final int mNative;
- private final StringBlock mStrings;
+ /*package*/ final StringBlock mStrings;
private boolean mOpen = true;
private int mOpenCount = 1;
@@ -494,9 +494,9 @@
private static final native int nativeGetStringBlock(int obj);
private static final native int nativeCreateParseState(int obj);
- private static final native int nativeNext(int state);
+ /*package*/ static final native int nativeNext(int state);
private static final native int nativeGetNamespace(int state);
- private static final native int nativeGetName(int state);
+ /*package*/ static final native int nativeGetName(int state);
private static final native int nativeGetText(int state);
private static final native int nativeGetLineNumber(int state);
private static final native int nativeGetAttributeCount(int state);
diff --git a/core/java/android/hardware/Camera.java b/core/java/android/hardware/Camera.java
index 48adfad..3becec0 100644
--- a/core/java/android/hardware/Camera.java
+++ b/core/java/android/hardware/Camera.java
@@ -22,9 +22,12 @@
import android.graphics.Point;
import android.graphics.Rect;
import android.graphics.SurfaceTexture;
+import android.media.AudioManager;
+import android.media.MediaPlayer;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
+import android.os.SystemProperties;
import android.util.Log;
import android.view.Surface;
import android.view.SurfaceHolder;
@@ -154,6 +157,7 @@
private boolean mOneShot;
private boolean mWithBuffer;
private boolean mFaceDetectionRunning = false;
+ private boolean mReleased = false;
/**
* Broadcast Action: A new picture is taken by the camera, and the entry of
@@ -303,7 +307,7 @@
}
protected void finalize() {
- native_release();
+ release();
}
private native final void native_setup(Object camera_this, int cameraId);
@@ -318,6 +322,15 @@
public final void release() {
native_release();
mFaceDetectionRunning = false;
+ if (mCameraSoundPlayers != null) {
+ for (CameraSoundPlayer csp: mCameraSoundPlayers) {
+ if (csp != null) {
+ csp.release();
+ }
+ }
+ mCameraSoundPlayers = null;
+ }
+ mReleased = true;
}
/**
@@ -2354,7 +2367,7 @@
*
* <p>The reference code is as follows.
*
- * <pre>
+ * <pre>
* public void onOrientationChanged(int orientation) {
* if (orientation == ORIENTATION_UNKNOWN) return;
* android.hardware.Camera.CameraInfo info =
@@ -2369,7 +2382,7 @@
* }
* mParameters.setRotation(rotation);
* }
- * </pre>
+ * </pre>
*
* @param rotation The rotation angle in degrees relative to the
* orientation of the camera. Rotation can only be 0,
@@ -3452,4 +3465,194 @@
return result;
}
};
+
+ /**
+ * <p>The set of default system sounds for camera actions. Use this with
+ * {@link #playSound} to play an appropriate sound when implementing a
+ * custom still or video recording mechanism through the preview
+ * callbacks.</p>
+ *
+ * <p>There is no need to play sounds when using {@link #takePicture} or
+ * {@link android.media.MediaRecorder} for still images or video,
+ * respectively, as these play their own sounds when needed.</p>
+ *
+ * @see #playSound
+ * @hide
+ */
+ public static class Sound {
+ /**
+ * The sound used by {@link android.hardware.Camera#takePicture} to
+ * indicate still image capture.
+ */
+ public static final int SHUTTER_CLICK = 0;
+
+ /**
+ * A sound to indicate that focusing has completed. Because deciding
+ * when this occurs is application-dependent, this sound is not used by
+ * any methods in the Camera class.
+ */
+ public static final int FOCUS_COMPLETE = 1;
+
+ /**
+ * The sound used by {@link android.media.MediaRecorder#start} to
+ * indicate the start of video recording.
+ */
+ public static final int START_VIDEO_RECORDING = 2;
+
+ /**
+ * The sound used by {@link android.media.MediaRecorder#stop} to
+ * indicate the end of video recording.
+ */
+ public static final int STOP_VIDEO_RECORDING = 3;
+
+ private static final int NUM_SOUNDS = 4;
+ };
+
+ /**
+ * <p>Play one of the predefined platform sounds for camera actions.</p>
+ *
+ * <p>Use this method to play a platform-specific sound for various camera
+ * actions. The sound playing is done asynchronously, with the same behavior
+ * and content as the sounds played by {@link #takePicture takePicture},
+ * {@link android.media.MediaRecorder#start MediaRecorder.start}, and
+ * {@link android.media.MediaRecorder#stop MediaRecorder.stop}.</p>
+ *
+ * <p>Using this method makes it easy to match the default device sounds
+ * when recording or capturing data through the preview callbacks
+ * ({@link #setPreviewCallback setPreviewCallback},
+ * {@link #setPreviewTexture setPreviewTexture}).</p>
+ *
+ * @param soundId The type of sound to play, selected from the options in
+ * {@link android.hardware.Camera.Sound}
+ * @see android.hardware.Camera.Sound
+ * @see #takePicture
+ * @see android.media.MediaRecorder
+ * @hide
+ */
+ public void playSound(int soundId) {
+ if (mReleased) return;
+ if (mCameraSoundPlayers == null) {
+ mCameraSoundPlayers = new CameraSoundPlayer[Sound.NUM_SOUNDS];
+ }
+ if (mCameraSoundPlayers[soundId] == null) {
+ mCameraSoundPlayers[soundId] = new CameraSoundPlayer(soundId);
+ }
+ mCameraSoundPlayers[soundId].play();
+ }
+
+ private CameraSoundPlayer[] mCameraSoundPlayers;
+
+ private static class CameraSoundPlayer implements Runnable {
+ private int mSoundId;
+ private int mAudioStreamType;
+ private MediaPlayer mPlayer;
+ private Thread mThread;
+ private boolean mExit;
+ private int mPlayCount;
+
+ private static final String mShutterSound =
+ "/system/media/audio/ui/camera_click.ogg";
+ private static final String mFocusSound =
+ "/system/media/audio/ui/camera_focus.ogg";
+ private static final String mVideoStartSound =
+ "/system/media/audio/ui/VideoRecord.ogg";
+ private static final String mVideoStopSound =
+ "/system/media/audio/ui/VideoRecord.ogg";
+
+ @Override
+ public void run() {
+ String soundFilePath;
+ switch (mSoundId) {
+ case Sound.SHUTTER_CLICK:
+ soundFilePath = mShutterSound;
+ break;
+ case Sound.FOCUS_COMPLETE:
+ soundFilePath = mFocusSound;
+ break;
+ case Sound.START_VIDEO_RECORDING:
+ soundFilePath = mVideoStartSound;
+ break;
+ case Sound.STOP_VIDEO_RECORDING:
+ soundFilePath = mVideoStopSound;
+ break;
+ default:
+ Log.e(TAG, "Unknown sound " + mSoundId + " requested.");
+ return;
+ }
+ mPlayer = new MediaPlayer();
+ try {
+ mPlayer.setAudioStreamType(mAudioStreamType);
+ mPlayer.setDataSource(soundFilePath);
+ mPlayer.setLooping(false);
+ mPlayer.prepare();
+ } catch(IOException e) {
+ Log.e(TAG, "Error setting up sound " + mSoundId, e);
+ return;
+ }
+
+ while(true) {
+ try {
+ synchronized (this) {
+ while(true) {
+ if (mExit) {
+ return;
+ } else if (mPlayCount <= 0) {
+ wait();
+ } else {
+ mPlayCount--;
+ break;
+ }
+ }
+ }
+ mPlayer.start();
+ } catch (Exception e) {
+ Log.e(TAG, "Error playing sound " + mSoundId, e);
+ }
+ }
+ }
+
+ public CameraSoundPlayer(int soundId) {
+ mSoundId = soundId;
+ if (SystemProperties.get("ro.camera.sound.forced", "0").equals("0")) {
+ mAudioStreamType = AudioManager.STREAM_MUSIC;
+ } else {
+ mAudioStreamType = AudioManager.STREAM_SYSTEM_ENFORCED;
+ }
+ }
+
+ public void play() {
+ if (mThread == null) {
+ mThread = new Thread(this);
+ mThread.start();
+ }
+ synchronized (this) {
+ mPlayCount++;
+ notifyAll();
+ }
+ }
+
+ public void release() {
+ if (mThread != null) {
+ synchronized (this) {
+ mExit = true;
+ notifyAll();
+ }
+ try {
+ mThread.join();
+ } catch (InterruptedException e) {
+ }
+ mThread = null;
+ }
+ if (mPlayer != null) {
+ mPlayer.release();
+ mPlayer = null;
+ }
+ }
+
+ @Override
+ protected void finalize() {
+ release();
+ }
+ }
+
}
diff --git a/core/java/android/net/NetworkStats.java b/core/java/android/net/NetworkStats.java
index 3605652..f6e627c 100644
--- a/core/java/android/net/NetworkStats.java
+++ b/core/java/android/net/NetworkStats.java
@@ -464,6 +464,19 @@
* time, and that none of them have disappeared.
*/
public NetworkStats subtract(NetworkStats value) throws NonMonotonicException {
+ return subtract(value, false);
+ }
+
+ /**
+ * Subtract the given {@link NetworkStats}, effectively leaving the delta
+ * between two snapshots in time. Assumes that statistics rows collect over
+ * time, and that none of them have disappeared.
+ *
+ * @param clampNonMonotonic When non-monotonic stats are found, just clamp
+ * to 0 instead of throwing {@link NonMonotonicException}.
+ */
+ public NetworkStats subtract(NetworkStats value, boolean clampNonMonotonic)
+ throws NonMonotonicException {
final long deltaRealtime = this.elapsedRealtime - value.elapsedRealtime;
if (deltaRealtime < 0) {
throw new NonMonotonicException(this, value);
@@ -497,7 +510,15 @@
if (entry.rxBytes < 0 || entry.rxPackets < 0 || entry.txBytes < 0
|| entry.txPackets < 0 || entry.operations < 0) {
- throw new NonMonotonicException(this, i, value, j);
+ if (clampNonMonotonic) {
+ entry.rxBytes = Math.max(entry.rxBytes, 0);
+ entry.rxPackets = Math.max(entry.rxPackets, 0);
+ entry.txBytes = Math.max(entry.txBytes, 0);
+ entry.txPackets = Math.max(entry.txPackets, 0);
+ entry.operations = Math.max(entry.operations, 0);
+ } else {
+ throw new NonMonotonicException(this, i, value, j);
+ }
}
}
diff --git a/core/java/android/nfc/INfcAdapter.aidl b/core/java/android/nfc/INfcAdapter.aidl
index 016af58..0b93ad0 100644
--- a/core/java/android/nfc/INfcAdapter.aidl
+++ b/core/java/android/nfc/INfcAdapter.aidl
@@ -32,7 +32,7 @@
interface INfcAdapter
{
INfcTag getNfcTagInterface();
- INfcAdapterExtras getNfcAdapterExtrasInterface();
+ INfcAdapterExtras getNfcAdapterExtrasInterface(in String pkg);
int getState();
boolean disable();
diff --git a/core/java/android/nfc/INfcAdapterExtras.aidl b/core/java/android/nfc/INfcAdapterExtras.aidl
index 0c2a2fd..2b9d4f0 100644
--- a/core/java/android/nfc/INfcAdapterExtras.aidl
+++ b/core/java/android/nfc/INfcAdapterExtras.aidl
@@ -23,10 +23,10 @@
* {@hide}
*/
interface INfcAdapterExtras {
- Bundle open(IBinder b);
- Bundle close();
- Bundle transceive(in byte[] data_in);
- int getCardEmulationRoute();
- void setCardEmulationRoute(int route);
- void authenticate(in byte[] token);
+ Bundle open(in String pkg, IBinder b);
+ Bundle close(in String pkg, IBinder b);
+ Bundle transceive(in String pkg, in byte[] data_in);
+ int getCardEmulationRoute(in String pkg);
+ void setCardEmulationRoute(in String pkg, int route);
+ void authenticate(in String pkg, in byte[] token);
}
diff --git a/core/java/android/nfc/NfcAdapter.java b/core/java/android/nfc/NfcAdapter.java
index 33310df..a9f1685 100644
--- a/core/java/android/nfc/NfcAdapter.java
+++ b/core/java/android/nfc/NfcAdapter.java
@@ -16,6 +16,8 @@
package android.nfc;
+import java.util.HashMap;
+
import android.annotation.SdkConstant;
import android.annotation.SdkConstant.SdkConstantType;
import android.app.Activity;
@@ -197,15 +199,21 @@
static INfcTag sTagService;
/**
- * NfcAdapter is currently a singleton, and does not require a context.
- * However all the public API's are future-proofed to require a context.
- * If we start using that then we'll need to keep a HashMap of
- * Context.getApplicationContext() -> NfcAdapter, such that NfcAdapter
- * is a singleton within each application context.
+ * The NfcAdapter object for each application context.
+ * There is a 1-1 relationship between application context and
+ * NfcAdapter object.
*/
- static NfcAdapter sSingleton; // protected by NfcAdapter.class
+ static HashMap<Context, NfcAdapter> sNfcAdapters = new HashMap(); //guard by NfcAdapter.class
+
+ /**
+ * NfcAdapter used with a null context. This ctor was deprecated but we have
+ * to support it for backwards compatibility. New methods that require context
+ * might throw when called on the null-context NfcAdapter.
+ */
+ static NfcAdapter sNullContextNfcAdapter; // protected by NfcAdapter.class
final NfcActivityManager mNfcActivityManager;
+ final Context mContext;
/**
* A callback to be invoked when the system successfully delivers your {@link NdefMessage}
@@ -280,12 +288,12 @@
}
/**
- * Returns the singleton, or throws if NFC is not available.
+ * Returns the NfcAdapter for application context,
+ * or throws if NFC is not available.
+ * @hide
*/
- static synchronized NfcAdapter getSingleton() {
+ public static synchronized NfcAdapter getNfcAdapter(Context context) {
if (!sIsInitialized) {
- sIsInitialized = true;
-
/* is this device meant to have NFC */
if (!hasNfcFeature()) {
Log.v(TAG, "this device does not have NFC support");
@@ -303,12 +311,21 @@
Log.e(TAG, "could not retrieve NFC Tag service");
throw new UnsupportedOperationException();
}
- sSingleton = new NfcAdapter();
+
+ sIsInitialized = true;
}
- if (sSingleton == null) {
- throw new UnsupportedOperationException();
+ if (context == null) {
+ if (sNullContextNfcAdapter == null) {
+ sNullContextNfcAdapter = new NfcAdapter(null);
+ }
+ return sNullContextNfcAdapter;
}
- return sSingleton;
+ NfcAdapter adapter = sNfcAdapters.get(context);
+ if (adapter == null) {
+ adapter = new NfcAdapter(context);
+ sNfcAdapters.put(context, adapter);
+ }
+ return adapter;
}
/** get handle to NFC service interface */
@@ -336,6 +353,10 @@
* @return the default NFC adapter, or null if no NFC adapter exists
*/
public static NfcAdapter getDefaultAdapter(Context context) {
+ if (context == null) {
+ throw new IllegalArgumentException("context cannot be null");
+ }
+ context = context.getApplicationContext();
/* use getSystemService() instead of just instantiating to take
* advantage of the context's cached NfcManager & NfcAdapter */
NfcManager manager = (NfcManager) context.getSystemService(Context.NFC_SERVICE);
@@ -343,25 +364,30 @@
}
/**
- * Get a handle to the default NFC Adapter on this Android device.
- * <p>
- * Most Android devices will only have one NFC Adapter (NFC Controller).
- *
- * @return the default NFC adapter, or null if no NFC adapter exists
+ * Legacy NfcAdapter getter, always use {@link #getDefaultAdapter(Context)} instead.<p>
+ * This method was deprecated at API level 10 (Gingerbread MR1) because a context is required
+ * for many NFC API methods. Those methods will fail when called on an NfcAdapter
+ * object created from this method.<p>
* @deprecated use {@link #getDefaultAdapter(Context)}
*/
@Deprecated
public static NfcAdapter getDefaultAdapter() {
Log.w(TAG, "WARNING: NfcAdapter.getDefaultAdapter() is deprecated, use " +
"NfcAdapter.getDefaultAdapter(Context) instead", new Exception());
- return getSingleton();
+
+ return NfcAdapter.getNfcAdapter(null);
+ }
+
+ NfcAdapter(Context context) {
+ mContext = context;
+ mNfcActivityManager = new NfcActivityManager(this);
}
/**
- * Does not currently need a context.
+ * @hide
*/
- NfcAdapter() {
- mNfcActivityManager = new NfcActivityManager(this);
+ public Context getContext() {
+ return mContext;
}
/**
@@ -768,6 +794,61 @@
}
/**
+ * TODO: Remove this once pre-built apk's (Maps, Youtube etc) are updated
+ * @deprecated use {@link CreateNdefMessageCallback} or {@link OnNdefPushCompleteCallback}
+ * @hide
+ */
+ @Deprecated
+ public interface NdefPushCallback {
+ /**
+ * @deprecated use {@link CreateNdefMessageCallback} instead
+ */
+ @Deprecated
+ NdefMessage createMessage();
+ /**
+ * @deprecated use{@link OnNdefPushCompleteCallback} instead
+ */
+ @Deprecated
+ void onMessagePushed();
+ }
+
+ /**
+ * TODO: Remove this
+ * Converts new callbacks to old callbacks.
+ */
+ static final class LegacyCallbackWrapper implements CreateNdefMessageCallback,
+ OnNdefPushCompleteCallback {
+ final NdefPushCallback mLegacyCallback;
+ LegacyCallbackWrapper(NdefPushCallback legacyCallback) {
+ mLegacyCallback = legacyCallback;
+ }
+ @Override
+ public void onNdefPushComplete(NfcEvent event) {
+ mLegacyCallback.onMessagePushed();
+ }
+ @Override
+ public NdefMessage createNdefMessage(NfcEvent event) {
+ return mLegacyCallback.createMessage();
+ }
+ }
+
+ /**
+ * TODO: Remove this once pre-built apk's (Maps, Youtube etc) are updated
+ * @deprecated use {@link #setNdefPushMessageCallback} instead
+ * @hide
+ */
+ @Deprecated
+ public void enableForegroundNdefPush(Activity activity, final NdefPushCallback callback) {
+ if (activity == null || callback == null) {
+ throw new NullPointerException();
+ }
+ enforceResumed(activity);
+ LegacyCallbackWrapper callbackWrapper = new LegacyCallbackWrapper(callback);
+ mNfcActivityManager.setNdefPushMessageCallback(activity, callbackWrapper);
+ mNfcActivityManager.setOnNdefPushCompleteCallback(activity, callbackWrapper);
+ }
+
+ /**
* Enable NDEF Push feature.
* <p>This API is for the Settings application.
* @hide
@@ -820,8 +901,12 @@
* @hide
*/
public INfcAdapterExtras getNfcAdapterExtrasInterface() {
+ if (mContext == null) {
+ throw new UnsupportedOperationException("You need a context on NfcAdapter to use the "
+ + " NFC extras APIs");
+ }
try {
- return sService.getNfcAdapterExtrasInterface();
+ return sService.getNfcAdapterExtrasInterface(mContext.getPackageName());
} catch (RemoteException e) {
attemptDeadServiceRecovery(e);
return null;
diff --git a/core/java/android/nfc/NfcManager.java b/core/java/android/nfc/NfcManager.java
index 300ab45..6ec2e21 100644
--- a/core/java/android/nfc/NfcManager.java
+++ b/core/java/android/nfc/NfcManager.java
@@ -39,8 +39,9 @@
*/
public NfcManager(Context context) {
NfcAdapter adapter;
+ context = context.getApplicationContext();
try {
- adapter = NfcAdapter.getSingleton();
+ adapter = NfcAdapter.getNfcAdapter(context);
} catch (UnsupportedOperationException e) {
adapter = null;
}
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 769776e..b032169 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -4077,13 +4077,6 @@
"contacts_preauth_uri_expiration";
/**
- * Whether the Messaging app posts notifications.
- * 0=disabled. 1=enabled.
- */
- public static final String MESSAGING_APP_NOTIFICATIONS = "messaging_app_notifications";
-
-
- /**
* This are the settings to be backed up.
*
* NOTE: Settings are backed up and restored in the order they appear
@@ -4120,8 +4113,7 @@
MOUNT_UMS_NOTIFY_ENABLED,
UI_NIGHT_MODE,
LOCK_SCREEN_OWNER_INFO,
- LOCK_SCREEN_OWNER_INFO_ENABLED,
- MESSAGING_APP_NOTIFICATIONS
+ LOCK_SCREEN_OWNER_INFO_ENABLED
};
/**
diff --git a/core/java/android/provider/Telephony.java b/core/java/android/provider/Telephony.java
index 8eb9da1..0e6d07d 100755
--- a/core/java/android/provider/Telephony.java
+++ b/core/java/android/provider/Telephony.java
@@ -1838,15 +1838,5 @@
public static final String EXTRA_PLMN = "plmn";
public static final String EXTRA_SHOW_SPN = "showSpn";
public static final String EXTRA_SPN = "spn";
-
- /**
- * Activity Action: Shows a dialog to turn off Messaging app notification.
- * <p>Input: Nothing.
- * <p>Output: Nothing.
- */
- @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
- public static final String ACTION_MESSAGING_APP_NOTIFICATIONS =
- "android.provider.Telephony.MESSAGING_APP_NOTIFICATIONS";
-
}
}
diff --git a/core/java/android/server/BluetoothEventLoop.java b/core/java/android/server/BluetoothEventLoop.java
index 1b473ec..aa62cd7 100644
--- a/core/java/android/server/BluetoothEventLoop.java
+++ b/core/java/android/server/BluetoothEventLoop.java
@@ -784,11 +784,12 @@
// machine. We don't handle AVCTP signals currently. We only send
// intents for AVDTP state changes. We need to handle both of them in
// some cases. For now, just don't move to incoming state in this case.
- mBluetoothService.notifyIncomingA2dpConnection(address);
+ mBluetoothService.notifyIncomingA2dpConnection(address, true);
} else {
Log.i(TAG, "" + authorized +
"Incoming A2DP / AVRCP connection from " + address);
mA2dp.allowIncomingConnect(device, authorized);
+ mBluetoothService.notifyIncomingA2dpConnection(address, false);
}
} else if (BluetoothUuid.isInputDevice(uuid)) {
// We can have more than 1 input device connected.
diff --git a/core/java/android/server/BluetoothService.java b/core/java/android/server/BluetoothService.java
index 9ca5847..d604a01 100755
--- a/core/java/android/server/BluetoothService.java
+++ b/core/java/android/server/BluetoothService.java
@@ -89,7 +89,7 @@
private int mNativeData;
private BluetoothEventLoop mEventLoop;
- private BluetoothHeadset mBluetoothHeadset;
+ private BluetoothHeadset mHeadsetProxy;
private BluetoothInputDevice mInputDevice;
private BluetoothPan mPan;
private boolean mIsAirplaneSensitive;
@@ -605,6 +605,7 @@
}
mBondState.initBondState();
initProfileState();
+ getProfileProxy();
}
/**
@@ -1766,8 +1767,8 @@
private void dumpHeadsetService(PrintWriter pw) {
pw.println("\n--Headset Service--");
- if (mBluetoothHeadset != null) {
- List<BluetoothDevice> deviceList = mBluetoothHeadset.getConnectedDevices();
+ if (mHeadsetProxy != null) {
+ List<BluetoothDevice> deviceList = mHeadsetProxy.getConnectedDevices();
if (deviceList.size() == 0) {
pw.println("No headsets connected");
} else {
@@ -1775,21 +1776,20 @@
pw.println("\ngetConnectedDevices[0] = " + device);
dumpHeadsetConnectionState(pw, device);
pw.println("getBatteryUsageHint() = " +
- mBluetoothHeadset.getBatteryUsageHint(device));
+ mHeadsetProxy.getBatteryUsageHint(device));
}
deviceList.clear();
- deviceList = mBluetoothHeadset.getDevicesMatchingConnectionStates(new int[] {
+ deviceList = mHeadsetProxy.getDevicesMatchingConnectionStates(new int[] {
BluetoothProfile.STATE_CONNECTED, BluetoothProfile.STATE_DISCONNECTED});
pw.println("--Connected and Disconnected Headsets");
for (BluetoothDevice device: deviceList) {
pw.println(device);
- if (mBluetoothHeadset.isAudioConnected(device)) {
+ if (mHeadsetProxy.isAudioConnected(device)) {
pw.println("SCO audio connected to device:" + device);
}
}
}
- mAdapter.closeProfileProxy(BluetoothProfile.HEADSET, mBluetoothHeadset);
}
private void dumpInputDeviceProfile(PrintWriter pw) {
@@ -1824,7 +1824,6 @@
pw.println(device);
}
}
- mAdapter.closeProfileProxy(BluetoothProfile.INPUT_DEVICE, mBluetoothHeadset);
}
private void dumpPanProfile(PrintWriter pw) {
@@ -1862,7 +1861,7 @@
private void dumpHeadsetConnectionState(PrintWriter pw,
BluetoothDevice device) {
- switch (mBluetoothHeadset.getConnectionState(device)) {
+ switch (mHeadsetProxy.getConnectionState(device)) {
case BluetoothHeadset.STATE_CONNECTING:
pw.println("getConnectionState() = STATE_CONNECTING");
break;
@@ -1884,7 +1883,6 @@
Integer pid = mServiceRecordToPid.get(handle).first;
pw.println("\tpid " + pid + " handle " + Integer.toHexString(handle));
}
- mAdapter.closeProfileProxy(BluetoothProfile.PAN, mBluetoothHeadset);
}
private void dumpAclConnectedDevices(PrintWriter pw) {
@@ -1927,11 +1925,16 @@
}
}
+ private void getProfileProxy() {
+ mAdapter.getProfileProxy(mContext,
+ mBluetoothProfileServiceListener, BluetoothProfile.HEADSET);
+ }
+
private BluetoothProfile.ServiceListener mBluetoothProfileServiceListener =
new BluetoothProfile.ServiceListener() {
public void onServiceConnected(int profile, BluetoothProfile proxy) {
if (profile == BluetoothProfile.HEADSET) {
- mBluetoothHeadset = (BluetoothHeadset) proxy;
+ mHeadsetProxy = (BluetoothHeadset) proxy;
} else if (profile == BluetoothProfile.INPUT_DEVICE) {
mInputDevice = (BluetoothInputDevice) proxy;
} else if (profile == BluetoothProfile.PAN) {
@@ -1940,7 +1943,7 @@
}
public void onServiceDisconnected(int profile) {
if (profile == BluetoothProfile.HEADSET) {
- mBluetoothHeadset = null;
+ mHeadsetProxy = null;
} else if (profile == BluetoothProfile.INPUT_DEVICE) {
mInputDevice = null;
} else if (profile == BluetoothProfile.PAN) {
@@ -2424,25 +2427,43 @@
}
}
- public boolean notifyIncomingConnection(String address) {
- BluetoothDeviceProfileState state =
- mDeviceProfileState.get(address);
+ public boolean notifyIncomingConnection(String address, boolean rejected) {
+ BluetoothDeviceProfileState state = mDeviceProfileState.get(address);
if (state != null) {
Message msg = new Message();
- msg.what = BluetoothDeviceProfileState.CONNECT_HFP_INCOMING;
- state.sendMessage(msg);
+ if (rejected) {
+ if (mA2dpService.getPriority(getRemoteDevice(address)) >=
+ BluetoothProfile.PRIORITY_ON) {
+ msg.what = BluetoothDeviceProfileState.CONNECT_OTHER_PROFILES;
+ msg.arg1 = BluetoothDeviceProfileState.CONNECT_A2DP_OUTGOING;
+ state.sendMessageDelayed(msg,
+ BluetoothDeviceProfileState.CONNECT_OTHER_PROFILES_DELAY);
+ }
+ } else {
+ msg.what = BluetoothDeviceProfileState.CONNECT_HFP_INCOMING;
+ state.sendMessage(msg);
+ }
return true;
}
return false;
}
- /*package*/ boolean notifyIncomingA2dpConnection(String address) {
- BluetoothDeviceProfileState state =
- mDeviceProfileState.get(address);
+ /*package*/ boolean notifyIncomingA2dpConnection(String address, boolean rejected) {
+ BluetoothDeviceProfileState state = mDeviceProfileState.get(address);
if (state != null) {
Message msg = new Message();
- msg.what = BluetoothDeviceProfileState.CONNECT_A2DP_INCOMING;
- state.sendMessage(msg);
+ if (rejected) {
+ if (mHeadsetProxy.getPriority(getRemoteDevice(address)) >=
+ BluetoothProfile.PRIORITY_ON) {
+ msg.what = BluetoothDeviceProfileState.CONNECT_OTHER_PROFILES;
+ msg.arg1 = BluetoothDeviceProfileState.CONNECT_HFP_OUTGOING;
+ state.sendMessageDelayed(msg,
+ BluetoothDeviceProfileState.CONNECT_OTHER_PROFILES_DELAY);
+ }
+ } else {
+ msg.what = BluetoothDeviceProfileState.CONNECT_A2DP_INCOMING;
+ state.sendMessage(msg);
+ }
return true;
}
return false;
diff --git a/core/java/android/speech/tts/AudioMessageParams.java b/core/java/android/speech/tts/AudioMessageParams.java
index 68d8738..29b4367 100644
--- a/core/java/android/speech/tts/AudioMessageParams.java
+++ b/core/java/android/speech/tts/AudioMessageParams.java
@@ -15,12 +15,12 @@
*/
package android.speech.tts;
-import android.speech.tts.TextToSpeechService.UtteranceCompletedDispatcher;
+import android.speech.tts.TextToSpeechService.UtteranceProgressDispatcher;
class AudioMessageParams extends MessageParams {
private final BlockingMediaPlayer mPlayer;
- AudioMessageParams(UtteranceCompletedDispatcher dispatcher,
+ AudioMessageParams(UtteranceProgressDispatcher dispatcher,
String callingApp, BlockingMediaPlayer player) {
super(dispatcher, callingApp);
mPlayer = player;
diff --git a/core/java/android/speech/tts/AudioPlaybackHandler.java b/core/java/android/speech/tts/AudioPlaybackHandler.java
index d970ae6..0194240 100644
--- a/core/java/android/speech/tts/AudioPlaybackHandler.java
+++ b/core/java/android/speech/tts/AudioPlaybackHandler.java
@@ -312,10 +312,11 @@
private void handleSilence(MessageParams msg) {
if (DBG) Log.d(TAG, "handleSilence()");
SilenceMessageParams params = (SilenceMessageParams) msg;
+ params.getDispatcher().dispatchOnStart();
if (params.getSilenceDurationMs() > 0) {
params.getConditionVariable().block(params.getSilenceDurationMs());
}
- params.getDispatcher().dispatchUtteranceCompleted();
+ params.getDispatcher().dispatchOnDone();
if (DBG) Log.d(TAG, "handleSilence() done.");
}
@@ -323,11 +324,12 @@
private void handleAudio(MessageParams msg) {
if (DBG) Log.d(TAG, "handleAudio()");
AudioMessageParams params = (AudioMessageParams) msg;
+ params.getDispatcher().dispatchOnStart();
// Note that the BlockingMediaPlayer spawns a separate thread.
//
// TODO: This can be avoided.
params.getPlayer().startAndWait();
- params.getDispatcher().dispatchUtteranceCompleted();
+ params.getDispatcher().dispatchOnDone();
if (DBG) Log.d(TAG, "handleAudio() done.");
}
@@ -361,6 +363,7 @@
if (DBG) Log.d(TAG, "Created audio track [" + audioTrack.hashCode() + "]");
param.setAudioTrack(audioTrack);
+ msg.getDispatcher().dispatchOnStart();
}
// More data available to be flushed to the audio track.
@@ -411,6 +414,7 @@
final AudioTrack audioTrack = params.getAudioTrack();
if (audioTrack == null) {
+ params.getDispatcher().dispatchOnError();
return;
}
@@ -439,7 +443,7 @@
audioTrack.release();
params.setAudioTrack(null);
}
- params.getDispatcher().dispatchUtteranceCompleted();
+ params.getDispatcher().dispatchOnDone();
mLastSynthesisRequest = null;
params.mLogger.onWriteData();
}
diff --git a/core/java/android/speech/tts/ITextToSpeechCallback.aidl b/core/java/android/speech/tts/ITextToSpeechCallback.aidl
index 40902ae..f0287d4 100755
--- a/core/java/android/speech/tts/ITextToSpeechCallback.aidl
+++ b/core/java/android/speech/tts/ITextToSpeechCallback.aidl
@@ -21,5 +21,7 @@
* {@hide}
*/
oneway interface ITextToSpeechCallback {
- void utteranceCompleted(String utteranceId);
+ void onStart(String utteranceId);
+ void onDone(String utteranceId);
+ void onError(String utteranceId);
}
diff --git a/core/java/android/speech/tts/MessageParams.java b/core/java/android/speech/tts/MessageParams.java
index e7d6da3..de9cc07 100644
--- a/core/java/android/speech/tts/MessageParams.java
+++ b/core/java/android/speech/tts/MessageParams.java
@@ -15,22 +15,22 @@
*/
package android.speech.tts;
-import android.speech.tts.TextToSpeechService.UtteranceCompletedDispatcher;
+import android.speech.tts.TextToSpeechService.UtteranceProgressDispatcher;
abstract class MessageParams {
static final int TYPE_SYNTHESIS = 1;
static final int TYPE_AUDIO = 2;
static final int TYPE_SILENCE = 3;
- private final UtteranceCompletedDispatcher mDispatcher;
+ private final UtteranceProgressDispatcher mDispatcher;
private final String mCallingApp;
- MessageParams(UtteranceCompletedDispatcher dispatcher, String callingApp) {
+ MessageParams(UtteranceProgressDispatcher dispatcher, String callingApp) {
mDispatcher = dispatcher;
mCallingApp = callingApp;
}
- UtteranceCompletedDispatcher getDispatcher() {
+ UtteranceProgressDispatcher getDispatcher() {
return mDispatcher;
}
diff --git a/core/java/android/speech/tts/PlaybackSynthesisCallback.java b/core/java/android/speech/tts/PlaybackSynthesisCallback.java
index 0cca06ac..ce3522b 100644
--- a/core/java/android/speech/tts/PlaybackSynthesisCallback.java
+++ b/core/java/android/speech/tts/PlaybackSynthesisCallback.java
@@ -15,7 +15,7 @@
*/
package android.speech.tts;
-import android.speech.tts.TextToSpeechService.UtteranceCompletedDispatcher;
+import android.speech.tts.TextToSpeechService.UtteranceProgressDispatcher;
import android.util.Log;
/**
@@ -62,12 +62,12 @@
private volatile boolean mDone = false;
- private final UtteranceCompletedDispatcher mDispatcher;
+ private final UtteranceProgressDispatcher mDispatcher;
private final String mCallingApp;
private final EventLogger mLogger;
PlaybackSynthesisCallback(int streamType, float volume, float pan,
- AudioPlaybackHandler audioTrackHandler, UtteranceCompletedDispatcher dispatcher,
+ AudioPlaybackHandler audioTrackHandler, UtteranceProgressDispatcher dispatcher,
String callingApp, EventLogger logger) {
mStreamType = streamType;
mVolume = volume;
diff --git a/core/java/android/speech/tts/SilenceMessageParams.java b/core/java/android/speech/tts/SilenceMessageParams.java
index 7a4ff1c..9909126 100644
--- a/core/java/android/speech/tts/SilenceMessageParams.java
+++ b/core/java/android/speech/tts/SilenceMessageParams.java
@@ -16,13 +16,13 @@
package android.speech.tts;
import android.os.ConditionVariable;
-import android.speech.tts.TextToSpeechService.UtteranceCompletedDispatcher;
+import android.speech.tts.TextToSpeechService.UtteranceProgressDispatcher;
class SilenceMessageParams extends MessageParams {
private final ConditionVariable mCondVar = new ConditionVariable();
private final long mSilenceDurationMs;
- SilenceMessageParams(UtteranceCompletedDispatcher dispatcher,
+ SilenceMessageParams(UtteranceProgressDispatcher dispatcher,
String callingApp, long silenceDurationMs) {
super(dispatcher, callingApp);
mSilenceDurationMs = silenceDurationMs;
diff --git a/core/java/android/speech/tts/SynthesisMessageParams.java b/core/java/android/speech/tts/SynthesisMessageParams.java
index 779721e..0c0f033 100644
--- a/core/java/android/speech/tts/SynthesisMessageParams.java
+++ b/core/java/android/speech/tts/SynthesisMessageParams.java
@@ -17,7 +17,7 @@
import android.media.AudioFormat;
import android.media.AudioTrack;
-import android.speech.tts.TextToSpeechService.UtteranceCompletedDispatcher;
+import android.speech.tts.TextToSpeechService.UtteranceProgressDispatcher;
import java.util.LinkedList;
@@ -56,7 +56,7 @@
SynthesisMessageParams(int streamType, int sampleRate,
int audioFormat, int channelCount,
- float volume, float pan, UtteranceCompletedDispatcher dispatcher,
+ float volume, float pan, UtteranceProgressDispatcher dispatcher,
String callingApp, EventLogger logger) {
super(dispatcher, callingApp);
diff --git a/core/java/android/speech/tts/TextToSpeech.java b/core/java/android/speech/tts/TextToSpeech.java
index fdc2570..38699ea 100755
--- a/core/java/android/speech/tts/TextToSpeech.java
+++ b/core/java/android/speech/tts/TextToSpeech.java
@@ -482,7 +482,7 @@
private OnInitListener mInitListener;
// Written from an unspecified application thread, read from
// a binder thread.
- private volatile OnUtteranceCompletedListener mUtteranceCompletedListener;
+ private volatile UtteranceProgressListener mUtteranceProgressListener;
private final Object mStartLock = new Object();
private String mRequestedEngine;
@@ -1146,9 +1146,28 @@
* @param listener The listener to use.
*
* @return {@link #ERROR} or {@link #SUCCESS}.
+ *
+ * @deprecated Use {@link #setOnUtteranceProgressListener(UtteranceProgressListener)}
+ * instead.
*/
+ @Deprecated
public int setOnUtteranceCompletedListener(final OnUtteranceCompletedListener listener) {
- mUtteranceCompletedListener = listener;
+ mUtteranceProgressListener = UtteranceProgressListener.from(listener);
+ return TextToSpeech.SUCCESS;
+ }
+
+ /**
+ * Sets the listener that will be notified of various events related to the
+ * synthesis of a given utterance.
+ *
+ * See {@link UtteranceProgressListener} and
+ * {@link TextToSpeech.Engine#KEY_PARAM_UTTERANCE_ID}.
+ *
+ * @param listener the listener to use.
+ * @return {@link #ERROR} or {@link #SUCCESS}
+ */
+ public int setOnUtteranceProgressListener(UtteranceProgressListener listener) {
+ mUtteranceProgressListener = listener;
return TextToSpeech.SUCCESS;
}
@@ -1204,10 +1223,26 @@
private ITextToSpeechService mService;
private final ITextToSpeechCallback.Stub mCallback = new ITextToSpeechCallback.Stub() {
@Override
- public void utteranceCompleted(String utteranceId) {
- OnUtteranceCompletedListener listener = mUtteranceCompletedListener;
+ public void onDone(String utteranceId) {
+ UtteranceProgressListener listener = mUtteranceProgressListener;
if (listener != null) {
- listener.onUtteranceCompleted(utteranceId);
+ listener.onDone(utteranceId);
+ }
+ }
+
+ @Override
+ public void onError(String utteranceId) {
+ UtteranceProgressListener listener = mUtteranceProgressListener;
+ if (listener != null) {
+ listener.onError(utteranceId);
+ }
+ }
+
+ @Override
+ public void onStart(String utteranceId) {
+ UtteranceProgressListener listener = mUtteranceProgressListener;
+ if (listener != null) {
+ listener.onStart(utteranceId);
}
}
};
diff --git a/core/java/android/speech/tts/TextToSpeechService.java b/core/java/android/speech/tts/TextToSpeechService.java
index 83b6d4c..39922da 100644
--- a/core/java/android/speech/tts/TextToSpeechService.java
+++ b/core/java/android/speech/tts/TextToSpeechService.java
@@ -306,6 +306,7 @@
*/
public int enqueueSpeechItem(int queueMode, final SpeechItem speechItem) {
if (!speechItem.isValid()) {
+ speechItem.dispatchOnError();
return TextToSpeech.ERROR;
}
@@ -332,6 +333,7 @@
return TextToSpeech.SUCCESS;
} else {
Log.w(TAG, "SynthThread has quit");
+ speechItem.dispatchOnError();
return TextToSpeech.ERROR;
}
}
@@ -381,14 +383,16 @@
}
}
- interface UtteranceCompletedDispatcher {
- public void dispatchUtteranceCompleted();
+ interface UtteranceProgressDispatcher {
+ public void dispatchOnDone();
+ public void dispatchOnStart();
+ public void dispatchOnError();
}
/**
* An item in the synth thread queue.
*/
- private abstract class SpeechItem implements UtteranceCompletedDispatcher {
+ private abstract class SpeechItem implements UtteranceProgressDispatcher {
private final String mCallingApp;
protected final Bundle mParams;
private boolean mStarted = false;
@@ -443,10 +447,27 @@
stopImpl();
}
- public void dispatchUtteranceCompleted() {
+ @Override
+ public void dispatchOnDone() {
final String utteranceId = getUtteranceId();
if (!TextUtils.isEmpty(utteranceId)) {
- mCallbacks.dispatchUtteranceCompleted(getCallingApp(), utteranceId);
+ mCallbacks.dispatchOnDone(getCallingApp(), utteranceId);
+ }
+ }
+
+ @Override
+ public void dispatchOnStart() {
+ final String utteranceId = getUtteranceId();
+ if (!TextUtils.isEmpty(utteranceId)) {
+ mCallbacks.dispatchOnStart(getCallingApp(), utteranceId);
+ }
+ }
+
+ @Override
+ public void dispatchOnError() {
+ final String utteranceId = getUtteranceId();
+ if (!TextUtils.isEmpty(utteranceId)) {
+ mCallbacks.dispatchOnError(getCallingApp(), utteranceId);
}
}
@@ -617,9 +638,12 @@
@Override
protected int playImpl() {
+ dispatchOnStart();
int status = super.playImpl();
if (status == TextToSpeech.SUCCESS) {
- dispatchUtteranceCompleted();
+ dispatchOnDone();
+ } else {
+ dispatchOnError();
}
return status;
}
@@ -856,16 +880,34 @@
}
}
- public void dispatchUtteranceCompleted(String packageName, String utteranceId) {
- ITextToSpeechCallback cb;
- synchronized (mAppToCallback) {
- cb = mAppToCallback.get(packageName);
- }
+ public void dispatchOnDone(String packageName, String utteranceId) {
+ ITextToSpeechCallback cb = getCallbackFor(packageName);
if (cb == null) return;
try {
- cb.utteranceCompleted(utteranceId);
+ cb.onDone(utteranceId);
} catch (RemoteException e) {
- Log.e(TAG, "Callback failed: " + e);
+ Log.e(TAG, "Callback onDone failed: " + e);
+ }
+ }
+
+ public void dispatchOnStart(String packageName, String utteranceId) {
+ ITextToSpeechCallback cb = getCallbackFor(packageName);
+ if (cb == null) return;
+ try {
+ cb.onStart(utteranceId);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Callback onStart failed: " + e);
+ }
+
+ }
+
+ public void dispatchOnError(String packageName, String utteranceId) {
+ ITextToSpeechCallback cb = getCallbackFor(packageName);
+ if (cb == null) return;
+ try {
+ cb.onError(utteranceId);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Callback onError failed: " + e);
}
}
@@ -886,6 +928,15 @@
}
}
+ private ITextToSpeechCallback getCallbackFor(String packageName) {
+ ITextToSpeechCallback cb;
+ synchronized (mAppToCallback) {
+ cb = mAppToCallback.get(packageName);
+ }
+
+ return cb;
+ }
+
}
}
diff --git a/core/java/android/speech/tts/UtteranceProgressListener.java b/core/java/android/speech/tts/UtteranceProgressListener.java
new file mode 100644
index 0000000..a04458a
--- /dev/null
+++ b/core/java/android/speech/tts/UtteranceProgressListener.java
@@ -0,0 +1,68 @@
+// Copyright 2011 Google Inc. All Rights Reserved.
+
+package android.speech.tts;
+
+/**
+ * Listener for events relating to the progress of an utterance through
+ * the synthesis queue. Each utterance is associated with a call to
+ * {@link TextToSpeech#speak} or {@link TextToSpeech#synthesizeToFile} with an
+ * associated utterance identifier, as per {@link TextToSpeech.Engine#KEY_PARAM_UTTERANCE_ID}.
+ *
+ * The callbacks specified in this method can be called from multiple threads.
+ */
+public abstract class UtteranceProgressListener {
+ /**
+ * Called when an utterance "starts" as perceived by the caller. This will
+ * be soon before audio is played back in the case of a {@link TextToSpeech#speak}
+ * or before the first bytes of a file are written to storage in the case
+ * of {@link TextToSpeech#synthesizeToFile}.
+ *
+ * @param utteranceId the utterance ID of the utterance.
+ */
+ public abstract void onStart(String utteranceId);
+
+ /**
+ * Called when an utterance has successfully completed processing.
+ * All audio will have been played back by this point for audible output, and all
+ * output will have been written to disk for file synthesis requests.
+ *
+ * This request is guaranteed to be called after {@link #onStart(String)}.
+ *
+ * @param utteranceId the utterance ID of the utterance.
+ */
+ public abstract void onDone(String utteranceId);
+
+ /**
+ * Called when an error has occurred during processing. This can be called
+ * at any point in the synthesis process. Note that there might be calls
+ * to {@link #onStart(String)} for specified utteranceId but there will never
+ * be a call to both {@link #onDone(String)} and {@link #onError(String)} for
+ * the same utterance.
+ *
+ * @param utteranceId the utterance ID of the utterance.
+ */
+ public abstract void onError(String utteranceId);
+
+ /**
+ * Wraps an old deprecated OnUtteranceCompletedListener with a shiny new
+ * progress listener.
+ *
+ * @hide
+ */
+ static UtteranceProgressListener from(
+ final TextToSpeech.OnUtteranceCompletedListener listener) {
+ return new UtteranceProgressListener() {
+ @Override
+ public synchronized void onDone(String utteranceId) {
+ listener.onUtteranceCompleted(utteranceId);
+ }
+
+ // The following methods are left unimplemented.
+ @Override
+ public void onStart(String utteranceId) { }
+
+ @Override
+ public void onError(String utteranceId) { }
+ };
+ }
+}
diff --git a/core/java/android/view/GLES20Canvas.java b/core/java/android/view/GLES20Canvas.java
index c934c7b..d948ec2 100644
--- a/core/java/android/view/GLES20Canvas.java
+++ b/core/java/android/view/GLES20Canvas.java
@@ -315,6 +315,27 @@
private static native void nFlushCaches(int level);
+ /**
+ * Release all resources associated with the underlying caches. This should
+ * only be called after a full flushCaches().
+ *
+ * @hide
+ */
+ public static void terminateCaches() {
+ nTerminateCaches();
+ }
+
+ private static native void nTerminateCaches();
+
+ /**
+ * @hide
+ */
+ public static void initCaches() {
+ nInitCaches();
+ }
+
+ private static native void nInitCaches();
+
///////////////////////////////////////////////////////////////////////////
// Display list
///////////////////////////////////////////////////////////////////////////
diff --git a/core/java/android/view/HardwareRenderer.java b/core/java/android/view/HardwareRenderer.java
index b86d21d..e0167d8 100644
--- a/core/java/android/view/HardwareRenderer.java
+++ b/core/java/android/view/HardwareRenderer.java
@@ -25,6 +25,7 @@
import android.os.SystemClock;
import android.os.SystemProperties;
import android.util.Log;
+import com.google.android.gles_jni.EGLImpl;
import javax.microedition.khronos.egl.EGL10;
import javax.microedition.khronos.egl.EGL11;
@@ -34,6 +35,8 @@
import javax.microedition.khronos.egl.EGLSurface;
import javax.microedition.khronos.opengles.GL;
+import java.io.File;
+
import static javax.microedition.khronos.egl.EGL10.*;
/**
@@ -45,6 +48,11 @@
static final String LOG_TAG = "HardwareRenderer";
/**
+ * Name of the file that holds the shaders cache.
+ */
+ private static final String CACHE_PATH_SHADERS = "com.android.opengl.shaders_cache";
+
+ /**
* Turn on to only refresh the parts of the screen that need updating.
* When turned on the property defined by {@link #RENDER_DIRTY_REGIONS_PROPERTY}
* must also have the value "true".
@@ -200,6 +208,18 @@
abstract int getHeight();
/**
+ * Sets the directory to use as a persistent storage for hardware rendering
+ * resources.
+ *
+ * @param cacheDir A directory the current process can write to
+ */
+ public static void setupDiskCache(File cacheDir) {
+ nSetupShadersDiskCache(new File(cacheDir, CACHE_PATH_SHADERS).getAbsolutePath());
+ }
+
+ private static native void nSetupShadersDiskCache(String cacheFile);
+
+ /**
* Interface used to receive callbacks whenever a view is drawn by
* a hardware renderer instance.
*/
@@ -325,6 +345,15 @@
}
/**
+ * Invoke this method when the system needs to clean up all resources
+ * associated with hardware rendering.
+ */
+ static void terminate() {
+ Log.d(LOG_TAG, "Terminating hardware rendering");
+ Gl20Renderer.terminate();
+ }
+
+ /**
* Indicates whether hardware acceleration is currently enabled.
*
* @return True if hardware acceleration is in use, false otherwise.
@@ -632,6 +661,8 @@
throw new Surface.OutOfResourcesException("eglMakeCurrent failed "
+ GLUtils.getEGLErrorString(sEgl.eglGetError()));
}
+
+ initCaches();
// If mDirtyRegions is set, this means we have an EGL configuration
// with EGL_SWAP_BEHAVIOR_PRESERVED_BIT set
@@ -652,6 +683,8 @@
return mEglContext.getGL();
}
+ abstract void initCaches();
+
EGLContext createContext(EGL10 egl, EGLDisplay eglDisplay, EGLConfig eglConfig) {
int[] attribs = { EGL_CONTEXT_CLIENT_VERSION, mGlVersion, EGL_NONE };
@@ -895,6 +928,11 @@
EGL_NONE
};
}
+
+ @Override
+ void initCaches() {
+ GLES20Canvas.initCaches();
+ }
@Override
boolean canDraw() {
@@ -987,16 +1025,7 @@
if (eglContext == null) {
return;
} else {
- synchronized (sPbufferLock) {
- // Create a temporary 1x1 pbuffer so we have a context
- // to clear our OpenGL objects
- if (sPbuffer == null) {
- sPbuffer = sEgl.eglCreatePbufferSurface(sEglDisplay, sEglConfig, new int[] {
- EGL_WIDTH, 1, EGL_HEIGHT, 1, EGL_NONE
- });
- }
- }
- sEgl.eglMakeCurrent(sEglDisplay, sPbuffer, sPbuffer, eglContext);
+ usePbufferSurface(eglContext);
}
switch (level) {
@@ -1010,5 +1039,46 @@
break;
}
}
+
+ private static void usePbufferSurface(EGLContext eglContext) {
+ synchronized (sPbufferLock) {
+ // Create a temporary 1x1 pbuffer so we have a context
+ // to clear our OpenGL objects
+ if (sPbuffer == null) {
+ sPbuffer = sEgl.eglCreatePbufferSurface(sEglDisplay, sEglConfig, new int[] {
+ EGL_WIDTH, 1, EGL_HEIGHT, 1, EGL_NONE
+ });
+ }
+ }
+ sEgl.eglMakeCurrent(sEglDisplay, sPbuffer, sPbuffer, eglContext);
+ }
+
+ static void terminate() {
+ synchronized (sEglLock) {
+ if (sEgl == null) return;
+
+ if (EGLImpl.getInitCount(sEglDisplay) == 1) {
+ EGLContext eglContext = sEglContextStorage.get();
+ if (eglContext == null) return;
+
+ usePbufferSurface(eglContext);
+ GLES20Canvas.terminateCaches();
+
+ sEgl.eglDestroyContext(sEglDisplay, eglContext);
+ sEglContextStorage.remove();
+
+ sEgl.eglDestroySurface(sEglDisplay, sPbuffer);
+ sEgl.eglMakeCurrent(sEglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
+
+ sEgl.eglReleaseThread();
+ sEgl.eglTerminate(sEglDisplay);
+
+ sEgl = null;
+ sEglDisplay = null;
+ sEglConfig = null;
+ sPbuffer = null;
+ }
+ }
+ }
}
}
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 62e6ebd..dc46d42 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -11402,8 +11402,12 @@
* {@link SystemClock#uptimeMillis} timebase.
*/
public void scheduleDrawable(Drawable who, Runnable what, long when) {
- if (verifyDrawable(who) && what != null && mAttachInfo != null) {
- mAttachInfo.mHandler.postAtTime(what, who, when);
+ if (verifyDrawable(who) && what != null) {
+ if (mAttachInfo != null) {
+ mAttachInfo.mHandler.postAtTime(what, who, when);
+ } else {
+ ViewRootImpl.getRunQueue().postDelayed(what, when - SystemClock.uptimeMillis());
+ }
}
}
@@ -11414,8 +11418,12 @@
* @param what the action to cancel
*/
public void unscheduleDrawable(Drawable who, Runnable what) {
- if (verifyDrawable(who) && what != null && mAttachInfo != null) {
- mAttachInfo.mHandler.removeCallbacks(what, who);
+ if (verifyDrawable(who) && what != null) {
+ if (mAttachInfo != null) {
+ mAttachInfo.mHandler.removeCallbacks(what, who);
+ } else {
+ ViewRootImpl.getRunQueue().removeCallbacks(what);
+ }
}
}
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index f7078ec..b15b155 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -567,7 +567,7 @@
}
}
- private void destroyHardwareResources() {
+ void destroyHardwareResources() {
if (mAttachInfo.mHardwareRenderer != null) {
if (mAttachInfo.mHardwareRenderer.isEnabled()) {
mAttachInfo.mHardwareRenderer.destroyLayers(mView);
@@ -880,12 +880,10 @@
|| mNewSurfaceNeeded;
WindowManager.LayoutParams params = null;
- int windowAttributesChanges = 0;
if (mWindowAttributesChanged) {
mWindowAttributesChanged = false;
surfaceChanged = true;
params = lp;
- windowAttributesChanges = mWindowAttributesChangesFlag;
}
CompatibilityInfo compatibilityInfo = mCompatibilityInfo.get();
if (compatibilityInfo.supportsScreen() == mLastInCompatMode) {
diff --git a/core/java/android/view/WindowManagerImpl.java b/core/java/android/view/WindowManagerImpl.java
index 5ef4f3e..d89bc36 100644
--- a/core/java/android/view/WindowManagerImpl.java
+++ b/core/java/android/view/WindowManagerImpl.java
@@ -16,6 +16,8 @@
package android.view;
+import android.app.ActivityManager;
+import android.content.ComponentCallbacks2;
import android.content.res.CompatibilityInfo;
import android.content.res.Configuration;
import android.graphics.PixelFormat;
@@ -409,7 +411,30 @@
*/
public void trimMemory(int level) {
if (HardwareRenderer.isAvailable()) {
- HardwareRenderer.trimMemory(level);
+ switch (level) {
+ case ComponentCallbacks2.TRIM_MEMORY_COMPLETE:
+ case ComponentCallbacks2.TRIM_MEMORY_MODERATE:
+ // On low and medium end gfx devices
+ if (!ActivityManager.isHighEndGfx(getDefaultDisplay())) {
+ // Force a full memory flush
+ HardwareRenderer.trimMemory(ComponentCallbacks2.TRIM_MEMORY_COMPLETE);
+ // Destroy all hardware surfaces and resources associated to
+ // known windows
+ synchronized (this) {
+ if (mViews == null) return;
+ int count = mViews.length;
+ for (int i = 0; i < count; i++) {
+ mRoots[i].destroyHardwareResources();
+ }
+ }
+ // Terminate the hardware renderer to free all resources
+ HardwareRenderer.terminate();
+ break;
+ }
+ // high end gfx devices fall through to next case
+ default:
+ HardwareRenderer.trimMemory(level);
+ }
}
}
diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java
index 03d6511..7249497 100644
--- a/core/java/android/webkit/WebView.java
+++ b/core/java/android/webkit/WebView.java
@@ -2861,8 +2861,8 @@
}
// Used to avoid sending many visible rect messages.
- private Rect mLastVisibleRectSent;
- private Rect mLastGlobalRect;
+ private Rect mLastVisibleRectSent = new Rect();
+ private Rect mLastGlobalRect = new Rect();
private Rect mVisibleRect = new Rect();
private Rect mGlobalVisibleRect = new Rect();
private Point mScrollOffset = new Point();
@@ -2878,7 +2878,7 @@
mWebViewCore.sendMessage(EventHub.SET_SCROLL_OFFSET,
nativeMoveGeneration(), mSendScrollEvent ? 1 : 0, mScrollOffset);
}
- mLastVisibleRectSent = mVisibleRect;
+ mLastVisibleRectSent.set(mVisibleRect);
mPrivateHandler.removeMessages(SWITCH_TO_LONGPRESS);
}
if (getGlobalVisibleRect(mGlobalVisibleRect)
@@ -2894,7 +2894,7 @@
if (!mBlockWebkitViewMessages) {
mWebViewCore.sendMessage(EventHub.SET_GLOBAL_BOUNDS, mGlobalVisibleRect);
}
- mLastGlobalRect = mGlobalVisibleRect;
+ mLastGlobalRect.set(mGlobalVisibleRect);
}
return mVisibleRect;
}
diff --git a/core/java/android/widget/EdgeEffect.java b/core/java/android/widget/EdgeEffect.java
index fd2abc2..326587e 100644
--- a/core/java/android/widget/EdgeEffect.java
+++ b/core/java/android/widget/EdgeEffect.java
@@ -129,7 +129,7 @@
mEdge = res.getDrawable(R.drawable.overscroll_edge);
mGlow = res.getDrawable(R.drawable.overscroll_glow);
- mMinWidth = (int) (context.getResources().getDisplayMetrics().density * MIN_WIDTH + 0.5f);
+ mMinWidth = (int) (res.getDisplayMetrics().density * MIN_WIDTH + 0.5f);
mInterpolator = new DecelerateInterpolator();
}
diff --git a/core/java/android/widget/ImageView.java b/core/java/android/widget/ImageView.java
index b24dd69..73e1273 100644
--- a/core/java/android/widget/ImageView.java
+++ b/core/java/android/widget/ImageView.java
@@ -1035,4 +1035,29 @@
mDrawable.setAlpha(mAlpha * mViewAlphaScale >> 8);
}
}
+
+ @RemotableViewMethod
+ @Override
+ public void setVisibility(int visibility) {
+ super.setVisibility(visibility);
+ if (mDrawable != null) {
+ mDrawable.setVisible(visibility == VISIBLE, false);
+ }
+ }
+
+ @Override
+ protected void onAttachedToWindow() {
+ super.onAttachedToWindow();
+ if (mDrawable != null) {
+ mDrawable.setVisible(getVisibility() == VISIBLE, false);
+ }
+ }
+
+ @Override
+ protected void onDetachedFromWindow() {
+ super.onDetachedFromWindow();
+ if (mDrawable != null) {
+ mDrawable.setVisible(false, false);
+ }
+ }
}
diff --git a/core/java/android/widget/PopupWindow.java b/core/java/android/widget/PopupWindow.java
index 8ba7bee..5fa4ad0 100644
--- a/core/java/android/widget/PopupWindow.java
+++ b/core/java/android/widget/PopupWindow.java
@@ -1248,6 +1248,8 @@
*/
public void dismiss() {
if (isShowing() && mPopupView != null) {
+ mIsShowing = false;
+
unregisterForScrollChanged();
try {
@@ -1257,7 +1259,6 @@
((ViewGroup) mPopupView).removeView(mContentView);
}
mPopupView = null;
- mIsShowing = false;
if (mOnDismissListener != null) {
mOnDismissListener.onDismiss();
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index bc8721a..b106cc5 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -24,6 +24,7 @@
import android.content.Intent;
import android.content.pm.PackageManager;
import android.content.res.ColorStateList;
+import android.content.res.CompatibilityInfo;
import android.content.res.Resources;
import android.content.res.TypedArray;
import android.content.res.XmlResourceParser;
@@ -449,18 +450,19 @@
super(context, attrs, defStyle);
mText = "";
+ final Resources res = getResources();
+ final CompatibilityInfo compat = res.getCompatibilityInfo();
+
mTextPaint = new TextPaint(Paint.ANTI_ALIAS_FLAG);
- mTextPaint.density = getResources().getDisplayMetrics().density;
- mTextPaint.setCompatibilityScaling(
- getResources().getCompatibilityInfo().applicationScale);
+ mTextPaint.density = res.getDisplayMetrics().density;
+ mTextPaint.setCompatibilityScaling(compat.applicationScale);
// If we get the paint from the skin, we should set it to left, since
// the layout always wants it to be left.
// mTextPaint.setTextAlign(Paint.Align.LEFT);
mHighlightPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
- mHighlightPaint.setCompatibilityScaling(
- getResources().getCompatibilityInfo().applicationScale);
+ mHighlightPaint.setCompatibilityScaling(compat.applicationScale);
mMovement = getDefaultMovementMethod();
mTransformation = null;
diff --git a/core/java/com/android/internal/widget/ActionBarView.java b/core/java/com/android/internal/widget/ActionBarView.java
index 4714be8..b689f53 100644
--- a/core/java/com/android/internal/widget/ActionBarView.java
+++ b/core/java/com/android/internal/widget/ActionBarView.java
@@ -537,7 +537,7 @@
if ((flagsChanged & DISPLAY_RELAYOUT_MASK) != 0) {
final boolean showHome = (options & ActionBar.DISPLAY_SHOW_HOME) != 0;
- final int vis = showHome ? VISIBLE : GONE;
+ final int vis = showHome && mExpandedActionView == null ? VISIBLE : GONE;
mHomeLayout.setVisibility(vis);
if ((flagsChanged & ActionBar.DISPLAY_HOME_AS_UP) != 0) {
diff --git a/core/java/com/android/internal/widget/LockPatternView.java b/core/java/com/android/internal/widget/LockPatternView.java
index a2fc6e2..0d9cf9a 100644
--- a/core/java/com/android/internal/widget/LockPatternView.java
+++ b/core/java/com/android/internal/widget/LockPatternView.java
@@ -463,7 +463,7 @@
result = desired;
break;
case MeasureSpec.AT_MOST:
- result = Math.min(specSize, desired);
+ result = Math.max(specSize, desired);
break;
case MeasureSpec.EXACTLY:
default:
diff --git a/core/jni/Android.mk b/core/jni/Android.mk
index 59a03e7..71c5d26 100644
--- a/core/jni/Android.mk
+++ b/core/jni/Android.mk
@@ -53,6 +53,7 @@
android_view_InputQueue.cpp \
android_view_KeyEvent.cpp \
android_view_KeyCharacterMap.cpp \
+ android_view_HardwareRenderer.cpp \
android_view_GLES20Canvas.cpp \
android_view_MotionEvent.cpp \
android_view_PointerIcon.cpp \
@@ -160,6 +161,7 @@
$(JNI_H_INCLUDE) \
$(LOCAL_PATH)/android/graphics \
$(LOCAL_PATH)/../../libs/hwui \
+ $(LOCAL_PATH)/../../opengl/libs \
$(call include-path-for, bluedroid) \
$(call include-path-for, libhardware)/hardware \
$(call include-path-for, libhardware_legacy)/hardware_legacy \
diff --git a/core/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp
index 12ec1b6..c00e6c9 100644
--- a/core/jni/AndroidRuntime.cpp
+++ b/core/jni/AndroidRuntime.cpp
@@ -116,6 +116,7 @@
extern int register_android_graphics_PixelFormat(JNIEnv* env);
extern int register_android_view_Display(JNIEnv* env);
extern int register_android_view_GLES20Canvas(JNIEnv* env);
+extern int register_android_view_HardwareRenderer(JNIEnv* env);
extern int register_android_view_Surface(JNIEnv* env);
extern int register_android_view_TextureView(JNIEnv* env);
extern int register_android_database_CursorWindow(JNIEnv* env);
@@ -1101,6 +1102,7 @@
REG_JNI(register_android_graphics_PixelFormat),
REG_JNI(register_android_graphics_Graphics),
REG_JNI(register_android_view_GLES20Canvas),
+ REG_JNI(register_android_view_HardwareRenderer),
REG_JNI(register_android_view_Surface),
REG_JNI(register_android_view_TextureView),
REG_JNI(register_com_google_android_gles_jni_EGLImpl),
diff --git a/core/jni/android/graphics/SurfaceTexture.cpp b/core/jni/android/graphics/SurfaceTexture.cpp
index ffcd1a0..de2d8c4 100644
--- a/core/jni/android/graphics/SurfaceTexture.cpp
+++ b/core/jni/android/graphics/SurfaceTexture.cpp
@@ -212,10 +212,10 @@
surfaceTexture->setDefaultBufferSize(width, height);
}
-static void SurfaceTexture_updateTexImage(JNIEnv* env, jobject thiz)
+static jint SurfaceTexture_updateTexImage(JNIEnv* env, jobject thiz)
{
sp<SurfaceTexture> surfaceTexture(SurfaceTexture_getSurfaceTexture(env, thiz));
- surfaceTexture->updateTexImage();
+ return surfaceTexture->updateTexImage();
}
static void SurfaceTexture_getTransformMatrix(JNIEnv* env, jobject thiz,
@@ -246,7 +246,7 @@
{"nativeInit", "(ILjava/lang/Object;Z)V", (void*)SurfaceTexture_init },
{"nativeFinalize", "()V", (void*)SurfaceTexture_finalize },
{"nativeSetDefaultBufferSize", "(II)V", (void*)SurfaceTexture_setDefaultBufferSize },
- {"nativeUpdateTexImage", "()V", (void*)SurfaceTexture_updateTexImage },
+ {"nativeUpdateTexImage", "()I", (void*)SurfaceTexture_updateTexImage },
{"nativeGetTransformMatrix", "([F)V", (void*)SurfaceTexture_getTransformMatrix },
{"nativeGetTimestamp", "()J", (void*)SurfaceTexture_getTimestamp },
{"nativeRelease", "()V", (void*)SurfaceTexture_release },
diff --git a/core/jni/android/graphics/TextLayoutCache.cpp b/core/jni/android/graphics/TextLayoutCache.cpp
index 79aa43b..7076e2a 100644
--- a/core/jni/android/graphics/TextLayoutCache.cpp
+++ b/core/jni/android/graphics/TextLayoutCache.cpp
@@ -249,7 +249,7 @@
flags(other.flags),
hinting(other.hinting) {
if (other.text) {
- textCopy.setTo(other.text);
+ textCopy.setTo(other.text, other.contextCount);
}
}
diff --git a/core/jni/android_nfc_NdefRecord.cpp b/core/jni/android_nfc_NdefRecord.cpp
index e8cc4c6..67907b6 100644
--- a/core/jni/android_nfc_NdefRecord.cpp
+++ b/core/jni/android_nfc_NdefRecord.cpp
@@ -149,7 +149,7 @@
/* Set flags field */
mFlags = e->GetFieldID(record_cls, "mFlags", "B");
- e->SetIntField(o, mFlags, record.Flags);
+ e->SetByteField(o, mFlags, record.Flags);
ret = 0;
diff --git a/core/jni/android_view_GLES20Canvas.cpp b/core/jni/android_view_GLES20Canvas.cpp
index e79de2d..4f75fad 100644
--- a/core/jni/android_view_GLES20Canvas.cpp
+++ b/core/jni/android_view_GLES20Canvas.cpp
@@ -134,6 +134,18 @@
}
}
+static void android_view_GLES20Canvas_initCaches(JNIEnv* env, jobject clazz) {
+ if (Caches::hasInstance()) {
+ Caches::getInstance().init();
+ }
+}
+
+static void android_view_GLES20Canvas_terminateCaches(JNIEnv* env, jobject clazz) {
+ if (Caches::hasInstance()) {
+ Caches::getInstance().terminate();
+ }
+}
+
// ----------------------------------------------------------------------------
// Constructors
// ----------------------------------------------------------------------------
@@ -756,6 +768,8 @@
{ "nPreserveBackBuffer", "()Z", (void*) android_view_GLES20Canvas_preserveBackBuffer },
{ "nDisableVsync", "()V", (void*) android_view_GLES20Canvas_disableVsync },
{ "nFlushCaches", "(I)V", (void*) android_view_GLES20Canvas_flushCaches },
+ { "nInitCaches", "()V", (void*) android_view_GLES20Canvas_initCaches },
+ { "nTerminateCaches", "()V", (void*) android_view_GLES20Canvas_terminateCaches },
{ "nCreateRenderer", "()I", (void*) android_view_GLES20Canvas_createRenderer },
{ "nDestroyRenderer", "(I)V", (void*) android_view_GLES20Canvas_destroyRenderer },
diff --git a/core/jni/android_view_HardwareRenderer.cpp b/core/jni/android_view_HardwareRenderer.cpp
new file mode 100644
index 0000000..09809ec
--- /dev/null
+++ b/core/jni/android_view_HardwareRenderer.cpp
@@ -0,0 +1,54 @@
+/*
+ * 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.
+ */
+
+#define LOG_TAG "HardwareRenderer"
+
+#include "jni.h"
+#include <nativehelper/JNIHelp.h>
+#include <android_runtime/AndroidRuntime.h>
+
+#include <EGL/egl_cache.h>
+
+namespace android {
+
+// ----------------------------------------------------------------------------
+// Misc
+// ----------------------------------------------------------------------------
+
+static void android_view_HardwareRenderer_setupShadersDiskCache(JNIEnv* env, jobject clazz,
+ jstring diskCachePath) {
+
+ const char* cacheArray = env->GetStringUTFChars(diskCachePath, NULL);
+ egl_cache_t::get()->setCacheFilename(cacheArray);
+ env->ReleaseStringUTFChars(diskCachePath, cacheArray);
+}
+
+// ----------------------------------------------------------------------------
+// JNI Glue
+// ----------------------------------------------------------------------------
+
+const char* const kClassPathName = "android/view/HardwareRenderer";
+
+static JNINativeMethod gMethods[] = {
+ { "nSetupShadersDiskCache", "(Ljava/lang/String;)V",
+ (void*) android_view_HardwareRenderer_setupShadersDiskCache },
+};
+
+int register_android_view_HardwareRenderer(JNIEnv* env) {
+ return AndroidRuntime::registerNativeMethods(env, kClassPathName, gMethods, NELEM(gMethods));
+}
+
+};
diff --git a/core/jni/com_google_android_gles_jni_EGLImpl.cpp b/core/jni/com_google_android_gles_jni_EGLImpl.cpp
index 02974f9a..4fe7600 100644
--- a/core/jni/com_google_android_gles_jni_EGLImpl.cpp
+++ b/core/jni/com_google_android_gles_jni_EGLImpl.cpp
@@ -24,6 +24,8 @@
#include <EGL/egl.h>
#include <GLES/gl.h>
+#include <EGL/egl_display.h>
+
#include <surfaceflinger/Surface.h>
#include <SkBitmap.h>
#include <SkPixelRef.h>
@@ -173,6 +175,16 @@
return success;
}
+static jint jni_getInitCount(JNIEnv *_env, jobject _clazz, jobject display) {
+ EGLDisplay dpy = getDisplay(_env, display);
+ egl_display_t* eglDisplay = get_display(dpy);
+ return eglDisplay ? eglDisplay->getRefsCount() : 0;
+}
+
+static jboolean jni_eglReleaseThread(JNIEnv *_env, jobject _this) {
+ return eglReleaseThread();
+}
+
static jboolean jni_eglChooseConfig(JNIEnv *_env, jobject _this, jobject display,
jintArray attrib_list, jobjectArray configs, jint config_size, jintArray num_config) {
if (display == NULL
@@ -526,6 +538,8 @@
{"eglInitialize", "(" DISPLAY "[I)Z", (void*)jni_eglInitialize },
{"eglQueryContext", "(" DISPLAY CONTEXT "I[I)Z", (void*)jni_eglQueryContext },
{"eglQuerySurface", "(" DISPLAY SURFACE "I[I)Z", (void*)jni_eglQuerySurface },
+{"eglReleaseThread","()Z", (void*)jni_eglReleaseThread },
+{"getInitCount", "(" DISPLAY ")I", (void*)jni_getInitCount },
{"eglChooseConfig", "(" DISPLAY "[I[" CONFIG "I[I)Z", (void*)jni_eglChooseConfig },
{"_eglCreateContext","(" DISPLAY CONFIG CONTEXT "[I)I", (void*)jni_eglCreateContext },
{"eglGetConfigs", "(" DISPLAY "[" CONFIG "I[I)Z", (void*)jni_eglGetConfigs },
diff --git a/core/res/res/drawable-hdpi/indicator_code_lock_drag_direction_green_up_holo.png b/core/res/res/drawable-hdpi/indicator_code_lock_drag_direction_green_up_holo.png
deleted file mode 100644
index a686975..0000000
--- a/core/res/res/drawable-hdpi/indicator_code_lock_drag_direction_green_up_holo.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-hdpi/indicator_code_lock_drag_direction_red_up_holo.png b/core/res/res/drawable-hdpi/indicator_code_lock_drag_direction_red_up_holo.png
deleted file mode 100644
index 92db8ef..0000000
--- a/core/res/res/drawable-hdpi/indicator_code_lock_drag_direction_red_up_holo.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-large-mdpi/btn_code_lock_default_holo.png b/core/res/res/drawable-large-mdpi/btn_code_lock_default_holo.png
deleted file mode 100644
index 45cc20d..0000000
--- a/core/res/res/drawable-large-mdpi/btn_code_lock_default_holo.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-large-mdpi/btn_code_lock_touched_holo.png b/core/res/res/drawable-large-mdpi/btn_code_lock_touched_holo.png
deleted file mode 100644
index 45cc20d..0000000
--- a/core/res/res/drawable-large-mdpi/btn_code_lock_touched_holo.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-large-mdpi/indicator_code_lock_point_area_default_holo.png b/core/res/res/drawable-large-mdpi/indicator_code_lock_point_area_default_holo.png
deleted file mode 100644
index fe72d00..0000000
--- a/core/res/res/drawable-large-mdpi/indicator_code_lock_point_area_default_holo.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-large-mdpi/indicator_code_lock_point_area_green_holo.png b/core/res/res/drawable-large-mdpi/indicator_code_lock_point_area_green_holo.png
deleted file mode 100644
index be666c6..0000000
--- a/core/res/res/drawable-large-mdpi/indicator_code_lock_point_area_green_holo.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-large-mdpi/indicator_code_lock_point_area_red_holo.png b/core/res/res/drawable-large-mdpi/indicator_code_lock_point_area_red_holo.png
deleted file mode 100644
index 9627197..0000000
--- a/core/res/res/drawable-large-mdpi/indicator_code_lock_point_area_red_holo.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-mdpi/indicator_code_lock_drag_direction_green_up_holo.png b/core/res/res/drawable-mdpi/indicator_code_lock_drag_direction_green_up_holo.png
deleted file mode 100644
index 89d209c..0000000
--- a/core/res/res/drawable-mdpi/indicator_code_lock_drag_direction_green_up_holo.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-mdpi/indicator_code_lock_drag_direction_red_up_holo.png b/core/res/res/drawable-mdpi/indicator_code_lock_drag_direction_red_up_holo.png
deleted file mode 100644
index 1d4cb32..0000000
--- a/core/res/res/drawable-mdpi/indicator_code_lock_drag_direction_red_up_holo.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-mdpi/indicator_code_lock_point_area_red.png b/core/res/res/drawable-mdpi/indicator_code_lock_point_area_red.png
deleted file mode 100644
index 9627197..0000000
--- a/core/res/res/drawable-mdpi/indicator_code_lock_point_area_red.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-large-mdpi/indicator_code_lock_drag_direction_red_up.png b/core/res/res/drawable-sw600dp-mdpi/indicator_code_lock_drag_direction_red_up.png
similarity index 100%
rename from core/res/res/drawable-large-mdpi/indicator_code_lock_drag_direction_red_up.png
rename to core/res/res/drawable-sw600dp-mdpi/indicator_code_lock_drag_direction_red_up.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/indicator_code_lock_drag_direction_green_up_holo.png b/core/res/res/drawable-xhdpi/indicator_code_lock_drag_direction_green_up_holo.png
deleted file mode 100644
index 66c1b58..0000000
--- a/core/res/res/drawable-xhdpi/indicator_code_lock_drag_direction_green_up_holo.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/indicator_code_lock_drag_direction_red_up_holo.png b/core/res/res/drawable-xhdpi/indicator_code_lock_drag_direction_red_up_holo.png
deleted file mode 100644
index b5f807f..0000000
--- a/core/res/res/drawable-xhdpi/indicator_code_lock_drag_direction_red_up_holo.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xlarge-hdpi/btn_code_lock_default.png b/core/res/res/drawable-xlarge-hdpi/btn_code_lock_default.png
deleted file mode 100644
index 719eb89..0000000
--- a/core/res/res/drawable-xlarge-hdpi/btn_code_lock_default.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xlarge-hdpi/btn_code_lock_touched.png b/core/res/res/drawable-xlarge-hdpi/btn_code_lock_touched.png
deleted file mode 100644
index 719eb89..0000000
--- a/core/res/res/drawable-xlarge-hdpi/btn_code_lock_touched.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xlarge-hdpi/ic_lock_idle_alarm.png b/core/res/res/drawable-xlarge-hdpi/ic_lock_idle_alarm.png
deleted file mode 100644
index 29cd471..0000000
--- a/core/res/res/drawable-xlarge-hdpi/ic_lock_idle_alarm.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xlarge-hdpi/ic_lock_idle_charging.png b/core/res/res/drawable-xlarge-hdpi/ic_lock_idle_charging.png
deleted file mode 100644
index 211aa0b..0000000
--- a/core/res/res/drawable-xlarge-hdpi/ic_lock_idle_charging.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xlarge-hdpi/ic_lock_idle_lock.png b/core/res/res/drawable-xlarge-hdpi/ic_lock_idle_lock.png
deleted file mode 100644
index 683ba22..0000000
--- a/core/res/res/drawable-xlarge-hdpi/ic_lock_idle_lock.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xlarge-hdpi/ic_lock_idle_low_battery.png b/core/res/res/drawable-xlarge-hdpi/ic_lock_idle_low_battery.png
deleted file mode 100644
index f4383f3..0000000
--- a/core/res/res/drawable-xlarge-hdpi/ic_lock_idle_low_battery.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xlarge-hdpi/indicator_code_lock_drag_direction_red_up.png b/core/res/res/drawable-xlarge-hdpi/indicator_code_lock_drag_direction_red_up.png
deleted file mode 100644
index a798863..0000000
--- a/core/res/res/drawable-xlarge-hdpi/indicator_code_lock_drag_direction_red_up.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xlarge-hdpi/indicator_code_lock_point_area_default.png b/core/res/res/drawable-xlarge-hdpi/indicator_code_lock_point_area_default.png
deleted file mode 100644
index 07e6165..0000000
--- a/core/res/res/drawable-xlarge-hdpi/indicator_code_lock_point_area_default.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xlarge-hdpi/indicator_code_lock_point_area_green.png b/core/res/res/drawable-xlarge-hdpi/indicator_code_lock_point_area_green.png
deleted file mode 100644
index ec17841..0000000
--- a/core/res/res/drawable-xlarge-hdpi/indicator_code_lock_point_area_green.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xlarge-hdpi/indicator_code_lock_point_area_red.png b/core/res/res/drawable-xlarge-hdpi/indicator_code_lock_point_area_red.png
deleted file mode 100644
index a0cb1ec..0000000
--- a/core/res/res/drawable-xlarge-hdpi/indicator_code_lock_point_area_red.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xlarge-hdpi/stat_notify_chat.png b/core/res/res/drawable-xlarge-hdpi/stat_notify_chat.png
deleted file mode 100644
index 8cc5535..0000000
--- a/core/res/res/drawable-xlarge-hdpi/stat_notify_chat.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xlarge-hdpi/stat_notify_disk_full.png b/core/res/res/drawable-xlarge-hdpi/stat_notify_disk_full.png
deleted file mode 100644
index 4441ba2..0000000
--- a/core/res/res/drawable-xlarge-hdpi/stat_notify_disk_full.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xlarge-hdpi/stat_notify_email_generic.png b/core/res/res/drawable-xlarge-hdpi/stat_notify_email_generic.png
deleted file mode 100644
index 73891a3..0000000
--- a/core/res/res/drawable-xlarge-hdpi/stat_notify_email_generic.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xlarge-hdpi/stat_notify_error.png b/core/res/res/drawable-xlarge-hdpi/stat_notify_error.png
deleted file mode 100644
index db68eea..0000000
--- a/core/res/res/drawable-xlarge-hdpi/stat_notify_error.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xlarge-hdpi/stat_notify_gmail.png b/core/res/res/drawable-xlarge-hdpi/stat_notify_gmail.png
deleted file mode 100644
index 7af6921..0000000
--- a/core/res/res/drawable-xlarge-hdpi/stat_notify_gmail.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xlarge-hdpi/stat_sys_battery_0.png b/core/res/res/drawable-xlarge-hdpi/stat_sys_battery_0.png
deleted file mode 100644
index 16424b9..0000000
--- a/core/res/res/drawable-xlarge-hdpi/stat_sys_battery_0.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xlarge-hdpi/stat_sys_battery_100.png b/core/res/res/drawable-xlarge-hdpi/stat_sys_battery_100.png
deleted file mode 100644
index 95cdc45..0000000
--- a/core/res/res/drawable-xlarge-hdpi/stat_sys_battery_100.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xlarge-hdpi/stat_sys_battery_15.png b/core/res/res/drawable-xlarge-hdpi/stat_sys_battery_15.png
deleted file mode 100644
index f61ccfa..0000000
--- a/core/res/res/drawable-xlarge-hdpi/stat_sys_battery_15.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xlarge-hdpi/stat_sys_battery_28.png b/core/res/res/drawable-xlarge-hdpi/stat_sys_battery_28.png
deleted file mode 100644
index 5666654..0000000
--- a/core/res/res/drawable-xlarge-hdpi/stat_sys_battery_28.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xlarge-hdpi/stat_sys_battery_43.png b/core/res/res/drawable-xlarge-hdpi/stat_sys_battery_43.png
deleted file mode 100644
index f9f4d81..0000000
--- a/core/res/res/drawable-xlarge-hdpi/stat_sys_battery_43.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xlarge-hdpi/stat_sys_battery_57.png b/core/res/res/drawable-xlarge-hdpi/stat_sys_battery_57.png
deleted file mode 100644
index 973ccc23..0000000
--- a/core/res/res/drawable-xlarge-hdpi/stat_sys_battery_57.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xlarge-hdpi/stat_sys_battery_71.png b/core/res/res/drawable-xlarge-hdpi/stat_sys_battery_71.png
deleted file mode 100644
index 1c7d446..0000000
--- a/core/res/res/drawable-xlarge-hdpi/stat_sys_battery_71.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xlarge-hdpi/stat_sys_battery_85.png b/core/res/res/drawable-xlarge-hdpi/stat_sys_battery_85.png
deleted file mode 100644
index 2120bdc..0000000
--- a/core/res/res/drawable-xlarge-hdpi/stat_sys_battery_85.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xlarge-hdpi/stat_sys_battery_charge_anim0.png b/core/res/res/drawable-xlarge-hdpi/stat_sys_battery_charge_anim0.png
deleted file mode 100644
index a526fcf..0000000
--- a/core/res/res/drawable-xlarge-hdpi/stat_sys_battery_charge_anim0.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xlarge-hdpi/stat_sys_battery_charge_anim100.png b/core/res/res/drawable-xlarge-hdpi/stat_sys_battery_charge_anim100.png
deleted file mode 100644
index 85be2e3..0000000
--- a/core/res/res/drawable-xlarge-hdpi/stat_sys_battery_charge_anim100.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xlarge-hdpi/stat_sys_battery_charge_anim15.png b/core/res/res/drawable-xlarge-hdpi/stat_sys_battery_charge_anim15.png
deleted file mode 100644
index 589b30b..0000000
--- a/core/res/res/drawable-xlarge-hdpi/stat_sys_battery_charge_anim15.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xlarge-hdpi/stat_sys_battery_charge_anim28.png b/core/res/res/drawable-xlarge-hdpi/stat_sys_battery_charge_anim28.png
deleted file mode 100644
index 4debfc0..0000000
--- a/core/res/res/drawable-xlarge-hdpi/stat_sys_battery_charge_anim28.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xlarge-hdpi/stat_sys_battery_charge_anim43.png b/core/res/res/drawable-xlarge-hdpi/stat_sys_battery_charge_anim43.png
deleted file mode 100644
index 3920ab1..0000000
--- a/core/res/res/drawable-xlarge-hdpi/stat_sys_battery_charge_anim43.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xlarge-hdpi/stat_sys_battery_charge_anim57.png b/core/res/res/drawable-xlarge-hdpi/stat_sys_battery_charge_anim57.png
deleted file mode 100644
index a15716f..0000000
--- a/core/res/res/drawable-xlarge-hdpi/stat_sys_battery_charge_anim57.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xlarge-hdpi/stat_sys_battery_charge_anim71.png b/core/res/res/drawable-xlarge-hdpi/stat_sys_battery_charge_anim71.png
deleted file mode 100644
index 8d7352f..0000000
--- a/core/res/res/drawable-xlarge-hdpi/stat_sys_battery_charge_anim71.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xlarge-hdpi/stat_sys_battery_charge_anim85.png b/core/res/res/drawable-xlarge-hdpi/stat_sys_battery_charge_anim85.png
deleted file mode 100644
index 45f8e81..0000000
--- a/core/res/res/drawable-xlarge-hdpi/stat_sys_battery_charge_anim85.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xlarge-hdpi/stat_sys_battery_unknown.png b/core/res/res/drawable-xlarge-hdpi/stat_sys_battery_unknown.png
deleted file mode 100644
index 696d9fb..0000000
--- a/core/res/res/drawable-xlarge-hdpi/stat_sys_battery_unknown.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xlarge-hdpi/unlock_default.png b/core/res/res/drawable-xlarge-hdpi/unlock_default.png
deleted file mode 100644
index 67311b9..0000000
--- a/core/res/res/drawable-xlarge-hdpi/unlock_default.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xlarge-hdpi/unlock_halo.png b/core/res/res/drawable-xlarge-hdpi/unlock_halo.png
deleted file mode 100644
index d841dea..0000000
--- a/core/res/res/drawable-xlarge-hdpi/unlock_halo.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xlarge-hdpi/unlock_ring.png b/core/res/res/drawable-xlarge-hdpi/unlock_ring.png
deleted file mode 100644
index 172efb8..0000000
--- a/core/res/res/drawable-xlarge-hdpi/unlock_ring.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xlarge-hdpi/unlock_wave.png b/core/res/res/drawable-xlarge-hdpi/unlock_wave.png
deleted file mode 100644
index 1ad26c3..0000000
--- a/core/res/res/drawable-xlarge-hdpi/unlock_wave.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xlarge-mdpi/ic_lock_idle_alarm.png b/core/res/res/drawable-xlarge-mdpi/ic_lock_idle_alarm.png
deleted file mode 100644
index 97ac023..0000000
--- a/core/res/res/drawable-xlarge-mdpi/ic_lock_idle_alarm.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xlarge-mdpi/ic_lock_idle_charging.png b/core/res/res/drawable-xlarge-mdpi/ic_lock_idle_charging.png
deleted file mode 100644
index 4210db2..0000000
--- a/core/res/res/drawable-xlarge-mdpi/ic_lock_idle_charging.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xlarge-mdpi/ic_lock_idle_lock.png b/core/res/res/drawable-xlarge-mdpi/ic_lock_idle_lock.png
deleted file mode 100644
index 1060f5a..0000000
--- a/core/res/res/drawable-xlarge-mdpi/ic_lock_idle_lock.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xlarge-mdpi/ic_lock_idle_low_battery.png b/core/res/res/drawable-xlarge-mdpi/ic_lock_idle_low_battery.png
deleted file mode 100644
index 72e4afa..0000000
--- a/core/res/res/drawable-xlarge-mdpi/ic_lock_idle_low_battery.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xlarge-mdpi/stat_notify_chat.png b/core/res/res/drawable-xlarge-mdpi/stat_notify_chat.png
deleted file mode 100644
index 22adc67..0000000
--- a/core/res/res/drawable-xlarge-mdpi/stat_notify_chat.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xlarge-mdpi/stat_notify_disk_full.png b/core/res/res/drawable-xlarge-mdpi/stat_notify_disk_full.png
deleted file mode 100644
index c434d12..0000000
--- a/core/res/res/drawable-xlarge-mdpi/stat_notify_disk_full.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xlarge-mdpi/stat_notify_email_generic.png b/core/res/res/drawable-xlarge-mdpi/stat_notify_email_generic.png
deleted file mode 100644
index daf3b84..0000000
--- a/core/res/res/drawable-xlarge-mdpi/stat_notify_email_generic.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xlarge-mdpi/stat_notify_error.png b/core/res/res/drawable-xlarge-mdpi/stat_notify_error.png
deleted file mode 100644
index 7b097b1..0000000
--- a/core/res/res/drawable-xlarge-mdpi/stat_notify_error.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xlarge-mdpi/stat_notify_gmail.png b/core/res/res/drawable-xlarge-mdpi/stat_notify_gmail.png
deleted file mode 100644
index 8daef7c..0000000
--- a/core/res/res/drawable-xlarge-mdpi/stat_notify_gmail.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xlarge-mdpi/stat_sys_battery_0.png b/core/res/res/drawable-xlarge-mdpi/stat_sys_battery_0.png
deleted file mode 100644
index ad48321..0000000
--- a/core/res/res/drawable-xlarge-mdpi/stat_sys_battery_0.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xlarge-mdpi/stat_sys_battery_100.png b/core/res/res/drawable-xlarge-mdpi/stat_sys_battery_100.png
deleted file mode 100644
index 16481d6..0000000
--- a/core/res/res/drawable-xlarge-mdpi/stat_sys_battery_100.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xlarge-mdpi/stat_sys_battery_15.png b/core/res/res/drawable-xlarge-mdpi/stat_sys_battery_15.png
deleted file mode 100644
index c3cdcc8..0000000
--- a/core/res/res/drawable-xlarge-mdpi/stat_sys_battery_15.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xlarge-mdpi/stat_sys_battery_28.png b/core/res/res/drawable-xlarge-mdpi/stat_sys_battery_28.png
deleted file mode 100644
index ec58d31..0000000
--- a/core/res/res/drawable-xlarge-mdpi/stat_sys_battery_28.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xlarge-mdpi/stat_sys_battery_43.png b/core/res/res/drawable-xlarge-mdpi/stat_sys_battery_43.png
deleted file mode 100644
index 1fb3696..0000000
--- a/core/res/res/drawable-xlarge-mdpi/stat_sys_battery_43.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xlarge-mdpi/stat_sys_battery_57.png b/core/res/res/drawable-xlarge-mdpi/stat_sys_battery_57.png
deleted file mode 100644
index d6d143a..0000000
--- a/core/res/res/drawable-xlarge-mdpi/stat_sys_battery_57.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xlarge-mdpi/stat_sys_battery_71.png b/core/res/res/drawable-xlarge-mdpi/stat_sys_battery_71.png
deleted file mode 100644
index 8de99fa..0000000
--- a/core/res/res/drawable-xlarge-mdpi/stat_sys_battery_71.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xlarge-mdpi/stat_sys_battery_85.png b/core/res/res/drawable-xlarge-mdpi/stat_sys_battery_85.png
deleted file mode 100644
index 4600b25..0000000
--- a/core/res/res/drawable-xlarge-mdpi/stat_sys_battery_85.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xlarge-mdpi/stat_sys_battery_charge_anim0.png b/core/res/res/drawable-xlarge-mdpi/stat_sys_battery_charge_anim0.png
deleted file mode 100644
index 3640f55..0000000
--- a/core/res/res/drawable-xlarge-mdpi/stat_sys_battery_charge_anim0.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xlarge-mdpi/stat_sys_battery_charge_anim100.png b/core/res/res/drawable-xlarge-mdpi/stat_sys_battery_charge_anim100.png
deleted file mode 100644
index 53af703..0000000
--- a/core/res/res/drawable-xlarge-mdpi/stat_sys_battery_charge_anim100.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xlarge-mdpi/stat_sys_battery_charge_anim15.png b/core/res/res/drawable-xlarge-mdpi/stat_sys_battery_charge_anim15.png
deleted file mode 100644
index c2282e6..0000000
--- a/core/res/res/drawable-xlarge-mdpi/stat_sys_battery_charge_anim15.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xlarge-mdpi/stat_sys_battery_charge_anim28.png b/core/res/res/drawable-xlarge-mdpi/stat_sys_battery_charge_anim28.png
deleted file mode 100644
index 704f962..0000000
--- a/core/res/res/drawable-xlarge-mdpi/stat_sys_battery_charge_anim28.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xlarge-mdpi/stat_sys_battery_charge_anim43.png b/core/res/res/drawable-xlarge-mdpi/stat_sys_battery_charge_anim43.png
deleted file mode 100644
index b275dbb..0000000
--- a/core/res/res/drawable-xlarge-mdpi/stat_sys_battery_charge_anim43.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xlarge-mdpi/stat_sys_battery_charge_anim57.png b/core/res/res/drawable-xlarge-mdpi/stat_sys_battery_charge_anim57.png
deleted file mode 100644
index 5b0649f..0000000
--- a/core/res/res/drawable-xlarge-mdpi/stat_sys_battery_charge_anim57.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xlarge-mdpi/stat_sys_battery_charge_anim71.png b/core/res/res/drawable-xlarge-mdpi/stat_sys_battery_charge_anim71.png
deleted file mode 100644
index 8bc888e..0000000
--- a/core/res/res/drawable-xlarge-mdpi/stat_sys_battery_charge_anim71.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xlarge-mdpi/stat_sys_battery_charge_anim85.png b/core/res/res/drawable-xlarge-mdpi/stat_sys_battery_charge_anim85.png
deleted file mode 100644
index ede370d..0000000
--- a/core/res/res/drawable-xlarge-mdpi/stat_sys_battery_charge_anim85.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xlarge-mdpi/stat_sys_battery_unknown.png b/core/res/res/drawable-xlarge-mdpi/stat_sys_battery_unknown.png
deleted file mode 100644
index 5f39f62..0000000
--- a/core/res/res/drawable-xlarge-mdpi/stat_sys_battery_unknown.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xlarge-xhdpi/btn_code_lock_default.png b/core/res/res/drawable-xlarge-xhdpi/btn_code_lock_default.png
deleted file mode 100644
index 9f7a132..0000000
--- a/core/res/res/drawable-xlarge-xhdpi/btn_code_lock_default.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xlarge-xhdpi/btn_code_lock_touched.png b/core/res/res/drawable-xlarge-xhdpi/btn_code_lock_touched.png
deleted file mode 100644
index 9f7a132..0000000
--- a/core/res/res/drawable-xlarge-xhdpi/btn_code_lock_touched.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xlarge-xhdpi/indicator_code_lock_point_area_default.png b/core/res/res/drawable-xlarge-xhdpi/indicator_code_lock_point_area_default.png
deleted file mode 100644
index 6662eb1..0000000
--- a/core/res/res/drawable-xlarge-xhdpi/indicator_code_lock_point_area_default.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xlarge-xhdpi/indicator_code_lock_point_area_green.png b/core/res/res/drawable-xlarge-xhdpi/indicator_code_lock_point_area_green.png
deleted file mode 100644
index dce220a..0000000
--- a/core/res/res/drawable-xlarge-xhdpi/indicator_code_lock_point_area_green.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xlarge-xhdpi/indicator_code_lock_point_area_red.png b/core/res/res/drawable-xlarge-xhdpi/indicator_code_lock_point_area_red.png
deleted file mode 100644
index 746a3ea..0000000
--- a/core/res/res/drawable-xlarge-xhdpi/indicator_code_lock_point_area_red.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 9b8be85..c8ba26a 100755
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -1,4 +1,4 @@
-<?xml version="1.0" encoding="utf-8"?>
+<?xml version="1.0" encoding="utf-8"?>
<!--
/* //device/apps/common/assets/res/any/strings.xml
**
@@ -3365,4 +3365,13 @@
<!-- Delimeter used between each item in a textual list; for example "Alpha, Beta". [CHAR LIMIT=3] -->
<string name="list_delimeter">", "</string>
+ <!-- STK sending DTMF, SMS, USSD, SS -->
+ <string name="sending">Sending...</string>
+
+ <!-- STK launch Browser -->
+ <string name="launchBrowserDefault">Launch Browser?</string>
+
+ <!-- STK setup Call -->
+ <string name="SetupCallDefault">Accept Call?</string>
+
</resources>
diff --git a/data/sounds/AudioPackage5.mk b/data/sounds/AudioPackage5.mk
index 550f990..5961f06 100755
--- a/data/sounds/AudioPackage5.mk
+++ b/data/sounds/AudioPackage5.mk
@@ -20,6 +20,7 @@
$(LOCAL_PATH)/effects/KeypressReturn.ogg:system/media/audio/ui/KeypressReturn.ogg \
$(LOCAL_PATH)/effects/VideoRecord.ogg:system/media/audio/ui/VideoRecord.ogg \
$(LOCAL_PATH)/effects/camera_click.ogg:system/media/audio/ui/camera_click.ogg \
+ $(LOCAL_PATH)/effects/ogg/camera_focus.ogg:system/media/audio/ui/camera_focus.ogg \
$(LOCAL_PATH)/effects/LowBattery.ogg:system/media/audio/ui/LowBattery.ogg \
$(LOCAL_PATH)/effects/Dock.ogg:system/media/audio/ui/Dock.ogg \
$(LOCAL_PATH)/effects/Undock.ogg:system/media/audio/ui/Undock.ogg \
diff --git a/data/sounds/AudioPackage6.mk b/data/sounds/AudioPackage6.mk
index 610e821..d113a29 100755
--- a/data/sounds/AudioPackage6.mk
+++ b/data/sounds/AudioPackage6.mk
@@ -19,6 +19,7 @@
$(LOCAL_PATH)/effects/ogg/KeypressReturn.ogg:system/media/audio/ui/KeypressReturn.ogg \
$(LOCAL_PATH)/effects/ogg/VideoRecord.ogg:system/media/audio/ui/VideoRecord.ogg \
$(LOCAL_PATH)/effects/ogg/camera_click.ogg:system/media/audio/ui/camera_click.ogg \
+ $(LOCAL_PATH)/effects/ogg/camera_focus.ogg:system/media/audio/ui/camera_focus.ogg \
$(LOCAL_PATH)/effects/ogg/LowBattery.ogg:system/media/audio/ui/LowBattery.ogg \
$(LOCAL_PATH)/effects/ogg/Dock.ogg:system/media/audio/ui/Dock.ogg \
$(LOCAL_PATH)/effects/ogg/Undock.ogg:system/media/audio/ui/Undock.ogg \
diff --git a/data/sounds/AudioPackage7.mk b/data/sounds/AudioPackage7.mk
index 93e0fa0..6ae624e 100755
--- a/data/sounds/AudioPackage7.mk
+++ b/data/sounds/AudioPackage7.mk
@@ -21,6 +21,7 @@
$(LOCAL_PATH)/effects/ogg/KeypressReturn_120.ogg:system/media/audio/ui/KeypressReturn.ogg \
$(LOCAL_PATH)/effects/ogg/VideoRecord.ogg:system/media/audio/ui/VideoRecord.ogg \
$(LOCAL_PATH)/effects/ogg/camera_click.ogg:system/media/audio/ui/camera_click.ogg \
+ $(LOCAL_PATH)/effects/ogg/camera_focus.ogg:system/media/audio/ui/camera_focus.ogg \
$(LOCAL_PATH)/effects/ogg/LowBattery.ogg:system/media/audio/ui/LowBattery.ogg \
$(LOCAL_PATH)/effects/ogg/Dock.ogg:system/media/audio/ui/Dock.ogg \
$(LOCAL_PATH)/effects/ogg/Undock.ogg:system/media/audio/ui/Undock.ogg \
diff --git a/data/sounds/effects/ogg/camera_focus.ogg b/data/sounds/effects/ogg/camera_focus.ogg
new file mode 100644
index 0000000..0db2683
--- /dev/null
+++ b/data/sounds/effects/ogg/camera_focus.ogg
Binary files differ
diff --git a/docs/html/guide/developing/building/building-cmdline.jd b/docs/html/guide/developing/building/building-cmdline.jd
index d78a4f5..c43962a 100644
--- a/docs/html/guide/developing/building/building-cmdline.jd
+++ b/docs/html/guide/developing/building/building-cmdline.jd
@@ -365,7 +365,7 @@
<dd>Builds a test project and the tested project, installs both <code>.apk</code> files, and
runs the tests.</dd>
- <dt><code>ant emma debug installt test</code></dt>
+ <dt><code>ant emma debug install test</code></dt>
<dd>Builds a test project and the tested project, installs both <code>.apk</code> files, and
runs the tests with code coverage enabled.</dd>
diff --git a/docs/html/guide/guide_toc.cs b/docs/html/guide/guide_toc.cs
index a3bb6d4..0338685 100644
--- a/docs/html/guide/guide_toc.cs
+++ b/docs/html/guide/guide_toc.cs
@@ -82,9 +82,17 @@
</a></li>
</ul>
</li>
- <li><a href="<?cs var:toroot ?>guide/topics/providers/content-providers.html">
+ <li class="toggle-list">
+ <div><a href="<?cs var:toroot ?>guide/topics/providers/content-providers.html">
<span class="en">Content Providers</span>
- </a></li>
+ </a><span class="new">updated</span></div>
+ <ul>
+ <li><a href="<?cs var:toroot ?>guide/topics/providers/calendar-provider.html">
+ <span class="en">Calendar Provider</span></a>
+ <span class="new">new!</span>
+ </li>
+ </ul>
+ </li>
<li><a href="<?cs var:toroot ?>guide/topics/intents/intents-filters.html">
<span class="en">Intents and Intent Filters</span>
</a></li>
diff --git a/docs/html/guide/topics/providers/calendar-provider.jd b/docs/html/guide/topics/providers/calendar-provider.jd
new file mode 100644
index 0000000..3ab5125
--- /dev/null
+++ b/docs/html/guide/topics/providers/calendar-provider.jd
@@ -0,0 +1,1185 @@
+page.title=Calendar Provider
+@jd:body
+
+<div id="qv-wrapper">
+<div id="qv">
+ <h2>In this document</h2>
+ <ol>
+ <li><a href="#overview">Basics</a></li>
+ <li><a href="#manifest">User Permissions</a></li>
+ <li><a href="#calendar">Calendars table</a>
+<ol>
+ <li><a href="#query">Querying a calendar</a></li>
+ <li><a href="#modify-calendar">Modifying a calendar</a></li>
+ <li><a href="#insert-calendar">Inserting a calendar</a></li>
+ </ol>
+ </li>
+ <li><a href="#events">Events table</a>
+<ol>
+ <li><a href="#add-event">Adding Events</a></li>
+ <li><a href="#update-event">Updating Events</a></li>
+ <li><a href="#delete-event">Deleting Events</a></li>
+ </ol>
+ </li>
+ <li><a href="#attendees">Attendees table</a>
+<ol>
+ <li><a href="#add-attendees">Adding Attendees</a></li>
+ </ol>
+ </li>
+ <li><a href="#reminders">Reminders table</a>
+<ol>
+ <li><a href="#add-reminders">Adding Reminders</a></li>
+ </ol>
+ </li>
+ <li><a href="#instances">Instances table</a>
+ <ol>
+ <li><a href="#query-instances">Querying the Instances table</a></li>
+ </ol></li>
+ <li><a href="#intents">Calendar Intents</a>
+ <ol>
+ <li><a href="#intent-insert">Using an intent to insert an event</a></li>
+ <li><a href="#intent-edit">Using an intent to edit an event</a></li>
+ <li><a href="#intent-view">Using intents to view calendar data</a></li>
+ </ol>
+ </li>
+
+ <li><a href="#sync-adapter">Sync Adapters</a></li>
+</ol>
+
+ <h2>Key classes</h2>
+ <ol>
+ <li>{@link android.provider.CalendarContract.Calendars}</li>
+ <li>{@link android.provider.CalendarContract.Events}</li>
+ <li>{@link android.provider.CalendarContract.Attendees}</li>
+ <li>{@link android.provider.CalendarContract.Reminders}</li>
+ </ol>
+</div>
+</div>
+
+<p>The Calendar Provider is a repository for a user's calendar events. The
+Calendar Provider API allows you to perform query, insert, update, and delete
+operations on calendars, events, attendees, reminders, and so on.</p>
+
+
+<p>The Calender Provider API can be used by applications and sync adapters. The
+rules vary depending on what type of program is making the calls. This document
+focuses primarily on using the Calendar Provider API as an application. For
+a discussion of how sync adapters are different, see
+<a href="#sync-adapter">Sync Adapters</a>.</p>
+
+
+<p>Normally, to read or write calendar data, an application's manifest must
+include the proper permissions, described in <a href="#manifest">User
+Permissions</a>. To make performing common operations easier, the Calendar
+Provider offers a set of intents, as described in <a href="#intents">Calendar
+Intents</a>. These intents take users to the Calendar application to insert, view,
+and edit events. The user interacts with the Calendar application and then
+returns to the original application. Thus your application doesn't need to request permissions,
+nor does it need to provide a user interface to view or create events.</p>
+
+<h2 id="overview">Basics</h2>
+
+<p><a href="{@docRoot}guide/topics/providers/content-providers.html">Content providers</a> store data and make it accessible to
+applications. The content providers offered by the Android platform (including the Calendar Provider) typically expose data as a set of tables based on a
+relational database model, where each row is a record and each column is data of
+a particular type and meaning. Through the Calendar Provider API, applications
+and sync adapters can get read/write access to the database tables that hold a
+user's calendar data.</p>
+
+<p>Every content provider exposes a public URI (wrapped as a
+{@link android.net.Uri}
+object) that uniquely identifies its data set. A content provider that controls
+ multiple data sets (multiple tables) exposes a separate URI for each one. All
+URIs for providers begin with the string "content://". This
+identifies the data as being controlled by a content provider. The Calendar
+Provider defines constants for the URIs for each of its classes (tables). These
+URIs have the format <code><em><class></em>.CONTENT_URI</code>. For
+example, {@link android.provider.CalendarContract.Events#CONTENT_URI Events.CONTENT_URI}.</p>
+
+<p>Figure 1 shows a graphical representation of the Calendar Provider data model. It shows the
+main tables and the fields that link them to each other.</p>
+
+<img src="{@docRoot}images/providers/datamodel.png" alt="Calendar Provider Data Model"/>
+<p class="img-caption"><strong>Figure 1.</strong> Calendar Provider data model.</p>
+
+<p>A user can have multiple calendars, and different calendars can be associated with different types of accounts (Google Calendar, Exchange, and so on).</p>
+
+<p>The {@link android.provider.CalendarContract} defines the data model of calendar and event related information. This data is stored in a number of tables, listed below.</p>
+
+<table>
+ <tr>
+ <th>Table (Class)</th>
+ <th>Description</th>
+ </tr>
+ <tr>
+ <td><p>{@link android.provider.CalendarContract.Calendars}</p></td>
+
+ <td>This table holds
+the calendar-specific information. Each row in this table contains the details for
+a single calendar, such as the name, color, sync information, and so on.</td>
+ </tr>
+ <tr>
+ <td>{@link android.provider.CalendarContract.Events}</td>
+
+ <td>This table holds the
+event-specific information. Each row in this table has the information for a single
+event—for example, event title, location, start time, end
+time, and so on. The event can occur one-time or can recur multiple times. Attendees,
+reminders, and extended properties are stored in separate tables.
+They each have an {@link android.provider.CalendarContract.AttendeesColumns#EVENT_ID}
+that references the {@link android.provider.BaseColumns#_ID} in the Events table.</td>
+
+ </tr>
+ <tr>
+ <td>{@link android.provider.CalendarContract.Instances}</td>
+
+ <td>This table holds the
+start and end time for each occurrence of an event. Each row in this table
+represents a single event occurrence. For one-time events there is a 1:1 mapping
+of instances to events. For recurring events, multiple rows are automatically
+ generated that correspond to multiple occurrences of that event.</td>
+ </tr>
+ <tr>
+ <td>{@link android.provider.CalendarContract.Attendees}</td>
+
+ <td>This table holds the
+event attendee (guest) information. Each row represents a single guest of an
+event. It specifies the type of guest and the guest's attendance response
+for the event.</td>
+ </tr>
+ <tr>
+ <td>{@link android.provider.CalendarContract.Reminders}</td>
+
+ <td>This table holds the
+alert/notification data. Each row represents a single alert for an event. An
+event can have multiple reminders. The maximum number of reminders per event is
+specified in
+{@link android.provider.CalendarContract.CalendarColumns#MAX_REMINDERS},
+which is set by the sync adapter that
+owns the given calendar. Reminders are specified in minutes before the event
+and have a method that determines how the user will be alerted.</td>
+ </tr>
+
+</table>
+
+<p>The Calendar Provider API is designed to be flexible and powerful. At the
+same time, it's important to provide a good end user experience and
+protect the integrity of the calendar and its data. To this end, here are
+some things to keep in mind when using the API:</p>
+
+<ul>
+
+<li><strong>Inserting, updating, and viewing calendar events.</strong> To directly insert, modify, and read events from the Calendar Provider, you need the appropriate <a href="#manifest">permissions</a>. However, if you're not building a full-fledged calendar application or sync adapter, requesting these permissions isn't necessary. You can instead use intents supported by Android's Calendar application to hand off read and write operations to that application. When you use the intents, your application sends users to the Calendar application to perform the desired operation
+in a pre-filled form. After they're done, they're returned to your application.
+By designing your application to perform common operations through the Calendar,
+you provide users with a consistent, robust user interface. This is the
+recommended approach. For more information, see <a href="#intents">Calendar
+Intents</a>.</p>
+
+
+<li><strong>Sync adapters.</strong> A sync adapter synchronizes the calendar data
+on a user's device with another server or data source. In the
+{@link android.provider.CalendarContract.Calendars} and
+{@link android.provider.CalendarContract.Events} tables,
+there are columns that are reserved for the sync adapters to use.
+The provider and applications should not modify them. In fact, they are not
+visible unless they are accessed as a sync adapter. For more information about
+sync adapters, see <a href="#sync-adapter">Sync Adapters</a>.</li>
+
+</ul>
+
+
+<h2 id="manifest">User Permissions</h2>
+
+<p>To read calendar data, an application must include the {@link
+android.Manifest.permission#READ_CALENDAR} permission in its manifest file. It
+must include the {@link android.Manifest.permission#WRITE_CALENDAR} permission
+to delete, insert or update calendar data:</p>
+
+<pre>
+<?xml version="1.0" encoding="utf-8"?>
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"...>
+ <uses-sdk android:minSdkVersion="14" />
+ <uses-permission android:name="android.permission.READ_CALENDAR" />
+ <uses-permission android:name="android.permission.WRITE_CALENDAR" />
+ ...
+</manifest>
+</pre>
+
+
+<h2 id="calendar">Calendars Table</h2>
+
+<p>The {@link android.provider.CalendarContract.Calendars} table contains details
+for individual calendars. The following
+Calendars columns are writable by both an application and a <a href="#sync-adapter">sync adapter</a>.
+For a full list of supported fields, see the
+{@link android.provider.CalendarContract.Calendars} reference.</p>
+<table>
+ <tr>
+ <th>Constant</th>
+ <th>Description</th>
+ </tr>
+ <tr>
+ <td>{@link android.provider.CalendarContract.Calendars#NAME}</td>
+ <td>The name of the calendar.</td>
+ </tr>
+ <tr>
+ <td>{@link android.provider.CalendarContract.Calendars#CALENDAR_DISPLAY_NAME}</td>
+ <td>The name of this calendar that is displayed to the user.</td>
+ </tr>
+ <tr>
+ <td>{@link android.provider.CalendarContract.Calendars#VISIBLE}</td>
+
+ <td>A boolean indicating whether the calendar is selected to be displayed. A
+value of 0 indicates that events associated with this calendar should not be
+shown. A value of 1 indicates that events associated with this calendar should
+be shown. This value affects the generation of rows in the {@link
+android.provider.CalendarContract.Instances} table.</td>
+
+
+ </tr>
+ <tr>
+ <td>{@link android.provider.CalendarContract.CalendarColumns#SYNC_EVENTS}</td>
+
+ <td>A boolean indicating whether the calendar should be synced and have its
+events stored on the device. A value of 0 says do not sync this calendar or
+store its events on the device. A value of 1 says sync events for this calendar
+and store its events on the device.</td>
+ </tr>
+</table>
+
+<h3 id="query">Querying a calendar</h3>
+
+<p>Here is an example that shows how to get all the calendars for a particular
+user. For simplicity's sake, in this example the query operation is shown in the
+user interface thread ("main thread"). In practice, this should be done in an asynchronous
+thread instead of on the main thread. For more discussion, see
+<a href="{@docRoot}guide/topics/fundamentals/loaders.html">Loaders</a>. If you are not just reading data but modifying it, see {@link android.content.AsyncQueryHandler}.
+</p>
+
+
+<pre>
+ // Projection array. Creating indices for this array instead of doing
+ // dynamic lookups improves performance.
+ public static final String[] EVENT_PROJECTION = new String[] {
+ Calendars._ID, // 0
+ Calendars.ACCOUNT_NAME, // 1
+ Calendars.CALENDAR_DISPLAY_NAME // 2
+ };
+
+ // The indices for the projection array above.
+ private static final int PROJECTION_ID_INDEX = 0;
+ private static final int PROJECTION_ACCOUNT_NAME_INDEX = 1;
+ private static final int PROJECTION_DISPLAY_NAME_INDEX = 2;</pre>
+
+
+<div class="sidebox-wrapper"> <div class="sidebox"> <h3>Why must you include
+ACCOUNT_TYPE?</h3> <p>If you query on a {@link
+android.provider.CalendarContract.Calendars#ACCOUNT_NAME
+Calendars.ACCOUNT_NAME}, you must also include
+{@link android.provider.CalendarContract.Calendars#ACCOUNT_TYPE Calendars.ACCOUNT_TYPE}
+in the selection. That is because a given account is
+only considered unique given both its <code>ACCOUNT_NAME</code> and its
+<code>ACCOUNT_TYPE</code>. The <code>ACCOUNT_TYPE</code> refers to the way that
+the account is being synced. It is often but not always the domain. For
+example, an account could be synced through a corporate pop3 sync adapter, in which
+case the <code>ACCOUNT_TYPE</code> would not be a domain. There is also a
+special type of account called {@link
+android.provider.CalendarContract#ACCOUNT_TYPE_LOCAL} for calendars not
+associated with a device account. {@link
+android.provider.CalendarContract#ACCOUNT_TYPE_LOCAL} accounts do not get
+synced.</p> </div> </div>
+
+
+<p> In the next part of the example, you construct your query. The selection
+specifies the criteria for the query. In this example the query is looking for
+all calendars that have the <code>ACCOUNT_NAME</code>
+"sampleuser@google.com" and the <code>ACCOUNT_TYPE</code>
+"com.google". The query returns a {@link android.database.Cursor}
+object that you can use to traverse the result set returned by the database
+query. For more discussion of using queries in content providers, see <a href="{@docRoot}guide/topics/providers/content-providers.html">Content Providers</a>.</p>
+
+
+<pre>// Run query
+Cursor cur = null;
+ContentResolver cr = getContentResolver();
+Uri uri = Calendars.CONTENT_URI;
+String selection = "((" + Calendars.ACCOUNT_NAME + " = ?) AND ("
+ + Calendars.ACCOUNT_TYPE + " = ?))";
+String[] selectionArgs = new String[] {"sampleuser@gmail.com", "com.google"};
+// Submit the query and get a Cursor object back.
+cur = cr.query(uri, EVENT_PROJECTION, selection, selectionArgs, null);</pre>
+
+<p>This next section uses the cursor to step through the result set. It uses the
+constants that were set up at the beginning of the example to return the values
+for each field.</p>
+
+<pre>// Use the cursor to step through the returned records
+while (cur.moveToNext()) {
+ long calID = 0;
+ String displayName = null;
+ String accountName = null;
+
+ // Get the field values
+ calID = cur.getLong(PROJECTION_ID_INDEX);
+ displayName = cur.getString(PROJECTION_DISPLAY_NAME_INDEX);
+ accountName = cur.getString(PROJECTION_ACCOUNT_NAME_INDEX);
+
+ // Do something with the values...
+
+ ...
+}
+</pre>
+
+<h3 id="modify-calendar">Modifying a calendar</h3>
+
+<p>To perform an update of an calendar, you can provide the {@link
+android.provider.BaseColumns#_ID} of the calendar either as an appended ID to
+the Uri
+
+({@link android.content.ContentUris#withAppendedId(android.net.Uri,long) withAppendedId()})
+or as the first selection item. The selection
+should start with <code>"_id=?"</code>, and the first
+<code>selectionArg</code> should be the {@link
+android.provider.BaseColumns#_ID} of the calendar.
+You can also do updates by encoding the ID in the URI. This example changes a
+calendar's display name using the
+({@link android.content.ContentUris#withAppendedId(android.net.Uri,long) withAppendedId()})
+approach:</p>
+
+<pre>private static final String DEBUG_TAG = "MyActivity";
+...
+long calID = 2;
+ContentValues values = new ContentValues();
+// The new display name for the calendar
+values.put(Calendars.CALENDAR_DISPLAY_NAME, "Trevor's Calendar");
+Uri updateUri = ContentUris.withAppendedId(Calendars.CONTENT_URI, calID);
+int rows = getContentResolver().update(updateUri, values, null, null);
+Log.i(DEBUG_TAG, "Rows updated: " + rows);</pre>
+
+<h3 id="insert-calendar">Inserting a calendar</h2>
+
+<p>Calendars are designed to be primarily managed by a sync adapter, so you
+should only insert new calendars as a sync adapter. For the most part,
+applications can only make superficial changes to calendars, such as changing the display name. If
+an application needs to create a local calendar, it can do this by performing
+the calendar insertion as a sync adapter, using an {@link
+android.provider.CalendarContract.SyncColumns#ACCOUNT_TYPE} of {@link
+android.provider.CalendarContract#ACCOUNT_TYPE_LOCAL}.
+{@link android.provider.CalendarContract#ACCOUNT_TYPE_LOCAL}
+is a special account type for calendars that are not
+associated with a device account. Calendars of this type are not synced to a server. For a
+discussion of sync adapters, see <a href="#sync-adapter">Sync Adapters</a>.</p>
+
+<h2 id="events">Events Table</h2>
+
+<p>The {@link android.provider.CalendarContract.Events} table contains details
+for individual events. To add, update, or delete events, an application must
+include the {@link android.Manifest.permission#WRITE_CALENDAR} permission in its
+<a href="#manifest">manifest file</a>.</p>
+
+<p>The following Events columns are writable by both an application and a sync
+adapter. For a full list of supported fields, see the {@link
+android.provider.CalendarContract.Events} reference.</p>
+
+<table>
+ <tr>
+ <th>Constant</th>
+ <th>Description</th>
+ </tr>
+ <tr>
+ <td>{@link android.provider.CalendarContract.EventsColumns#CALENDAR_ID}</td>
+ <td>The {@link android.provider.BaseColumns#_ID} of the calendar the event belongs to.</td>
+ </tr>
+ <tr>
+ <td>{@link android.provider.CalendarContract.EventsColumns#ORGANIZER}</td>
+ <td>Email of the organizer (owner) of the event.</td>
+ </tr>
+ <tr>
+ <td>{@link android.provider.CalendarContract.EventsColumns#TITLE}</td>
+ <td>The title of the event.</td>
+ </tr>
+ <tr>
+ <td>{@link android.provider.CalendarContract.EventsColumns#EVENT_LOCATION}</td>
+ <td>Where the event takes place. </td>
+ </tr>
+ <tr>
+ <td>{@link android.provider.CalendarContract.EventsColumns#DESCRIPTION}</td>
+ <td>The description of the event.</td>
+ </tr>
+ <tr>
+ <td>{@link android.provider.CalendarContract.EventsColumns#DTSTART}</td>
+ <td>The time the event starts in UTC milliseconds since the epoch. </td>
+ </tr>
+ <tr>
+ <td>{@link android.provider.CalendarContract.EventsColumns#DTEND}</td>
+ <td>The time the event ends in UTC milliseconds since the epoch. </td>
+ </tr>
+ <tr>
+ <td>{@link android.provider.CalendarContract.EventsColumns#EVENT_TIMEZONE}</td>
+ <td>The time zone for the event.</td>
+ </tr>
+ <tr>
+ <td>{@link android.provider.CalendarContract.EventsColumns#EVENT_END_TIMEZONE}</td>
+ <td>The time zone for the end time of the event.</td>
+ </tr>
+ <tr>
+ <td>{@link android.provider.CalendarContract.EventsColumns#DURATION}</td>
+
+ <td>The duration of the event in <a
+href="http://tools.ietf.org/html/rfc5545#section-3.8.2.5">RFC5545</a> format.
+For example, a value of <code>"PT1H"</code> states that the event
+should last one hour, and a value of <code>"P2W"</code> indicates a
+duration of 2 weeks. </td>
+
+
+ </tr>
+ <tr>
+ <td>{@link android.provider.CalendarContract.EventsColumns#ALL_DAY}</td>
+
+ <td>A value of 1 indicates this event occupies the entire day, as defined by
+the local time zone. A value of 0 indicates it is a regular event that may start
+and end at any time during a day.</td>
+
+
+ </tr>
+
+
+ <tr>
+ <td>{@link android.provider.CalendarContract.EventsColumns#RRULE}</td>
+
+ <td>The recurrence rule for the event format. For
+example, <code>"FREQ=WEEKLY;COUNT=10;WKST=SU"</code>. You can find
+more examples <a
+href="http://tools.ietf.org/html/rfc5545#section-3.8.5.3">here</a>.</td>
+
+ </tr>
+
+ <tr>
+ <td>{@link android.provider.CalendarContract.EventsColumns#RDATE}</td>
+ <td>The recurrence dates for the event.
+ You typically use {@link android.provider.CalendarContract.EventsColumns#RDATE}
+ in conjunction with {@link android.provider.CalendarContract.EventsColumns#RRULE}
+ to define an aggregate set of
+repeating occurrences. For more discussion, see the <a
+href="http://tools.ietf.org/html/rfc5545#section-3.8.5.2">RFC5545 spec</a>.</td>
+</tr>
+
+ <tr>
+ <td>{@link android.provider.CalendarContract.EventsColumns#AVAILABILITY}</td>
+
+ <td>If this event counts as busy time or is free time that can be
+scheduled over. </td>
+
+ </tr>
+ <tr>
+ <td>{@link android.provider.CalendarContract.EventsColumns#GUESTS_CAN_MODIFY}</td>
+ <td>Whether guests can modify the event. </td>
+ </tr>
+ <tr>
+ <td>{@link android.provider.CalendarContract.EventsColumns#GUESTS_CAN_INVITE_OTHERS}</td>
+ <td>Whether guests can invite other guests. </td>
+ </tr>
+ <tr>
+ <td>{@link android.provider.CalendarContract.EventsColumns#GUESTS_CAN_SEE_GUESTS}</td>
+ <td>Whether guests can see the list of attendees.</td>
+ </tr>
+</table>
+
+<h3 id="add-event">Adding Events</h3>
+
+<p>When your application inserts a new event, we recommend that you use an
+{@link android.content.Intent#ACTION_INSERT INSERT} Intent, as described in <a
+href="#intent-insert">Using an intent to insert an event</a>. However, if you
+need to, you can insert events directly. This section describes how to do
+this.</p>
+
+
+<p>Here are the rules for inserting a new event: </p>
+<ul>
+
+ <li>You must include {@link
+android.provider.CalendarContract.EventsColumns#CALENDAR_ID} and {@link
+android.provider.CalendarContract.EventsColumns#DTSTART}.</li>
+
+<li>You must include an {@link
+android.provider.CalendarContract.EventsColumns#EVENT_TIMEZONE}. To get a list
+of the system's installed time zone IDs, use {@link
+java.util.TimeZone#getAvailableIDs()}. Note that this rule does not apply if
+you're inserting an event through the {@link
+android.content.Intent#ACTION_INSERT INSERT} Intent, described in <a
+href="#intent-insert">Using an intent to insert an event</a>—in that
+scenario, a default time zone is supplied.</li>
+
+ <li>For non-recurring events, you must include {@link
+android.provider.CalendarContract.EventsColumns#DTEND}. </li>
+
+
+ <li>For recurring events, you must include a {@link
+android.provider.CalendarContract.EventsColumns#DURATION} in addition to {@link
+android.provider.CalendarContract.EventsColumns#RRULE} or {@link
+android.provider.CalendarContract.EventsColumns#RDATE}. Note that this rule does not apply if
+you're inserting an event through the {@link
+android.content.Intent#ACTION_INSERT INSERT} Intent, described in <a
+href="#intent-insert">Using an intent to insert an event</a>—in that
+scenario, you can use an {@link
+android.provider.CalendarContract.EventsColumns#RRULE} in conjunction with {@link android.provider.CalendarContract.EventsColumns#DTSTART} and {@link android.provider.CalendarContract.EventsColumns#DTEND}, and the Calendar application
+converts it to a duration automatically.</li>
+
+</ul>
+
+<p>Here is an example of inserting an event. This is being performed in the UI
+thread for simplicity. In practice, inserts and updates should be done in an
+asynchronous thread to move the action into a background thread. For more
+information, see {@link android.content.AsyncQueryHandler}.</p>
+
+
+<pre>
+long calID = 3;
+long startMillis = 0;
+long endMillis = 0;
+Calendar beginTime = Calendar.getInstance();
+beginTime.set(2012, 9, 14, 7, 30);
+startMillis = beginTime.getTimeInMillis();
+Calendar endTime = Calendar.getInstance();
+endTime.set(2012, 9, 14, 8, 45);
+endMillis = endTime.getTimeInMillis();
+...
+
+ContentResolver cr = getContentResolver();
+ContentValues values = new ContentValues();
+values.put(Events.DTSTART, startMillis);
+values.put(Events.DTEND, endMillis);
+values.put(Events.TITLE, "Jazzercise");
+values.put(Events.DESCRIPTION, "Group workout");
+values.put(Events.CALENDAR_ID, calID);
+values.put(Events.EVENT_TIMEZONE, "America/Los_Angeles");
+Uri uri = cr.insert(Events.CONTENT_URI, values);
+
+// get the event ID that is the last element in the Uri
+long eventID = Long.parseLong(uri.getLastPathSegment());
+//
+// ... do something with event ID
+//
+//</pre>
+
+<p class="note"><strong>Note:</strong> See how this example captures the event
+ID after the event is created. This is the easiest way to get an event ID. You often
+need the event ID to perform other calendar operations—for example, to add
+attendees or reminders to an event.</p>
+
+
+<h3 id="update-event">Updating Events</h3>
+
+<p>When your application wants to allow the user to edit an event, we recommend
+that you use an {@link android.content.Intent#ACTION_EDIT EDIT} Intent, as
+described in <a href="#intent-edit">Using an intent to edit an event</a>.
+However, if you need to, you can edit events directly. To perform an update of
+an Event, you can provide the <code>_ID</code> of the
+event either as an appended ID to the Uri ({@link
+android.content.ContentUris#withAppendedId(android.net.Uri,long) withAppendedId()})
+or as the first selection item.
+The selection should start with <code>"_id=?"</code>, and the first
+<code>selectionArg</code> should be the <code>_ID</code> of the event. You can
+also do updates using a selection with no ID. Here is an example of updating an
+event. It changes the title of the event using the
+{@link android.content.ContentUris#withAppendedId(android.net.Uri,long) withAppendedId()}
+approach:</p>
+
+
+<pre>private static final String DEBUG_TAG = "MyActivity";
+...
+long eventID = 188;
+...
+ContentResolver cr = getContentResolver();
+ContentValues values = new ContentValues();
+Uri updateUri = null;
+// The new title for the event
+values.put(Events.TITLE, "Kickboxing");
+myUri = ContentUris.withAppendedId(Events.CONTENT_URI, eventID);
+int rows = getContentResolver().update(updateUri, values, null, null);
+Log.i(DEBUG_TAG, "Rows updated: " + rows); </pre>
+
+<h3 id="delete-event">Deleting Events</h3>
+
+<p>You can delete an event either by its {@link
+android.provider.BaseColumns#_ID} as an appended ID on the URI, or by using
+standard selection. If you use an appended ID, you can't also do a selection.
+There are two versions of delete: as an application and as a sync adapter. An
+application delete sets the <em>deleted</em> column to 1. This flag that tells
+the sync adapter that the row was deleted and that this deletion should be
+propagated to the server. A sync adapter delete removes the event from the
+database along with all its associated data. Here is an example of application
+deleting an event through its {@link android.provider.BaseColumns#_ID}:</p>
+
+
+<pre>private static final String DEBUG_TAG = "MyActivity";
+...
+long eventID = 201;
+...
+ContentResolver cr = getContentResolver();
+ContentValues values = new ContentValues();
+Uri deleteUri = null;
+deleteUri = ContentUris.withAppendedId(Events.CONTENT_URI, eventID);
+int rows = getContentResolver().delete(deleteUri, null, null);
+Log.i(DEBUG_TAG, "Rows deleted: " + rows);
+</pre>
+
+<h2 id="attendees">Attendees Table</h2>
+
+<p>Each row of the {@link android.provider.CalendarContract.Attendees} table
+represents a single attendee or guest of an event. Calling
+{@link android.provider.CalendarContract.Reminders#query(android.content.ContentResolver, long, java.lang.String[]) query()}
+returns a list of attendees for the
+event with the given {@link android.provider.CalendarContract.AttendeesColumns#EVENT_ID}.
+This {@link android.provider.CalendarContract.AttendeesColumns#EVENT_ID}
+must match the {@link
+android.provider.BaseColumns#_ID} of a particular event.</p>
+
+<p>The following table lists the
+writable fields. When inserting a new attendee, you must include all of them
+except <code>ATTENDEE_NAME</code>.
+</p>
+
+
+<table>
+ <tr>
+ <th>Constant</th>
+ <th>Description</th>
+ </tr>
+ <tr>
+ <td>{@link android.provider.CalendarContract.AttendeesColumns#EVENT_ID}</td>
+ <td>The ID of the event.</td>
+ </tr>
+ <tr>
+ <td>{@link android.provider.CalendarContract.AttendeesColumns#ATTENDEE_NAME}</td>
+ <td>The name of the attendee.</td>
+ </tr>
+ <tr>
+ <td>{@link android.provider.CalendarContract.AttendeesColumns#ATTENDEE_EMAIL}</td>
+ <td>The email address of the attendee.</td>
+ </tr>
+ <tr>
+ <td>{@link android.provider.CalendarContract.AttendeesColumns#ATTENDEE_RELATIONSHIP}</td>
+ <td><p>The relationship of the attendee to the event. One of:</p>
+ <ul>
+ <li>{@link android.provider.CalendarContract.AttendeesColumns#RELATIONSHIP_ATTENDEE}</li>
+ <li>{@link android.provider.CalendarContract.AttendeesColumns#RELATIONSHIP_NONE}</li>
+ <li>{@link android.provider.CalendarContract.AttendeesColumns#RELATIONSHIP_ORGANIZER}</li>
+ <li>{@link android.provider.CalendarContract.AttendeesColumns#RELATIONSHIP_PERFORMER}</li>
+ <li>{@link android.provider.CalendarContract.AttendeesColumns#RELATIONSHIP_SPEAKER}</li>
+ </ul>
+ </td>
+ </tr>
+ <tr>
+ <td>{@link android.provider.CalendarContract.AttendeesColumns#ATTENDEE_TYPE}</td>
+ <td><p>The type of attendee. One of: </p>
+ <ul>
+ <li>{@link android.provider.CalendarContract.AttendeesColumns#TYPE_REQUIRED}</li>
+ <li>{@link android.provider.CalendarContract.AttendeesColumns#TYPE_OPTIONAL}</li>
+ </ul></td>
+ </tr>
+ <tr>
+ <td>{@link android.provider.CalendarContract.AttendeesColumns#ATTENDEE_STATUS}</td>
+ <td><p>The attendance status of the attendee. One of:</p>
+ <ul>
+ <li>{@link android.provider.CalendarContract.AttendeesColumns#ATTENDEE_STATUS_ACCEPTED}</li>
+ <li>{@link android.provider.CalendarContract.AttendeesColumns#ATTENDEE_STATUS_DECLINED}</li>
+ <li>{@link android.provider.CalendarContract.AttendeesColumns#ATTENDEE_STATUS_INVITED}</li>
+ <li>{@link android.provider.CalendarContract.AttendeesColumns#ATTENDEE_STATUS_NONE}</li>
+ <li>{@link android.provider.CalendarContract.AttendeesColumns#ATTENDEE_STATUS_TENTATIVE}</li>
+ </ul></td>
+ </tr>
+</table>
+
+<h3 id="add-attendees">Adding Attendees</h3>
+
+<p>Here is an example that adds a single attendee to an event. Note that the
+{@link android.provider.CalendarContract.AttendeesColumns#EVENT_ID}
+is required:</p>
+
+<pre>
+long eventID = 202;
+...
+ContentResolver cr = getContentResolver();
+ContentValues values = new ContentValues();
+values.put(Attendees.ATTENDEE_NAME, "Trevor");
+values.put(Attendees.ATTENDEE_EMAIL, "trevor@example.com");
+values.put(Attendees.ATTENDEE_RELATIONSHIP, Attendees.RELATIONSHIP_ATTENDEE);
+values.put(Attendees.ATTENDEE_TYPE, Attendees.TYPE_OPTIONAL);
+values.put(Attendees.ATTENDEE_STATUS, Attendees.ATTENDEE_STATUS_INVITED);
+values.put(Attendees.EVENT_ID, eventID);
+Uri uri = cr.insert(Attendees.CONTENT_URI, values);
+</pre>
+
+<h2 id="reminders">Reminders Table</h2>
+
+<p>Each row of the {@link android.provider.CalendarContract.Reminders} table
+represents a single reminder for an event. Calling
+{@link android.provider.CalendarContract.Reminders#query(android.content.ContentResolver, long, java.lang.String[]) query()} returns a list of reminders for the
+event with the given
+{@link android.provider.CalendarContract.AttendeesColumns#EVENT_ID}.</p>
+
+
+<p>The following table lists the writable fields for reminders. All of them must
+be included when inserting a new reminder. Note that sync adapters specify the
+types of reminders they support in the {@link
+android.provider.CalendarContract.Calendars} table. See
+{@link android.provider.CalendarContract.CalendarColumns#ALLOWED_REMINDERS}
+for details.</p>
+
+
+<table>
+ <tr>
+ <th>Constant</th>
+ <th>Description</th>
+ </tr>
+ <tr>
+ <td>{@link android.provider.CalendarContract.RemindersColumns#EVENT_ID}</td>
+ <td>The ID of the event.</td>
+ </tr>
+ <tr>
+ <td>{@link android.provider.CalendarContract.RemindersColumns#MINUTES}</td>
+ <td>The minutes prior to the event that the reminder should fire.</td>
+ </tr>
+ <tr>
+ <td>{@link android.provider.CalendarContract.RemindersColumns#METHOD}</td>
+ <td><p>The alarm method, as set on the server. One of:</p>
+ <ul>
+ <li>{@link android.provider.CalendarContract.RemindersColumns#METHOD_ALERT}</li>
+ <li>{@link android.provider.CalendarContract.RemindersColumns#METHOD_DEFAULT}</li>
+ <li>{@link android.provider.CalendarContract.RemindersColumns#METHOD_EMAIL}</li>
+ <li>{@link android.provider.CalendarContract.RemindersColumns#METHOD_SMS}</li>
+ </ul></td>
+ </tr>
+</table>
+
+<h3 id="add-reminders">Adding Reminders</h3>
+
+<p>This example adds a reminder to an event. The reminder fires 15
+minutes before the event.</p>
+<pre>
+long eventID = 221;
+...
+ContentResolver cr = getContentResolver();
+ContentValues values = new ContentValues();
+values.put(Reminders.MINUTES, 15);
+values.put(Reminders.EVENT_ID, eventID);
+values.put(Reminders.METHOD, Reminders.METHOD_ALERT);
+Uri uri = cr.insert(Reminders.CONTENT_URI, values);</pre>
+
+<h2 id="instances">Instances Table</h2>
+
+<p>The
+{@link android.provider.CalendarContract.Instances} table holds the
+start and end time for occurrences of an event. Each row in this table
+represents a single event occurrence. The instances table is not writable and only
+provides a way to query event occurrences. </p>
+
+<p>The following table lists some of the fields you can query on for an instance. Note
+that time zone is defined by
+{@link android.provider.CalendarContract.CalendarCache#KEY_TIMEZONE_TYPE}
+and
+{@link android.provider.CalendarContract.CalendarCache#KEY_TIMEZONE_INSTANCES}.</p>
+
+
+<table>
+ <tr>
+ <th>Constant</th>
+ <th>Description</th>
+ </tr>
+ <tr>
+ <td>{@link android.provider.CalendarContract.Instances#BEGIN}</td>
+ <td>The beginning time of the instance, in UTC milliseconds.</td>
+ </tr>
+ <tr>
+ <td>{@link android.provider.CalendarContract.Instances#END}</td>
+ <td>The ending time of the instance, in UTC milliseconds.</td>
+ </tr>
+ <tr>
+ <td>{@link android.provider.CalendarContract.Instances#END_DAY}</td>
+
+ <td>The Julian end day of the instance, relative to the Calendar's time
+zone.
+
+</td>
+ </tr>
+ <tr>
+ <td>{@link android.provider.CalendarContract.Instances#END_MINUTE}</td>
+
+ <td>The end minute of the instance measured from midnight in the the
+Calendar's time zone.</td>
+
+ </tr>
+ <tr>
+ <td>{@link android.provider.CalendarContract.Instances#EVENT_ID}</td>
+ <td>The <code>_ID</code> of the event for this instance.</td>
+ </tr>
+ <tr>
+ <td>{@link android.provider.CalendarContract.Instances#START_DAY}</td>
+ <td>The Julian start day of the instance, relative to the Calendar's time zone.
+ </td>
+ </tr>
+ <tr>
+ <td>{@link android.provider.CalendarContract.Instances#START_MINUTE}</td>
+
+ <td>The start minute of the instance measured from midnight, relative to the
+Calendar's time zone.
+</td>
+
+ </tr>
+
+</table>
+
+<h3 id="query-instances">Querying the Instances table</h3>
+
+<p>To query the Instances table, you need to specify a range time for the query
+in the URI. In this example, {@link android.provider.CalendarContract.Instances}
+gets access to the {@link
+android.provider.CalendarContract.EventsColumns#TITLE} field through its
+implementation of the {@link android.provider.CalendarContract.EventsColumns} interface.
+In other words, {@link
+android.provider.CalendarContract.EventsColumns#TITLE} is returned through a
+database view, not through querying the raw {@link
+android.provider.CalendarContract.Instances} table.</p>
+
+<pre>
+private static final String DEBUG_TAG = "MyActivity";
+public static final String[] INSTANCE_PROJECTION = new String[] {
+ Instances.EVENT_ID, // 0
+ Instances.BEGIN, // 1
+ Instances.TITLE // 2
+ };
+
+// The indices for the projection array above.
+private static final int PROJECTION_ID_INDEX = 0;
+private static final int PROJECTION_BEGIN_INDEX = 1;
+private static final int PROJECTION_TITLE_INDEX = 2;
+...
+
+// Specify the date range you want to search for recurring
+// event instances
+Calendar beginTime = Calendar.getInstance();
+beginTime.set(2011, 9, 23, 8, 0);
+long startMillis = beginTime.getTimeInMillis();
+Calendar endTime = Calendar.getInstance();
+endTime.set(2011, 10, 24, 8, 0);
+long endMillis = endTime.getTimeInMillis();
+
+Cursor cur = null;
+ContentResolver cr = getContentResolver();
+
+// The ID of the recurring event whose instances you are searching
+// for in the Instances table
+String selection = Instances.EVENT_ID + " = ?";
+String[] selectionArgs = new String[] {"207"};
+
+// Construct the query with the desired date range.
+Uri.Builder builder = Instances.CONTENT_URI.buildUpon();
+ContentUris.appendId(builder, startMillis);
+ContentUris.appendId(builder, endMillis);
+
+// Submit the query
+cur = cr.query(builder.build(),
+ INSTANCE_PROJECTION,
+ selection,
+ selectionArgs,
+ null);
+
+while (cur.moveToNext()) {
+ String title = null;
+ long eventID = 0;
+ long beginVal = 0;
+
+ // Get the field values
+ eventID = cur.getLong(PROJECTION_ID_INDEX);
+ beginVal = cur.getLong(PROJECTION_BEGIN_INDEX);
+ title = cur.getString(PROJECTION_TITLE_INDEX);
+
+ // Do something with the values.
+ Log.i(DEBUG_TAG, "Event: " + title);
+ Calendar calendar = Calendar.getInstance();
+ calendar.setTimeInMillis(beginVal);
+ DateFormat formatter = new SimpleDateFormat("MM/dd/yyyy");
+ Log.i(DEBUG_TAG, "Date: " + formatter.format(calendar.getTime()));
+ }
+ }</pre>
+
+<h2 id="intents">Calendar Intents</h2>
+<p>Your application doesn't need <a href="#manifest">permissions</a> to read and write calendar data. It can instead use intents supported by Android's Calendar application to hand off read and write operations to that application. The following table lists the intents supported by the Calendar Provider:</p>
+<table>
+ <tr>
+ <th>Action</th>
+ <th>URI</th>
+
+ <th>Description</th>
+ <th>Extras</th>
+ </tr>
+ <tr>
+ <td><br>
+ {@link android.content.Intent#ACTION_VIEW VIEW} <br></td>
+ <td><p><code>content://com.android.calendar/time/<ms_since_epoch></code></p>
+ You can also refer to the URI with
+{@link android.provider.CalendarContract#CONTENT_URI CalendarContract.CONTENT_URI}.
+For an example of using this intent, see <a href="{@docRoot}guide/topics/providers/calendar-provider.html#intent-view">Using intents to view calendar data</a>.
+
+ </td>
+ <td>Open calendar to the time specified by <code><ms_since_epoch></code>.</td>
+ <td>None.</td>
+ </tr>
+ <tr>
+ <td><p>{@link android.content.Intent#ACTION_VIEW VIEW} </p>
+
+ </td>
+ <td><p><code>content://com.android.calendar/events/<event_id></code></p>
+
+ You can also refer to the URI with
+{@link android.provider.CalendarContract.Events#CONTENT_URI Events.CONTENT_URI}.
+For an example of using this intent, see <a href="{@docRoot}guide/topics/providers/calendar-provider.html#intent-view">Using intents to view calendar data</a>.
+
+ </td>
+ <td>View the event specified by <code><event_id></code>.</td>
+
+ <td>{@link android.provider.CalendarContract#EXTRA_EVENT_BEGIN_TIME CalendarContract.EXTRA_EVENT_BEGIN_TIME}<br>
+ <br>
+ <br>
+ {@link android.provider.CalendarContract#EXTRA_EVENT_END_TIME CalendarContract.EXTRA_EVENT_END_TIME}</td>
+ </tr>
+
+ <tr>
+ <td>{@link android.content.Intent#ACTION_EDIT EDIT} </td>
+ <td><p><code>content://com.android.calendar/events/<event_id></code></p>
+
+ You can also refer to the URI with
+{@link android.provider.CalendarContract.Events#CONTENT_URI Events.CONTENT_URI}.
+For an example of using this intent, see <a href="{@docRoot}guide/topics/providers/calendar-provider.html#intent-edit">Using an intent to edit an event</a>.
+
+
+ </td>
+ <td>Edit the event specified by <code><event_id></code>.</td>
+
+ <td>{@link android.provider.CalendarContract#EXTRA_EVENT_BEGIN_TIME CalendarContract.EXTRA_EVENT_BEGIN_TIME}<br>
+ <br>
+ <br>
+ {@link android.provider.CalendarContract#EXTRA_EVENT_END_TIME CalendarContract.EXTRA_EVENT_END_TIME}</td>
+ </tr>
+
+ <tr>
+ <td>{@link android.content.Intent#ACTION_EDIT EDIT} <br>
+ <br>
+ {@link android.content.Intent#ACTION_INSERT INSERT} </td>
+ <td><p><code>content://com.android.calendar/events</code></p>
+
+ You can also refer to the URI with
+{@link android.provider.CalendarContract.Events#CONTENT_URI Events.CONTENT_URI}.
+For an example of using this intent, see <a href="{@docRoot}guide/topics/providers/calendar-provider.html#intent-insert">Using an intent to insert an event</a>.
+
+ </td>
+
+ <td>Create an event.</td>
+ <td>Any of the extras listed in the table below.</td>
+ </tr>
+</table>
+
+<p>The following table lists the intent extras supported by the Calendar Provider:
+</p>
+<table>
+ <tr>
+ <th>Intent Extra</th>
+ <th>Description</th>
+ </tr>
+ <tr>
+ <td>{@link android.provider.CalendarContract.EventsColumns#TITLE Events.TITLE}</td>
+ <td>Name for the event.</td>
+ </tr>
+ <tr>
+
+ <td>{@link android.provider.CalendarContract#EXTRA_EVENT_BEGIN_TIME
+CalendarContract.EXTRA_EVENT_BEGIN_TIME}</td>
+ <td>Event begin time in milliseconds from the epoch.</td>
+ </tr>
+ <tr>
+ <td>{@link android.provider.CalendarContract#EXTRA_EVENT_END_TIME
+CalendarContract.EXTRA_EVENT_END_TIME}</td>
+
+ <td>Event end time in milliseconds from the epoch.</td>
+ </tr>
+ <tr>
+ <td>{@link android.provider.CalendarContract#EXTRA_EVENT_ALL_DAY
+CalendarContract.EXTRA_EVENT_ALL_DAY}</td>
+
+ <td>A boolean that indicates that an event is all day. Value can be
+<code>true</code> or <code>false</code>.</td> </tr>
+ <tr>
+ <td>{@link android.provider.CalendarContract.EventsColumns#EVENT_LOCATION
+Events.EVENT_LOCATION}</td>
+
+ <td>Location of the event.</td>
+ </tr>
+ <tr>
+ <td>{@link android.provider.CalendarContract.EventsColumns#DESCRIPTION
+Events.DESCRIPTION}</td>
+
+ <td>Event description.</td>
+ </tr>
+ <tr>
+ <td>
+ {@link android.content.Intent#EXTRA_EMAIL Intent.EXTRA_EMAIL}</td>
+ <td>Email addresses of those to invite as a comma-separated list.</td>
+ </tr>
+ <tr>
+ <td>
+ {@link android.provider.CalendarContract.EventsColumns#RRULE Events.RRULE}</td>
+ <td>The recurrence rule for the event.</td>
+ </tr>
+ <tr>
+ <td>
+ {@link android.provider.CalendarContract.EventsColumns#ACCESS_LEVEL
+Events.ACCESS_LEVEL}</td>
+
+ <td>Whether the event is private or public.</td>
+ </tr>
+ <tr>
+ <td>{@link android.provider.CalendarContract.EventsColumns#AVAILABILITY
+Events.AVAILABILITY}</td>
+
+ <td>If this event counts as busy time or is free time that can be scheduled over.</td>
+
+</table>
+<p>The following sections describe how to use these intents.</p>
+
+
+<h3 id="intent-insert">Using an intent to insert an event</h3>
+
+<p>Using the {@link android.content.Intent#ACTION_INSERT INSERT} Intent
+lets your application hand off the event insertion task to the Calendar itself.
+With this approach, your application doesn't even need to have the {@link
+android.Manifest.permission#WRITE_CALENDAR} permission included in its <a
+href="#manifest">manifest file</a>.</p>
+
+
+<p>When users run an application that uses this approach, the application sends
+them to the Calendar to finish adding the event. The {@link
+android.content.Intent#ACTION_INSERT INSERT} Intent uses extra fields to
+pre-populate a form with the details of the event in the Calendar. Users can
+then cancel the event, edit the form as needed, or save the event to their
+calendars.</p>
+
+
+
+<p>Here is a code snippet that schedules an event on January 19, 2012, that runs
+from 7:30 a.m. to 8:30 a.m. Note the following about this code snippet:</p>
+
+<ul>
+ <li>It specifies {@link android.provider.CalendarContract.Events#CONTENT_URI Events.CONTENT_URI}
+ as the Uri.</li>
+
+ <li>It uses the {@link
+android.provider.CalendarContract#EXTRA_EVENT_BEGIN_TIME
+CalendarContract.EXTRA_EVENT_BEGIN_TIME} and {@link
+android.provider.CalendarContract#EXTRA_EVENT_END_TIME
+CalendarContract.EXTRA_EVENT_END_TIME} extra fields to pre-populate the form
+with the time of the event. The values for these times must be in UTC milliseconds
+from the epoch.</li>
+
+ <li>It uses the {@link android.content.Intent#EXTRA_EMAIL Intent.EXTRA_EMAIL}
+extra field to provide a comma-separated list of invitees, specified by email address.</li>
+
+</ul>
+<pre>
+Calendar beginTime = Calendar.getInstance();
+beginTime.set(2012, 0, 19, 7, 30);
+Calendar endTime = Calendar.getInstance();
+endTime.set(2012, 0, 19, 8, 30);
+Intent intent = new Intent(Intent.ACTION_INSERT)
+ .setData(Events.CONTENT_URI)
+ .putExtra(CalendarContract.EXTRA_EVENT_BEGIN_TIME, beginTime.getTimeInMillis())
+ .putExtra(CalendarContract.EXTRA_EVENT_END_TIME, endTime.getTimeInMillis())
+ .putExtra(Events.TITLE, "Yoga")
+ .putExtra(Events.DESCRIPTION, "Group class")
+ .putExtra(Events.EVENT_LOCATION, "The gym")
+ .putExtra(Events.AVAILABILITY, Events.AVAILABILITY_BUSY)
+ .putExtra(Intent.EXTRA_EMAIL, "rowan@example.com,trevor@example.com");
+startActivity(intent);
+</pre>
+
+<h3 id="intent-edit">Using an intent to edit an event</h3>
+
+<p>You can update an event directly, as described in <a
+href="#update-event">Updating events</a>. But using the {@link
+android.content.Intent#ACTION_EDIT EDIT} Intent allows an application that
+doesn't have permission to hand off event editing to the Calendar application.
+When users finish editing their event in Calendar, they're returned to the
+original application.</p> <p>Here is an example of an intent that sets a new
+title for a specified event and lets users edit the event in the Calendar.</p>
+
+
+<pre>long eventID = 208;
+Uri uri = ContentUris.withAppendedId(Events.CONTENT_URI, eventID);
+Intent intent = new Intent(Intent.ACTION_EDIT)
+ .setData(uri)
+ .putExtra(Events.TITLE, "My New Title");
+startActivity(intent);</pre>
+
+<h3 id="intent-view">Using intents to view calendar data</h3>
+<p>Calender Provider offers two different ways to use the {@link android.content.Intent#ACTION_VIEW VIEW} Intent:</p>
+<ul>
+ <li>To open the Calendar to a particular date.</li>
+ <li>To view an event.</li>
+
+</ul>
+<p>Here is an example that shows how to open the Calendar to a particular date:</p>
+<pre>// A date-time specified in milliseconds since the epoch.
+long startMillis;
+...
+Uri.Builder builder = CalendarContract.CONTENT_URI.buildUpon();
+builder.appendPath("time");
+ContentUris.appendId(builder, startMillis);
+Intent intent = new Intent(Intent.ACTION_VIEW)
+ .setData(builder.build());
+startActivity(intent);</pre>
+
+<p>Here is an example that shows how to open an event for viewing:</p>
+<pre>long eventID = 208;
+...
+Uri uri = ContentUris.withAppendedId(Events.CONTENT_URI, eventID);
+Intent intent = new Intent(Intent.ACTION_VIEW)
+ .setData(uri);
+startActivity(intent);
+</pre>
+
+
+<h2 id="sync-adapter">Sync Adapters</h2>
+
+
+<p>There are only minor differences in how an application and a sync adapter
+access the Calendar Provider:</p>
+
+<ul>
+ <li>A sync adapter needs to specify that it's a sync adapter by setting {@link android.provider.CalendarContract#CALLER_IS_SYNCADAPTER} to <code>true</code>.</li>
+
+
+ <li>A sync adapter needs to provide an {@link
+android.provider.CalendarContract.SyncColumns#ACCOUNT_NAME} and an {@link
+android.provider.CalendarContract.SyncColumns#ACCOUNT_TYPE} as query parameters in the URI. </li>
+
+ <li>A sync adapter has write access to more columns than an application or widget.
+ For example, an application can only modify a few characteristics of a calendar,
+ such as its name, display name, visibility setting, and whether the calendar is
+ synced. By comparison, a sync adapter can access not only those columns, but many others,
+ such as calendar color, time zone, access level, location, and so on.
+However, a sync adapter is restricted to the <code>ACCOUNT_NAME</code> and
+<code>ACCOUNT_TYPE</code> it specified.</li> </ul>
+
+<p>Here is a helper method you can use to return a URI for use with a sync adapter:</p>
+<pre> static Uri asSyncAdapter(Uri uri, String account, String accountType) {
+ return uri.buildUpon()
+ .appendQueryParameter(android.provider.CalendarContract.CALLER_IS_SYNCADAPTER,"true")
+ .appendQueryParameter(Calendars.ACCOUNT_NAME, account)
+ .appendQueryParameter(Calendars.ACCOUNT_TYPE, accountType).build();
+ }
+</pre>
+<p>For a sample implementation of a sync adapter (not specifically related to Calendar), see
+<a href="{@docRoot}resources/samples/SampleSyncAdapter/index.html">SampleSyncAdapter</a>.
+</body>
+</html>
diff --git a/docs/html/guide/topics/providers/content-providers.jd b/docs/html/guide/topics/providers/content-providers.jd
index 513886a..95331ce 100644
--- a/docs/html/guide/topics/providers/content-providers.jd
+++ b/docs/html/guide/topics/providers/content-providers.jd
@@ -19,6 +19,11 @@
<li>{@link android.content.ContentResolver}</li>
<li>{@link android.database.Cursor}</li>
</ol>
+
+<h2>See also</h2>
+<ol>
+ <li><a href="{@docRoot}guide/topics/providers/calendar-provider.html">Calendar Provider</a></li>
+</ol>
</div>
</div>
@@ -36,6 +41,10 @@
for some, you must acquire the proper permission to read the data).
</p>
+<p class="note"><strong>Note:</strong> Android 4.0 introduces the Calendar
+Provider. For more information, see <a
+href="{@docRoot}guide/topics/providers/calendar-provider.html">Calendar
+Provider</a>.</p>
<p>
If you want to make your own data public, you have two options: You can
create your own content provider (a {@link android.content.ContentProvider}
diff --git a/docs/html/guide/topics/resources/drawable-resource.jd b/docs/html/guide/topics/resources/drawable-resource.jd
index fdf6c5a..80de9f9 100644
--- a/docs/html/guide/topics/resources/drawable-resource.jd
+++ b/docs/html/guide/topics/resources/drawable-resource.jd
@@ -646,6 +646,7 @@
android:state_checkable=["true" | "false"]
android:state_checked=["true" | "false"]
android:state_enabled=["true" | "false"]
+ android:state_activated=["true" | "false"]
android:state_window_focused=["true" | "false"] />
</selector>
</pre>
@@ -690,8 +691,8 @@
<dd><em>Boolean</em>. "true" if this item should be used when the object is pressed (such as when a button
is touched/clicked); "false" if this item should be used in the default, non-pressed state.</dd>
<dt><code>android:state_focused</code></dt>
- <dd><em>Boolean</em>. "true" if this item should be used when the object is focused (such as when a button
-is highlighted using the trackball/d-pad); "false" if this item should be used in the default,
+ <dd><em>Boolean</em>. "true" if this item should be used when the object has input focus
+(such as when the user selects a text input); "false" if this item should be used in the default,
non-focused state.</dd>
<dt><code>android:state_hovered</code></dt>
<dd><em>Boolean</em>. "true" if this item should be used when the object is being hovered
@@ -699,8 +700,11 @@
drawable may be the same drawable used for the "focused" state.
<p>Introduced in API level 14.</p></dd>
<dt><code>android:state_selected</code></dt>
- <dd><em>Boolean</em>. "true" if this item should be used when the object is selected (such as when a
-tab is opened); "false" if this item should be used when the object is not selected.</dd>
+ <dd><em>Boolean</em>. "true" if this item should be used when the object is the current
+user selection when navigating with a directional control (such as when navigating through a list
+with a d-pad); "false" if this item should be used when the object is not selected.
+<p>The selected state is used when focus (<code>android:state_focused</code>) is not sufficient
+(such as when list view has focus and an item within it is selected with a d-pad).</p></dd>
<dt><code>android:state_checkable</code></dt>
<dd><em>Boolean</em>. "true" if this item should be used when the object is checkable; "false" if this
item should be used when the object is not checkable. (Only useful if the object can
@@ -709,8 +713,14 @@
<dd><em>Boolean</em>. "true" if this item should be used when the object is checked; "false" if it
should be used when the object is un-checked.</dd>
<dt><code>android:state_enabled</code></dt>
- <dd><em>Boolean</em>. "true" if this item should be used when the object is enabled (capable of
-receiving touch/click events); "false" if it should be used when the object is disabled.</dd>
+ <dd><em>Boolean</em>. "true" if this item should be used when the object is enabled
+(capable of receiving touch/click events); "false" if it should be used when the object is
+disabled.</dd>
+ <dt><code>android:state_activated</code></dt>
+ <dd><em>Boolean</em>. "true" if this item should be used when the object is activated as
+the persistent selection (such as to "highlight" the previously selected list item in a persistent
+navigation view); "false" if it should be used when the object is not activated.
+<p>Introduced in API level 11.</p></dd>
<dt><code>android:state_window_focused</code></dt>
<dd><em>Boolean</em>. "true" if this item should be used when the application window has focus (the
application is in the foreground), "false" if this item should be used when the application
diff --git a/docs/html/images/providers/datamodel.graffle b/docs/html/images/providers/datamodel.graffle
new file mode 100644
index 0000000..f8d730f
--- /dev/null
+++ b/docs/html/images/providers/datamodel.graffle
@@ -0,0 +1,2029 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>ActiveLayerIndex</key>
+ <integer>0</integer>
+ <key>ApplicationVersion</key>
+ <array>
+ <string>com.omnigroup.OmniGrafflePro</string>
+ <string>138.9.0.117994</string>
+ </array>
+ <key>AutoAdjust</key>
+ <true/>
+ <key>BackgroundGraphic</key>
+ <dict>
+ <key>Bounds</key>
+ <string>{{0, 0}, {576, 733}}</string>
+ <key>Class</key>
+ <string>SolidGraphic</string>
+ <key>ID</key>
+ <integer>2</integer>
+ <key>Style</key>
+ <dict>
+ <key>shadow</key>
+ <dict>
+ <key>Draws</key>
+ <string>NO</string>
+ </dict>
+ <key>stroke</key>
+ <dict>
+ <key>Draws</key>
+ <string>NO</string>
+ </dict>
+ </dict>
+ </dict>
+ <key>CanvasOrigin</key>
+ <string>{0, 0}</string>
+ <key>ColumnAlign</key>
+ <integer>1</integer>
+ <key>ColumnSpacing</key>
+ <real>36</real>
+ <key>CreationDate</key>
+ <string>2011-10-12 11:34:15 -0700</string>
+ <key>Creator</key>
+ <string>Katie McCormick</string>
+ <key>DisplayScale</key>
+ <string>1 0/72 in = 1.0000 in</string>
+ <key>GraphDocumentVersion</key>
+ <integer>6</integer>
+ <key>GraphicsList</key>
+ <array>
+ <dict>
+ <key>Bounds</key>
+ <string>{{249.63, 336.648}, {140.426, 27.9745}}</string>
+ <key>Class</key>
+ <string>ShapedGraphic</string>
+ <key>ID</key>
+ <integer>29</integer>
+ <key>Line</key>
+ <dict>
+ <key>ID</key>
+ <integer>169</integer>
+ <key>Position</key>
+ <real>0.33598536252975464</real>
+ <key>RotationType</key>
+ <integer>0</integer>
+ </dict>
+ <key>Shape</key>
+ <string>Rectangle</string>
+ <key>Style</key>
+ <dict>
+ <key>shadow</key>
+ <dict>
+ <key>Draws</key>
+ <string>NO</string>
+ </dict>
+ <key>stroke</key>
+ <dict>
+ <key>Draws</key>
+ <string>NO</string>
+ <key>Width</key>
+ <real>0.0</real>
+ </dict>
+ </dict>
+ <key>Text</key>
+ <dict>
+ <key>Text</key>
+ <string>{\rtf1\ansi\ansicpg1252\cocoartf1038\cocoasubrtf360
+{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc\pardirnatural
+
+\f0\fs24 \cf0 \
+Reminders.EVENT_ID\
+}</string>
+ </dict>
+ </dict>
+ <dict>
+ <key>Bounds</key>
+ <string>{{248.834, 121}, {145.338, 27.9745}}</string>
+ <key>Class</key>
+ <string>ShapedGraphic</string>
+ <key>ID</key>
+ <integer>28</integer>
+ <key>Line</key>
+ <dict>
+ <key>ID</key>
+ <integer>15</integer>
+ <key>Position</key>
+ <real>0.49666976928710938</real>
+ <key>RotationType</key>
+ <integer>0</integer>
+ </dict>
+ <key>Shape</key>
+ <string>Rectangle</string>
+ <key>Style</key>
+ <dict>
+ <key>shadow</key>
+ <dict>
+ <key>Draws</key>
+ <string>NO</string>
+ </dict>
+ <key>stroke</key>
+ <dict>
+ <key>Draws</key>
+ <string>NO</string>
+ <key>Width</key>
+ <real>0.0</real>
+ </dict>
+ </dict>
+ <key>Text</key>
+ <dict>
+ <key>Text</key>
+ <string>{\rtf1\ansi\ansicpg1252\cocoartf1038\cocoasubrtf360
+{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc\pardirnatural
+
+\f0\fs24 \cf0 \
+Events.CALENDAR_ID\
+}</string>
+ </dict>
+ </dict>
+ <dict>
+ <key>Class</key>
+ <string>LineGraphic</string>
+ <key>Head</key>
+ <dict>
+ <key>ID</key>
+ <integer>157</integer>
+ <key>Info</key>
+ <integer>5</integer>
+ </dict>
+ <key>ID</key>
+ <integer>170</integer>
+ <key>Points</key>
+ <array>
+ <string>{188.253, 404}</string>
+ <string>{321.503, 245.17}</string>
+ </array>
+ <key>Style</key>
+ <dict>
+ <key>stroke</key>
+ <dict>
+ <key>Cap</key>
+ <integer>0</integer>
+ <key>HeadArrow</key>
+ <string>0</string>
+ <key>Join</key>
+ <integer>0</integer>
+ <key>TailArrow</key>
+ <string>CrowBall</string>
+ </dict>
+ </dict>
+ <key>Tail</key>
+ <dict>
+ <key>ID</key>
+ <integer>165</integer>
+ </dict>
+ </dict>
+ <dict>
+ <key>Class</key>
+ <string>LineGraphic</string>
+ <key>Head</key>
+ <dict>
+ <key>ID</key>
+ <integer>157</integer>
+ </dict>
+ <key>ID</key>
+ <integer>169</integer>
+ <key>Points</key>
+ <array>
+ <string>{319.003, 404}</string>
+ <string>{321.503, 245.17}</string>
+ </array>
+ <key>Style</key>
+ <dict>
+ <key>stroke</key>
+ <dict>
+ <key>Cap</key>
+ <integer>0</integer>
+ <key>HeadArrow</key>
+ <string>0</string>
+ <key>Join</key>
+ <integer>0</integer>
+ <key>TailArrow</key>
+ <string>CrowBall</string>
+ </dict>
+ </dict>
+ <key>Tail</key>
+ <dict>
+ <key>ID</key>
+ <integer>166</integer>
+ </dict>
+ </dict>
+ <dict>
+ <key>Class</key>
+ <string>LineGraphic</string>
+ <key>Head</key>
+ <dict>
+ <key>ID</key>
+ <integer>157</integer>
+ <key>Info</key>
+ <integer>5</integer>
+ </dict>
+ <key>ID</key>
+ <integer>168</integer>
+ <key>Points</key>
+ <array>
+ <string>{450.042, 404}</string>
+ <string>{321.503, 245.17}</string>
+ </array>
+ <key>Style</key>
+ <dict>
+ <key>stroke</key>
+ <dict>
+ <key>Cap</key>
+ <integer>0</integer>
+ <key>HeadArrow</key>
+ <string>0</string>
+ <key>Join</key>
+ <integer>0</integer>
+ <key>TailArrow</key>
+ <string>CrowBall</string>
+ </dict>
+ </dict>
+ <key>Tail</key>
+ <dict>
+ <key>ID</key>
+ <integer>167</integer>
+ </dict>
+ </dict>
+ <dict>
+ <key>Class</key>
+ <string>LineGraphic</string>
+ <key>Head</key>
+ <dict>
+ <key>ID</key>
+ <integer>155</integer>
+ </dict>
+ <key>ID</key>
+ <integer>15</integer>
+ <key>Points</key>
+ <array>
+ <string>{321.503, 195}</string>
+ <string>{321.503, 74.1697}</string>
+ </array>
+ <key>Style</key>
+ <dict>
+ <key>stroke</key>
+ <dict>
+ <key>Cap</key>
+ <integer>0</integer>
+ <key>HeadArrow</key>
+ <string>0</string>
+ <key>Join</key>
+ <integer>0</integer>
+ <key>TailArrow</key>
+ <string>CrowBall</string>
+ </dict>
+ </dict>
+ <key>Tail</key>
+ <dict>
+ <key>ID</key>
+ <integer>157</integer>
+ <key>Info</key>
+ <integer>6</integer>
+ </dict>
+ </dict>
+ <dict>
+ <key>Bounds</key>
+ <string>{{281.41, 24}, {80.1852, 50.1697}}</string>
+ <key>Class</key>
+ <string>ShapedGraphic</string>
+ <key>FontInfo</key>
+ <dict>
+ <key>Color</key>
+ <dict>
+ <key>b</key>
+ <string>0</string>
+ <key>g</key>
+ <string>0</string>
+ <key>r</key>
+ <string>0</string>
+ </dict>
+ <key>Font</key>
+ <string>Helvetica-Bold</string>
+ <key>Size</key>
+ <real>10</real>
+ </dict>
+ <key>ID</key>
+ <integer>155</integer>
+ <key>Magnets</key>
+ <array>
+ <string>{1, 1}</string>
+ <string>{1, -1}</string>
+ <string>{-1, -1}</string>
+ <string>{-1, 1}</string>
+ <string>{0, 1}</string>
+ <string>{0, -1}</string>
+ <string>{1, 0}</string>
+ <string>{-1, 0}</string>
+ <string>{-0.5, -0.233518}</string>
+ <string>{-0.491442, 0.260063}</string>
+ <string>{0.507118, -0.224086}</string>
+ <string>{0.507118, 0.267179}</string>
+ <string>{-0.27431, -0.474028}</string>
+ <string>{0.27978, -0.478478}</string>
+ <string>{0.293938, 0.543044}</string>
+ <string>{-0.286232, 0.553804}</string>
+ </array>
+ <key>Shape</key>
+ <string>Rectangle</string>
+ <key>Style</key>
+ <dict>
+ <key>fill</key>
+ <dict>
+ <key>Color</key>
+ <dict>
+ <key>b</key>
+ <string>0.938075</string>
+ <key>g</key>
+ <string>0.938269</string>
+ <key>r</key>
+ <string>0.938154</string>
+ </dict>
+ <key>FillType</key>
+ <integer>2</integer>
+ <key>GradientAngle</key>
+ <real>90</real>
+ <key>GradientColor</key>
+ <dict>
+ <key>b</key>
+ <string>0.727869</string>
+ <key>g</key>
+ <string>0.728019</string>
+ <key>r</key>
+ <string>0.72793</string>
+ </dict>
+ </dict>
+ <key>shadow</key>
+ <dict>
+ <key>Color</key>
+ <dict>
+ <key>a</key>
+ <string>0.35</string>
+ <key>b</key>
+ <string>0</string>
+ <key>g</key>
+ <string>0</string>
+ <key>r</key>
+ <string>0</string>
+ </dict>
+ <key>Fuzziness</key>
+ <real>2.3972222805023193</real>
+ <key>ShadowVector</key>
+ <string>{0, 1}</string>
+ </dict>
+ <key>stroke</key>
+ <dict>
+ <key>Color</key>
+ <dict>
+ <key>b</key>
+ <string>0.472997</string>
+ <key>g</key>
+ <string>0.473094</string>
+ <key>r</key>
+ <string>0.473036</string>
+ </dict>
+ <key>CornerRadius</key>
+ <real>3</real>
+ </dict>
+ </dict>
+ <key>Text</key>
+ <dict>
+ <key>Text</key>
+ <string>{\rtf1\ansi\ansicpg1252\cocoartf1038\cocoasubrtf360
+{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\b\fs24 \cf0 Calendars}</string>
+ <key>VerticalPad</key>
+ <integer>0</integer>
+ </dict>
+ </dict>
+ <dict>
+ <key>Bounds</key>
+ <string>{{433, 404}, {80.1852, 50.1697}}</string>
+ <key>Class</key>
+ <string>ShapedGraphic</string>
+ <key>FontInfo</key>
+ <dict>
+ <key>Color</key>
+ <dict>
+ <key>b</key>
+ <string>1</string>
+ <key>g</key>
+ <string>1</string>
+ <key>r</key>
+ <string>1</string>
+ </dict>
+ <key>Font</key>
+ <string>DroidSans-Bold</string>
+ <key>Size</key>
+ <real>10</real>
+ </dict>
+ <key>ID</key>
+ <integer>167</integer>
+ <key>Magnets</key>
+ <array>
+ <string>{1, 1}</string>
+ <string>{1, -1}</string>
+ <string>{-1, -1}</string>
+ <string>{-1, 1}</string>
+ <string>{0, 1}</string>
+ <string>{0, -1}</string>
+ <string>{1, 0}</string>
+ <string>{-1, 0}</string>
+ <string>{-0.5, -0.233518}</string>
+ <string>{-0.491442, 0.260063}</string>
+ <string>{0.507118, -0.224086}</string>
+ <string>{0.507118, 0.267179}</string>
+ <string>{-0.27431, -0.474028}</string>
+ <string>{0.27978, -0.478478}</string>
+ <string>{0.293938, 0.543044}</string>
+ <string>{-0.286232, 0.553804}</string>
+ </array>
+ <key>Shape</key>
+ <string>Rectangle</string>
+ <key>Style</key>
+ <dict>
+ <key>fill</key>
+ <dict>
+ <key>Color</key>
+ <dict>
+ <key>b</key>
+ <string>0.937525</string>
+ <key>g</key>
+ <string>0.489708</string>
+ <key>r</key>
+ <string>0.223421</string>
+ </dict>
+ <key>FillType</key>
+ <integer>2</integer>
+ <key>GradientAngle</key>
+ <real>90</real>
+ <key>GradientColor</key>
+ <dict>
+ <key>b</key>
+ <string>0.905866</string>
+ <key>g</key>
+ <string>0.149816</string>
+ <key>r</key>
+ <string>0.119797</string>
+ </dict>
+ </dict>
+ <key>shadow</key>
+ <dict>
+ <key>Color</key>
+ <dict>
+ <key>a</key>
+ <string>0.35</string>
+ <key>b</key>
+ <string>0</string>
+ <key>g</key>
+ <string>0</string>
+ <key>r</key>
+ <string>0</string>
+ </dict>
+ <key>Fuzziness</key>
+ <real>2.3972222805023193</real>
+ <key>ShadowVector</key>
+ <string>{1, 2}</string>
+ </dict>
+ <key>stroke</key>
+ <dict>
+ <key>Color</key>
+ <dict>
+ <key>b</key>
+ <string>0.461178</string>
+ <key>g</key>
+ <string>0.0874307</string>
+ <key>r</key>
+ <string>0</string>
+ </dict>
+ <key>CornerRadius</key>
+ <real>3</real>
+ <key>Draws</key>
+ <string>NO</string>
+ <key>Width</key>
+ <real>2</real>
+ </dict>
+ </dict>
+ <key>Text</key>
+ <dict>
+ <key>Text</key>
+ <string>{\rtf1\ansi\ansicpg1252\cocoartf1038\cocoasubrtf360
+{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\b\fs24 \cf1 Instances}</string>
+ <key>VerticalPad</key>
+ <integer>0</integer>
+ </dict>
+ </dict>
+ <dict>
+ <key>Bounds</key>
+ <string>{{278.91, 404}, {80.1852, 50.1697}}</string>
+ <key>Class</key>
+ <string>ShapedGraphic</string>
+ <key>FontInfo</key>
+ <dict>
+ <key>Color</key>
+ <dict>
+ <key>b</key>
+ <string>1</string>
+ <key>g</key>
+ <string>1</string>
+ <key>r</key>
+ <string>1</string>
+ </dict>
+ <key>Font</key>
+ <string>DroidSans-Bold</string>
+ <key>Size</key>
+ <real>10</real>
+ </dict>
+ <key>ID</key>
+ <integer>166</integer>
+ <key>Magnets</key>
+ <array>
+ <string>{1, 1}</string>
+ <string>{1, -1}</string>
+ <string>{-1, -1}</string>
+ <string>{-1, 1}</string>
+ <string>{0, 1}</string>
+ <string>{0, -1}</string>
+ <string>{1, 0}</string>
+ <string>{-1, 0}</string>
+ <string>{-0.5, -0.233518}</string>
+ <string>{-0.491442, 0.260063}</string>
+ <string>{0.507118, -0.224086}</string>
+ <string>{0.507118, 0.267179}</string>
+ <string>{-0.27431, -0.474028}</string>
+ <string>{0.27978, -0.478478}</string>
+ <string>{0.293938, 0.543044}</string>
+ <string>{-0.286232, 0.553804}</string>
+ </array>
+ <key>Shape</key>
+ <string>Rectangle</string>
+ <key>Style</key>
+ <dict>
+ <key>fill</key>
+ <dict>
+ <key>Color</key>
+ <dict>
+ <key>b</key>
+ <string>0.937525</string>
+ <key>g</key>
+ <string>0.489708</string>
+ <key>r</key>
+ <string>0.223421</string>
+ </dict>
+ <key>FillType</key>
+ <integer>2</integer>
+ <key>GradientAngle</key>
+ <real>90</real>
+ <key>GradientColor</key>
+ <dict>
+ <key>b</key>
+ <string>0.905866</string>
+ <key>g</key>
+ <string>0.149816</string>
+ <key>r</key>
+ <string>0.119797</string>
+ </dict>
+ </dict>
+ <key>shadow</key>
+ <dict>
+ <key>Color</key>
+ <dict>
+ <key>a</key>
+ <string>0.35</string>
+ <key>b</key>
+ <string>0</string>
+ <key>g</key>
+ <string>0</string>
+ <key>r</key>
+ <string>0</string>
+ </dict>
+ <key>Fuzziness</key>
+ <real>2.3972222805023193</real>
+ <key>ShadowVector</key>
+ <string>{1, 2}</string>
+ </dict>
+ <key>stroke</key>
+ <dict>
+ <key>Color</key>
+ <dict>
+ <key>b</key>
+ <string>0.461178</string>
+ <key>g</key>
+ <string>0.0874307</string>
+ <key>r</key>
+ <string>0</string>
+ </dict>
+ <key>CornerRadius</key>
+ <real>3</real>
+ <key>Draws</key>
+ <string>NO</string>
+ <key>Width</key>
+ <real>2</real>
+ </dict>
+ </dict>
+ <key>Text</key>
+ <dict>
+ <key>Text</key>
+ <string>{\rtf1\ansi\ansicpg1252\cocoartf1038\cocoasubrtf360
+{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\b\fs24 \cf1 Reminders}</string>
+ <key>VerticalPad</key>
+ <integer>0</integer>
+ </dict>
+ </dict>
+ <dict>
+ <key>Bounds</key>
+ <string>{{281.41, 195}, {80.1852, 50.1697}}</string>
+ <key>Class</key>
+ <string>ShapedGraphic</string>
+ <key>FontInfo</key>
+ <dict>
+ <key>Color</key>
+ <dict>
+ <key>b</key>
+ <string>0</string>
+ <key>g</key>
+ <string>0</string>
+ <key>r</key>
+ <string>0</string>
+ </dict>
+ <key>Font</key>
+ <string>DroidSans-Bold</string>
+ <key>Size</key>
+ <real>10</real>
+ </dict>
+ <key>ID</key>
+ <integer>157</integer>
+ <key>Magnets</key>
+ <array>
+ <string>{1, 1}</string>
+ <string>{1, -1}</string>
+ <string>{-1, -1}</string>
+ <string>{-1, 1}</string>
+ <string>{0, 1}</string>
+ <string>{0, -1}</string>
+ <string>{1, 0}</string>
+ <string>{-1, 0}</string>
+ <string>{-0.5, -0.233518}</string>
+ <string>{-0.491442, 0.260063}</string>
+ <string>{0.507118, -0.224086}</string>
+ <string>{0.507118, 0.267179}</string>
+ <string>{-0.27431, -0.474028}</string>
+ <string>{0.27978, -0.478478}</string>
+ <string>{0.293938, 0.543044}</string>
+ <string>{-0.286232, 0.553804}</string>
+ </array>
+ <key>Shape</key>
+ <string>Rectangle</string>
+ <key>Style</key>
+ <dict>
+ <key>fill</key>
+ <dict>
+ <key>Color</key>
+ <dict>
+ <key>b</key>
+ <string>1</string>
+ <key>g</key>
+ <string>0.874135</string>
+ <key>r</key>
+ <string>0.71718</string>
+ </dict>
+ <key>FillType</key>
+ <integer>2</integer>
+ <key>GradientAngle</key>
+ <real>90</real>
+ <key>GradientColor</key>
+ <dict>
+ <key>b</key>
+ <string>1</string>
+ <key>g</key>
+ <string>0.662438</string>
+ <key>r</key>
+ <string>0.464468</string>
+ </dict>
+ </dict>
+ <key>shadow</key>
+ <dict>
+ <key>Color</key>
+ <dict>
+ <key>a</key>
+ <string>0.35</string>
+ <key>b</key>
+ <string>0</string>
+ <key>g</key>
+ <string>0</string>
+ <key>r</key>
+ <string>0</string>
+ </dict>
+ <key>Fuzziness</key>
+ <real>2.3972222805023193</real>
+ <key>ShadowVector</key>
+ <string>{0, 1}</string>
+ </dict>
+ <key>stroke</key>
+ <dict>
+ <key>Color</key>
+ <dict>
+ <key>b</key>
+ <string>0.93512</string>
+ <key>g</key>
+ <string>0.472602</string>
+ <key>r</key>
+ <string>0.333854</string>
+ </dict>
+ <key>CornerRadius</key>
+ <real>3</real>
+ </dict>
+ </dict>
+ <key>Text</key>
+ <dict>
+ <key>Text</key>
+ <string>{\rtf1\ansi\ansicpg1252\cocoartf1038\cocoasubrtf360
+{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\b\fs24 \cf0 Events}</string>
+ <key>VerticalPad</key>
+ <integer>0</integer>
+ </dict>
+ </dict>
+ <dict>
+ <key>Bounds</key>
+ <string>{{124.821, 404}, {80.1852, 50.1697}}</string>
+ <key>Class</key>
+ <string>ShapedGraphic</string>
+ <key>FontInfo</key>
+ <dict>
+ <key>Color</key>
+ <dict>
+ <key>b</key>
+ <string>1</string>
+ <key>g</key>
+ <string>1</string>
+ <key>r</key>
+ <string>1</string>
+ </dict>
+ <key>Font</key>
+ <string>DroidSans-Bold</string>
+ <key>Size</key>
+ <real>10</real>
+ </dict>
+ <key>ID</key>
+ <integer>165</integer>
+ <key>Magnets</key>
+ <array>
+ <string>{1, 1}</string>
+ <string>{1, -1}</string>
+ <string>{-1, -1}</string>
+ <string>{-1, 1}</string>
+ <string>{0, 1}</string>
+ <string>{0, -1}</string>
+ <string>{1, 0}</string>
+ <string>{-1, 0}</string>
+ <string>{-0.5, -0.233518}</string>
+ <string>{-0.491442, 0.260063}</string>
+ <string>{0.507118, -0.224086}</string>
+ <string>{0.507118, 0.267179}</string>
+ <string>{-0.27431, -0.474028}</string>
+ <string>{0.27978, -0.478478}</string>
+ <string>{0.293938, 0.543044}</string>
+ <string>{-0.286232, 0.553804}</string>
+ </array>
+ <key>Shape</key>
+ <string>Rectangle</string>
+ <key>Style</key>
+ <dict>
+ <key>fill</key>
+ <dict>
+ <key>Color</key>
+ <dict>
+ <key>b</key>
+ <string>0.937525</string>
+ <key>g</key>
+ <string>0.489708</string>
+ <key>r</key>
+ <string>0.223421</string>
+ </dict>
+ <key>FillType</key>
+ <integer>2</integer>
+ <key>GradientAngle</key>
+ <real>90</real>
+ <key>GradientColor</key>
+ <dict>
+ <key>b</key>
+ <string>0.905866</string>
+ <key>g</key>
+ <string>0.149816</string>
+ <key>r</key>
+ <string>0.119797</string>
+ </dict>
+ </dict>
+ <key>shadow</key>
+ <dict>
+ <key>Color</key>
+ <dict>
+ <key>a</key>
+ <string>0.35</string>
+ <key>b</key>
+ <string>0</string>
+ <key>g</key>
+ <string>0</string>
+ <key>r</key>
+ <string>0</string>
+ </dict>
+ <key>Fuzziness</key>
+ <real>2.3972222805023193</real>
+ <key>ShadowVector</key>
+ <string>{1, 2}</string>
+ </dict>
+ <key>stroke</key>
+ <dict>
+ <key>Color</key>
+ <dict>
+ <key>b</key>
+ <string>0.461178</string>
+ <key>g</key>
+ <string>0.0874307</string>
+ <key>r</key>
+ <string>0</string>
+ </dict>
+ <key>CornerRadius</key>
+ <real>3</real>
+ <key>Draws</key>
+ <string>NO</string>
+ <key>Width</key>
+ <real>2</real>
+ </dict>
+ </dict>
+ <key>Text</key>
+ <dict>
+ <key>Text</key>
+ <string>{\rtf1\ansi\ansicpg1252\cocoartf1038\cocoasubrtf360
+{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc
+
+\f0\b\fs24 \cf1 Attendees}</string>
+ <key>VerticalPad</key>
+ <integer>0</integer>
+ </dict>
+ </dict>
+ <dict>
+ <key>Bounds</key>
+ <string>{{383, 317.03}, {150.288, 18.4565}}</string>
+ <key>Class</key>
+ <string>ShapedGraphic</string>
+ <key>ID</key>
+ <integer>22</integer>
+ <key>Shape</key>
+ <string>Rectangle</string>
+ <key>Style</key>
+ <dict>
+ <key>fill</key>
+ <dict>
+ <key>Draws</key>
+ <string>NO</string>
+ </dict>
+ <key>shadow</key>
+ <dict>
+ <key>Draws</key>
+ <string>NO</string>
+ </dict>
+ <key>stroke</key>
+ <dict>
+ <key>Draws</key>
+ <string>NO</string>
+ </dict>
+ </dict>
+ <key>Text</key>
+ <dict>
+ <key>Pad</key>
+ <integer>0</integer>
+ <key>Text</key>
+ <string>{\rtf1\ansi\ansicpg1252\cocoartf1038\cocoasubrtf360
+{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc\pardirnatural
+
+\f0\fs24 \cf0 Instances.EVENT_ID}</string>
+ <key>VerticalPad</key>
+ <integer>0</integer>
+ </dict>
+ <key>Wrap</key>
+ <string>NO</string>
+ </dict>
+ <dict>
+ <key>Bounds</key>
+ <string>{{107, 317.03}, {154.243, 18.4565}}</string>
+ <key>Class</key>
+ <string>ShapedGraphic</string>
+ <key>ID</key>
+ <integer>20</integer>
+ <key>Shape</key>
+ <string>Rectangle</string>
+ <key>Style</key>
+ <dict>
+ <key>fill</key>
+ <dict>
+ <key>Draws</key>
+ <string>NO</string>
+ </dict>
+ <key>shadow</key>
+ <dict>
+ <key>Draws</key>
+ <string>NO</string>
+ </dict>
+ <key>stroke</key>
+ <dict>
+ <key>Draws</key>
+ <string>NO</string>
+ </dict>
+ </dict>
+ <key>Text</key>
+ <dict>
+ <key>Pad</key>
+ <integer>0</integer>
+ <key>Text</key>
+ <string>{\rtf1\ansi\ansicpg1252\cocoartf1038\cocoasubrtf360
+{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc\pardirnatural
+
+\f0\fs24 \cf0 Attendees.EVENT_ID}</string>
+ <key>VerticalPad</key>
+ <integer>0</integer>
+ </dict>
+ <key>Wrap</key>
+ <string>NO</string>
+ </dict>
+ </array>
+ <key>GridInfo</key>
+ <dict>
+ <key>ShowsGrid</key>
+ <string>YES</string>
+ </dict>
+ <key>GuidesLocked</key>
+ <string>NO</string>
+ <key>GuidesVisible</key>
+ <string>YES</string>
+ <key>HPages</key>
+ <integer>1</integer>
+ <key>ImageCounter</key>
+ <integer>1</integer>
+ <key>KeepToScale</key>
+ <false/>
+ <key>Layers</key>
+ <array>
+ <dict>
+ <key>Lock</key>
+ <string>NO</string>
+ <key>Name</key>
+ <string>Layer 1</string>
+ <key>Print</key>
+ <string>YES</string>
+ <key>View</key>
+ <string>YES</string>
+ </dict>
+ </array>
+ <key>LayoutInfo</key>
+ <dict>
+ <key>Animate</key>
+ <string>NO</string>
+ <key>circoMinDist</key>
+ <real>18</real>
+ <key>circoSeparation</key>
+ <real>0.0</real>
+ <key>layoutEngine</key>
+ <string>dot</string>
+ <key>neatoSeparation</key>
+ <real>0.0</real>
+ <key>twopiSeparation</key>
+ <real>0.0</real>
+ </dict>
+ <key>LinksVisible</key>
+ <string>NO</string>
+ <key>MagnetsVisible</key>
+ <string>NO</string>
+ <key>MasterSheets</key>
+ <array/>
+ <key>ModificationDate</key>
+ <string>2011-10-20 15:09:11 -0700</string>
+ <key>Modifier</key>
+ <string>Katie McCormick</string>
+ <key>NotesVisible</key>
+ <string>NO</string>
+ <key>Orientation</key>
+ <integer>2</integer>
+ <key>OriginVisible</key>
+ <string>NO</string>
+ <key>PageBreaks</key>
+ <string>YES</string>
+ <key>PrintInfo</key>
+ <dict>
+ <key>NSBottomMargin</key>
+ <array>
+ <string>float</string>
+ <string>41</string>
+ </array>
+ <key>NSLeftMargin</key>
+ <array>
+ <string>float</string>
+ <string>18</string>
+ </array>
+ <key>NSPaperSize</key>
+ <array>
+ <string>size</string>
+ <string>{612, 792}</string>
+ </array>
+ <key>NSRightMargin</key>
+ <array>
+ <string>float</string>
+ <string>18</string>
+ </array>
+ <key>NSTopMargin</key>
+ <array>
+ <string>float</string>
+ <string>18</string>
+ </array>
+ </dict>
+ <key>PrintOnePage</key>
+ <false/>
+ <key>QuickLookPreview</key>
+ <data>
+ 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
+ IC9QYWdlIC9QYXJlbnQgNCAwIFIgL1Jlc291cmNlcyA3IDAgUiAvQ29udGVudHMgNSAw
+ IFIgL01lZGlhQm94IFswIDAgNTc2IDczM10KPj4KZW5kb2JqCjcgMCBvYmoKPDwgL1By
+ b2NTZXQgWyAvUERGIC9UZXh0IC9JbWFnZUIgL0ltYWdlQyAvSW1hZ2VJIF0gL0NvbG9y
+ U3BhY2UgPDwgL0NzMSA4IDAgUgovQ3MyIDEzIDAgUiA+PiAvRm9udCA8PCAvRjEuMCAx
+ NCAwIFIgL0YyLjAgMTYgMCBSID4+IC9YT2JqZWN0IDw8IC9JbTEgOSAwIFIKL0ltMiAx
+ MSAwIFIgPj4gL1NoYWRpbmcgPDwgL1NoMiAxNyAwIFIgL1NoMSAxNSAwIFIgL1NoMyAx
+ OCAwIFIgL1NoNCAxOSAwIFIKL1NoNSAyMCAwIFIgPj4gPj4KZW5kb2JqCjE3IDAgb2Jq
+ Cjw8IC9Db2xvclNwYWNlIDIxIDAgUiAvU2hhZGluZ1R5cGUgMiAvQ29vcmRzIFsgNDAu
+ NTkyNiAtMjUuNTg0ODUgNDAuNTkyNTkKMjUuNTg0ODcgXSAvRG9tYWluIFsgMCAxIF0g
+ L0V4dGVuZCBbIGZhbHNlIGZhbHNlIF0gL0Z1bmN0aW9uIDIyIDAgUiA+PgplbmRvYmoK
+ MTUgMCBvYmoKPDwgL0NvbG9yU3BhY2UgMjEgMCBSIC9TaGFkaW5nVHlwZSAyIC9Db29y
+ ZHMgWyA0MC41OTI2IC0yNS41ODQ4NSA0MC41OTI1OQoyNS41ODQ4NyBdIC9Eb21haW4g
+ WyAwIDEgXSAvRXh0ZW5kIFsgZmFsc2UgZmFsc2UgXSAvRnVuY3Rpb24gMjMgMCBSID4+
+ CmVuZG9iagoxOCAwIG9iago8PCAvQ29sb3JTcGFjZSAyMSAwIFIgL1NoYWRpbmdUeXBl
+ IDIgL0Nvb3JkcyBbIDQwLjU5MjYgLTI1LjU4NDg1IDQwLjU5MjU5CjI1LjU4NDg3IF0g
+ L0RvbWFpbiBbIDAgMSBdIC9FeHRlbmQgWyBmYWxzZSBmYWxzZSBdIC9GdW5jdGlvbiAy
+ NCAwIFIgPj4KZW5kb2JqCjE5IDAgb2JqCjw8IC9Db2xvclNwYWNlIDIxIDAgUiAvU2hh
+ ZGluZ1R5cGUgMiAvQ29vcmRzIFsgNDAuNTkyNiAtMjUuNTg0ODUgNDAuNTkyNTkKMjUu
+ NTg0ODcgXSAvRG9tYWluIFsgMCAxIF0gL0V4dGVuZCBbIGZhbHNlIGZhbHNlIF0gL0Z1
+ bmN0aW9uIDI1IDAgUiA+PgplbmRvYmoKMjAgMCBvYmoKPDwgL0NvbG9yU3BhY2UgMjEg
+ MCBSIC9TaGFkaW5nVHlwZSAyIC9Db29yZHMgWyA0MC41OTI2IC0yNS41ODQ4NSA0MC41
+ OTI1OQoyNS41ODQ4NyBdIC9Eb21haW4gWyAwIDEgXSAvRXh0ZW5kIFsgZmFsc2UgZmFs
+ c2UgXSAvRnVuY3Rpb24gMjYgMCBSID4+CmVuZG9iago5IDAgb2JqCjw8IC9MZW5ndGgg
+ MTAgMCBSIC9UeXBlIC9YT2JqZWN0IC9TdWJ0eXBlIC9JbWFnZSAvV2lkdGggMTc0IC9I
+ ZWlnaHQgMTE0IC9JbnRlcnBvbGF0ZQp0cnVlIC9Db2xvclNwYWNlIDI3IDAgUiAvSW50
+ ZW50IC9QZXJjZXB0dWFsIC9TTWFzayAyOCAwIFIgL0JpdHNQZXJDb21wb25lbnQKOCAv
+ RmlsdGVyIC9GbGF0ZURlY29kZSA+PgpzdHJlYW0KeAHt0AENAAAAwqD3T20ON4hAYcCA
+ AQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgw
+ YMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMG
+ DBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCA
+ AQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgw
+ YMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMG
+ PgYG6HQAAQplbmRzdHJlYW0KZW5kb2JqCjEwIDAgb2JqCjI4MwplbmRvYmoKMTEgMCBv
+ YmoKPDwgL0xlbmd0aCAxMiAwIFIgL1R5cGUgL1hPYmplY3QgL1N1YnR5cGUgL0ltYWdl
+ IC9XaWR0aCAxODIgL0hlaWdodCAxMjIgL0ludGVycG9sYXRlCnRydWUgL0NvbG9yU3Bh
+ Y2UgMjcgMCBSIC9JbnRlbnQgL1BlcmNlcHR1YWwgL1NNYXNrIDMwIDAgUiAvQml0c1Bl
+ ckNvbXBvbmVudAo4IC9GaWx0ZXIgL0ZsYXRlRGVjb2RlID4+CnN0cmVhbQp4Ae3QMQEA
+ AADCoPVPbQZ/iEBhwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIAB
+ AwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBg
+ wIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYM
+ GDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIAB
+ AwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBg
+ wIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBg4BsYBEMA
+ AQplbmRzdHJlYW0KZW5kb2JqCjEyIDAgb2JqCjMxNAplbmRvYmoKMzAgMCBvYmoKPDwg
+ L0xlbmd0aCAzMSAwIFIgL1R5cGUgL1hPYmplY3QgL1N1YnR5cGUgL0ltYWdlIC9XaWR0
+ aCAxODIgL0hlaWdodCAxMjIgL0NvbG9yU3BhY2UKL0RldmljZUdyYXkgL0ludGVycG9s
+ YXRlIHRydWUgL0JpdHNQZXJDb21wb25lbnQgOCAvRmlsdGVyIC9GbGF0ZURlY29kZSA+
+ PgpzdHJlYW0KeAHt3E1vomAQB3ABBcQXKjTtYqH2UGxtlaauTeoLTU1gtW6tmEq13/+L
+ LLibFNHZyzrZx2TmZOYwjj/R2/wzGSoSIAES2JcAx/MCi8XzHPQROV7IiZKcZ69kScwK
+ uxfnhJxcKKkVjb2qqKWCnBN2ePOCWFD106ppnbNWllk91dWCuL02J0hFvXph3zQd546t
+ cpxmw64ZelFKr80JYvHYqjsP3YH7xFq5g27HqVvHxbQ2nyvo1nW7P/RH4xfWajzyh732
+ taUpOX7jr0SQVaPedv2fb7NgzloFs7eJN2jXDVUSkltz2YJ+4fT91/kiDD9YqzBczF+9
+ nlPTlWzyf4QXS6f2w3AyD5fL1Wr1yVJF+yyX4Xwy7NgnJXFja0mt3nT9t0W8M2Nbf37G
+ ey+mfrdRVaXkgy3IFbM5GM1C5qTjbz3eOpyN+rdnR/LG1vmK5bjjIGQP+s/aYTB2W1ZF
+ Tv4chbx27jy9zKOtWXqkv3ZZhcHLk2Np+fTWdwe79cfXp2Ps1ccctmZ86/PdTwhtvd9H
+ bP2EkPV+UYFpZA3AILTJGgEVGEnWAAxCm6wRUIGRZA3AILTJGgEVGEnWAAxCm6wRUIGR
+ ZA3AILTJGgEVGEnWAAxCm6wRUIGRZA3AILTJGgEVGEnWAAxCm6wRUIGRZA3AILTJGgEV
+ GEnWAAxCm6wRUIGRZA3AILTJGgEVGEnWAAxCm6wRUIGRZA3AILTJGgEVGEnWAAxCm6wR
+ UIGRZA3AILTJGgEVGEnWAAxCm6wRUIGRZA3AILTJGgEVGEnWAAxCm6wRUIGRZA3AILQP
+ 2Bq8JUVg2sdI8AL2993uPt4CYQaw9UHcSJupG+lDuUffuKLno9v/Rtefrm//Eb7gfxsZ
+ X9G/T71uI4qHSF7Rr3MWOmznLDx3LlM5C1xW0WtOz1tnWjCWahFG9R5nWrTSmRYZQVIN
+ uz3wJtNZwFqASBDMplF+yL1tlDfzQzJ8TtGsq3bv2fvBXFjLePTDe+7dX5lbWS3rXBzT
+ bnUe+y5rwTiu23/83rJNfSsXJxNnEGlG7bJx22w5bFWreXt9WfumbS+didYWlbJ+YpyZ
+ FmtlnhknWllJJxCtI3KibC1JKZWPKlExFK8Vr3NULirSzmytSJsXslGOGXtBZvJfcsxi
+ cI7N0LgoMi6Z4pNMT6LXJEAC/1fgF8y5cjkKZW5kc3RyZWFtCmVuZG9iagozMSAwIG9i
+ ago4ODQKZW5kb2JqCjI4IDAgb2JqCjw8IC9MZW5ndGggMjkgMCBSIC9UeXBlIC9YT2Jq
+ ZWN0IC9TdWJ0eXBlIC9JbWFnZSAvV2lkdGggMTc0IC9IZWlnaHQgMTE0IC9Db2xvclNw
+ YWNlCi9EZXZpY2VHcmF5IC9JbnRlcnBvbGF0ZSB0cnVlIC9CaXRzUGVyQ29tcG9uZW50
+ IDggL0ZpbHRlciAvRmxhdGVEZWNvZGUgPj4Kc3RyZWFtCngB7dzbTupQEAbgrh4obYAe
+ EuuuUpINJh5Ka4KJNUGqRmNLorYEi/D+L7IXVHR03w7JIpm5mqvJz5cpd2skiWrnAkyW
+ FRFLltnv386Yojb0piFeNfWGqrAfgZms6mbbchxXtHJsq2XqKvRlima0Xe+oG/REq6Dr
+ e27b0L7jMlkz7cPeyfkwji/Fqjganp/0Dm1Tk7fLy1TD9gfh1c14kopWk/HNVdj3bUPd
+ rq6itw8HcXL3lOVT0SrPntIk6nttXalxmWq6vTB5yF+LciZalcVr/pCEgWt+4rJGyzu5
+ usuLeVUtRKuqmhd5Ohp4La1eBVm3js5vnl7ni4/lcrkSqXiej8X85TE58zt6/Z3JTbs7
+ HGdFxcOKFHWThcd9L57H4bH9mVYxnCCa5GUlYNjVarmsynwSdZ1m/ZkphtuL0+msEk92
+ zcvTTidx4BrfaS/FTpv+n3Yh3NLWgRaz6b6l7f3eBKFtKe1ONn+zt2RLtivahJ0swWYo
+ 2ZJtLUCbQJtAm7C7HSBbsoUC9H8LNXB7ssX1hNPIFmrg9mSL6wmnkS3UwO3JFtcTTiNb
+ qIHbky2uJ5xGtlADtydbXE84jWyhBm5PtriecBrZQg3cnmxxPeE0soUauD3Z4nrCaWQL
+ NXB7ssX1hNPIFmrg9mSL6wmnkS3UwO3JFtcTTiNbqIHbky2uJ5xGtlADtydbXE84jWyh
+ Bm5PtriecBrZQg3cnmxxPeG0je0ev93bp3eR+/TmdL/e88p6xz8T/K30qd9p1G+lmdby
+ BqM0f5u/V4K9ROd53udvGX+HfrB9h75+4x+EyX32UpSiPfIvy+Ilu7++CJyvAwr8foLX
+ j67Tx2fhDijk2fNjer2+n/C5CJLEb1NYfj8cJeNb0Y5TTG7Hyeji7x/ri1aS+N0PywsG
+ p+EwisWqaBieDgLP4mdKtnc/JH6mhN9UOfCPu4Fo1T32D5wfN1X4Lshqw2x1bIeXQBdr
+ 1nGsTsto/LhXw5F5Xk3EY0D8FJD2O+t6J5iYh5b4maXt7ZevzaWGBP4BbIC/7gplbmRz
+ dHJlYW0KZW5kb2JqCjI5IDAgb2JqCjc3NwplbmRvYmoKMzIgMCBvYmoKPDwgL0xlbmd0
+ aCAzMyAwIFIgL04gMyAvQWx0ZXJuYXRlIC9EZXZpY2VSR0IgL0ZpbHRlciAvRmxhdGVE
+ ZWNvZGUgPj4Kc3RyZWFtCngBhVTPaxNBFP42bqnQIghaaw6yeJAiSVmraEXUNv0RYmsM
+ 2x+2RZBkM0nWbjbr7ia1pYjk4tEq3kXtoQf/gB568GQvSoVaRSjeqyhioRct8c1uTLal
+ 6sDOfvPeN+99b3bfAA1y0jT1gATkDcdSohFpbHxCavyIAI6iCUE0JVXb7E4kBkGDc/l7
+ 59h6D4FbVsN7+3eyd62a0raaB4T9QOBHmtkqsO8XcQpZEgKIPN+hKcd0CN/j2PLsjzlO
+ eXjBtQ8rPcRZInxANS3Of024U80l00CDSDiU9XFSPpzXi5TXHQdpbmbGyBC9T5Cmu8zu
+ q2KhnE72DpC9nfR+TrPePsIhwgsZrT9GuI2e9YzVP+Jh4aTmxIY9HBg19PhgFbcaqfg1
+ whRfEE0nolRx2S4N8Ziu/VbySoJwkDjKZGGAc1pIT9dMbvi6hwV9JtcTr+J3VlHheY8T
+ Z97U3e9F2gKvMA4dDBoMmg1IUBBFBGGYsFBAhjwaMTSycj8jqwYbk3sydSRqu3RiRLFB
+ ezbcPbdRpN08/igicZRDtQiS/EH+Kq/JT+V5+ctcsNhW95Stm5q68uA7xeWZuRoe19PI
+ 43NNXnyV1HaTV0eWrHl6vJrsGj/sV5cx5oI1j8RzsPvxLV+VzJcpjBTF41Xz6kuEdVox
+ N9+fbH87PeIuzy611nOtiYs3VpuXZ/1qSPvuqryT5lX5T1718fxnzcRj4ikxJnaK5yGJ
+ l8Uu8ZLYS6sL4mBtxwidlYYp0m2R+iTVYGCavPUvXT9beL1Gfwz1UZQZzNJUifd/wipk
+ NJ25Dm/6j9vH/Bfk94rnnygCL2zgyJm6bVNx7xChZaVuc64CF7/RffC2bmujfjj8BFg8
+ qxatUjWfILwBHHaHeh7oKZjTlpbNOVKHLJ+TuunKYlLMUNtDUlLXJddlSxazmVVi6XbY
+ mdMdbhyhOUL3xKdKZZP6r/ERsP2wUvn5rFLZfk4a1oGX+m/AvP1FCmVuZHN0cmVhbQpl
+ bmRvYmoKMzMgMCBvYmoKNzM3CmVuZG9iagoyMSAwIG9iagpbIC9JQ0NCYXNlZCAzMiAw
+ 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
+ MbIHs0dlT+Ceyj2TktSS2pKRkvWSM3uZ95ruTd7bsvejlKCUo1Se1H2pbWkFaX/paukX
+ MgwyxjLJMu0yn2XFZUmypbJP5AhyBnJJcq1yq/IS8p7y5fJPFYgKBxSOKfQo/FRUUgxV
+ vKK4qCSo5KpUpjSpzKhsoZyt/EAFo6KjkqTSobKhqqgartqs+klNUs1P7ZLawj6RfZ77
+ qvfNqfOru6mfV5/W4NVw1TinMa3Jp+mmWak5qyWg5aFVo/VOW0zbV/uy9kcdaZ1QnRs6
+ a7qqugm63XooPUO9TL0hfQZ9W/0S/SkDfgNvg3qDFUMFwzjD7v2Y/Sb78/ZPGnEZkYzq
+ jFaMlYwTjPtMqE2sTUpMZk3FTUNN2w/AB4wPnDrw0kzILNCsxRyYG5mfMn9lIWIRYnHL
+ EmtpYVlq+dZKxire6r410drF+pL1dxsdm1ybF7aithG2PXa0dk52dXZr9nr2+fbTB6UO
+ JhwccGB3IDu0OuIc7RxrHL8d0j90+tC8k4JTutPEYZHD0YcfOrM7+zt3utC6uLlcc8W4
+ 2rtect1yM3erdPvmbuRe5r5C0iUVkZY8tDwKPBY91T3zPd95qXvley14q3uf8l700fQp
+ 9Fkm65JLyKu++30rfNf8zP0u+u342/s3BlAEuAa0BTIE+gX2BXEHRQeNBEsEpwdPh6iG
+ nA5ZCTUJrQmDwg6HtYYzIi+HgxGiEWkRM5EakaWR61F2Udei6aMDowdjxGMyYt7FGsRe
+ iEPHkeJ64vnij8bPJGgnnE+EEt0Te5IEklKT5o8YHqk9SnXU7+ijZOnk/OSvKfYp7alc
+ qUdS59IM0+rTadJD0yePqR2rOI4+Tj4+lCGXcSZjO9Mjsz9LOqswayublN1/QuZE8Ymd
+ HK+coVzF3PKT2JOBJyfyNPNq8+nzY/PnTh04dbOAtyCz4Otpl9MPC+ULK4qoiiKKpotN
+ i1vPCJ45eWarxKdkvFSntLGMsyyjbO2sx9nRcq3yKxVcFVkVP86Rzz09b3j+ZqVwZWEV
+ tiqy6m21XfX9C8oX6mrYa7Jqfl4MvDhda1XbV6dUV3eJ81JuPVwfUb942enycINeQ+sV
+ ySvnG5kbs5pAU0TT+6uuVyeaTZp7rilfu3Jd6HrZDeKNzJvQzZibKy0+LdOtDq0jbcZt
+ Pe1q7Tdu7b11sYOvo7STqTO3i6ortWvnduztb93B3ct3vO/M9bj0vOg92Pukz7Jv6K7J
+ 3Qf3DO713te+f/uB+oOOh6oP2/qV+1sGFAduDioM3nik8OjGkOLQzcdKj1uHVYbbR/aN
+ dI1qjt4Z0xu798ToycC42fjIhO3E00mnyemnHk8Xnvk/W30e+XzzxZGXmJeZr+heFU5x
+ TlW+FnvdOK043TmjNzM4az37Yo40t/Qm7M3WfOpbwtvCdzzv6hZkFzoWDRaH3x96P78U
+ vLS5nP6B/kPZR9GP1z9pfRpcObgyvxq6uvM5+wvbl4tf5b/2fLP4NvU94PvmWuY623rt
+ hvLG/R/2P95tRm3htop/iv1s3zbZfrkTsLMT7Bbq9utdAIX0sJcXAJ8vIu8JDkjtMAwA
+ Fc3vmuKXBVKuQIgNgu2gvdASfBbljBZCv8d0Y4txwRRWlPpUingp6r0ECRplWhM6V/oI
+ htPENsYZZmoWbdZQtgb2JU4xLl/uJp51Pj3+kwKzQjLCx0ReiSmIn5RYltTfWyW1LeMk
+ 2y7PrhCtOK4sp5KjurzPUP2cxg8tK+0LOht6JvolBgv75Y3ijLtMoQNaZrHmTRZzVvTW
+ 6jYetml25+yvHbzt0OvYfajNqfFwjXOZy0nXZLcQd2eSqYeSJ78XwWvNe8ann9zsW+KX
+ 7E8OsAhUCGIJWgseC6kPTQozD+cJ/xTRFZkT5RQtEf0jpj+2JI4cr5yATRhLrEjyP6Jz
+ VDCZMYU2lS6NPp3uGOE4ZQY6YydzI+tz9tKJ2ZznuaMnB/J68ttOXSmoOn2mMKcopTju
+ TExJcmlx2Y2zw+WzFcvnVs6vVK5Ufar+eOFDzdLFhdo3dTOX5upXG+iv6DYmNrVcfd28
+ fh13g3iTp0W8VaFNs93olnWHe2d0V/HtO90LPeheYh/7Xd574veVHug81OkX7f80kDnI
+ Nnj+keaj5aGGx6HDKiPQyKPR8rGQJ/rjbOMfJ3oni576PFN8tvO8+0XsS7mXy68apsJe
+ 75vGTo/OlM16zcnMbb65N1/w1vOd6gLDwvvFrvfZS/bLfMuLH65+jP2ks4JfGV9t+Fz+
+ 5frXte9ea883tH4UbE7/lNsu2Nn5lX8BqAl2QDGgHqDTMSZYJuwr3DWKbEp/Klu8HrUc
+ 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
+ W2SR/Q9AGf1mCmVuZHN0cmVhbQplbmRvYmoKMzkgMCBvYmoKNzA0CmVuZG9iagoxMyAw
+ IG9iagpbIC9JQ0NCYXNlZCAzOCAwIFIgXQplbmRvYmoKNCAwIG9iago8PCAvVHlwZSAv
+ UGFnZXMgL01lZGlhQm94IFswIDAgNjEyIDc5Ml0gL0NvdW50IDEgL0tpZHMgWyAzIDAg
+ UiBdID4+CmVuZG9iago0MCAwIG9iago8PCAvVHlwZSAvQ2F0YWxvZyAvT3V0bGluZXMg
+ MiAwIFIgL1BhZ2VzIDQgMCBSIC9WZXJzaW9uIC8xLjQgPj4KZW5kb2JqCjI2IDAgb2Jq
+ Cjw8IC9MZW5ndGggNDEgMCBSIC9PcmRlciAxIC9FbmNvZGUgWyAwIDEzNjQgXSAvRnVu
+ Y3Rpb25UeXBlIDAgL0JpdHNQZXJTYW1wbGUKOCAvRGVjb2RlIFsgMCAxIDAgMSAwIDEg
+ XSAvRG9tYWluIFsgMCAxIF0gL1JhbmdlIFsgMCAxIDAgMSAwIDEgXSAvU2l6ZSBbIDEz
+ NjUKXSAvRmlsdGVyIC9GbGF0ZURlY29kZSA+PgpzdHJlYW0KeAGtwQcCgQAAQNH7X0k0
+ VLQ1jBbtNHUFd+C/t20/+mwfzspZlnWhzMvMmaZ5oozTyBlA7+HN6UFd31HaruU0TdtQ
+ 6qbmVFVdUcqq5BSgV/HiPEH5M6dkecZJ0yylJGnCieMkpjziB+cOut1vnCsoukaUMAo5
+ QRAGFD/wOReQd/E4LshxHY4NsmyLYlomyDANytk4c04g/aRzNJCqqZwjSDkqFFmRQZIs
+ UURJ5BxA+8OeI4B2wu5/X6r+RswKZW5kc3RyZWFtCmVuZG9iago0MSAwIG9iagoxODgK
+ ZW5kb2JqCjI1IDAgb2JqCjw8IC9MZW5ndGggNDIgMCBSIC9PcmRlciAxIC9FbmNvZGUg
+ WyAwIDEzNjQgXSAvRnVuY3Rpb25UeXBlIDAgL0JpdHNQZXJTYW1wbGUKOCAvRGVjb2Rl
+ IFsgMCAxIDAgMSAwIDEgXSAvRG9tYWluIFsgMCAxIF0gL1JhbmdlIFsgMCAxIDAgMSAw
+ IDEgXSAvU2l6ZSBbIDEzNjUKXSAvRmlsdGVyIC9GbGF0ZURlY29kZSA+PgpzdHJlYW0K
+ eAGVwolS02AUBtBHabqmaZI2adINRUFRFEFFUVxRFBUFcUVQ9Hnz73kFp4yd2k6a3u/M
+ GfxJB1N/pwPoWTo43z9LSX+lfejPtE9/mvaz9k7T7Cdpb37TOxn9YXrQY9PL3T02499N
+ F/rNdKFfTRfZ+WKAn00H+sl0oEemMxofmTk/mhh6aOLsOj7MeqDjGaMDnfGDjujf6wi6
+ ryPa9r4efgd+q9v0b3Qbuqfbezqkf61D6Csd0u/qcFyFu8NBzpcqgL5QAXRHBbO3dtTE
+ 56oFfaZa0KeqRd58orCPVRP6SDWh26o56m+r3NJ/CH4gfeiW9LN6WzL7fenR35MedFN6
+ hO6m/PeudKF3pEt/W7rQDeluyAb9umzkFY31ybdEg35NNCY7ayLvTeFAbwiHflU4ueur
+ YuJ1UYdeE3XoiqjT2ivCvgq+ImzosrCnc3t59iVun68t8fkv8xr0Eq9BF3kta3WRZ7/I
+ q/QXeBW6wKvzVhb4+IBXoH1eoe/xCrTLy8OMusPK0JiV6SNWnlyKWN42K0FDVqIPWGn2
+ YsCmt1gR2mRFqM+KtJbPLI8+sbzEcsGNxII6ieUkBeJ6UoDaSQFaSwr//QuuW4G8CmVu
+ ZHN0cmVhbQplbmRvYmoKNDIgMCBvYmoKNDU2CmVuZG9iagoyNCAwIG9iago8PCAvTGVu
+ Z3RoIDQzIDAgUiAvT3JkZXIgMSAvRW5jb2RlIFsgMCAxMzY0IF0gL0Z1bmN0aW9uVHlw
+ ZSAwIC9CaXRzUGVyU2FtcGxlCjggL0RlY29kZSBbIDAgMSAwIDEgMCAxIF0gL0RvbWFp
+ biBbIDAgMSBdIC9SYW5nZSBbIDAgMSAwIDEgMCAxIF0gL1NpemUgWyAxMzY1Cl0gL0Zp
+ bHRlciAvRmxhdGVEZWNvZGUgPj4Kc3RyZWFtCngBlcKJUtNgFAbQR2m6pmmSNmnSDUVB
+ URRBRVFcURQVBXFFUPR58+95BaeMndpOmt7vzBn8SQdTf6cD6Fk6ON8/S0l/pX3oz7RP
+ f5r2s/ZO0+wnaW9+0zsZ/WF60GPTy909NuPfTRf6zXShX00X2fligJ9NB/rJdKBHpjMa
+ H5k5P5oYemji7Do+zHqg4xmjA53xg47o3+sIuq8j2va+Hn4Hfqvb9G90G7qn23s6pH+t
+ Q+grHdLv6nBchbvDQc6XKoC+UAF0RwWzt3bUxOeqBX2mWtCnqkXefKKwj1UT+kg1oduq
+ Oepvq9zSfwh+IH3olvSzelsy+33p0d+THnRTeoTupvz3rnShd6RLf1u60A3pbsgG/bps
+ 5BWN9cm3RIN+TTQmO2si703hQG8Ih35VOLnrq2LidVGHXhN16Iqo09orwr4KviJs6LKw
+ p3N7efYlbp+vLfH5L/Ma9BKvQRd5LWt1kWe/yKv0F3gVusCr81YW+PiAV6B9XqHv8Qq0
+ y8vDjLrDytCYlekjVp5ciljeNitBQ1aiD1hp9mLAprdYEdpkRajPirSWzyyPPrG8xHLB
+ jcSCOonlJAXielKA2kkBWksK//0LrluBvAplbmRzdHJlYW0KZW5kb2JqCjQzIDAgb2Jq
+ CjQ1NgplbmRvYmoKMjMgMCBvYmoKPDwgL0xlbmd0aCA0NCAwIFIgL09yZGVyIDEgL0Vu
+ Y29kZSBbIDAgMTM2NCBdIC9GdW5jdGlvblR5cGUgMCAvQml0c1BlclNhbXBsZQo4IC9E
+ ZWNvZGUgWyAwIDEgMCAxIDAgMSBdIC9Eb21haW4gWyAwIDEgXSAvUmFuZ2UgWyAwIDEg
+ MCAxIDAgMSBdIC9TaXplIFsgMTM2NQpdIC9GaWx0ZXIgL0ZsYXRlRGVjb2RlID4+CnN0
+ cmVhbQp4AZXCiVLTYBQG0EdpuqZpkjZp0g1FQVEUQUVRXFEUFQVxRVD0efPveQWnjJ3a
+ Tpre78wZ/EkHU3+nA+hZOjjfP0tJf6V96M+0T3+a9rP2TtPsJ2lvftM7Gf1hetBj08vd
+ PTbj300X+s10oV9NF9n5YoCfTQf6yXSgR6YzGh+ZOT+aGHpo4uw6Psx6oOMZowOd8YOO
+ 6N/rCLqvI9r2vh5+B36r2/RvdBu6p9t7OqR/rUPoKx3S7+pwXIW7w0HOlyqAvlABdEcF
+ s7d21MTnqgV9plrQp6pF3nyisI9VE/pINaHbqjnqb6vc0n8IfiB96Jb0s3pbMvt96dHf
+ kx50U3qE7qb89650oXekS39butAN6W7IBv26bOQVjfXJt0SDfk00JjtrIu9N4UBvCId+
+ VTi566ti4nVRh14TdeiKqNPaK8K+Cr4ibOiysKdze3n2JW6fry3x+S/zGvQSr0EXeS1r
+ dZFnv8ir9Bd4FbrAq/NWFvj4gFegfV6h7/EKtMvLw4y6w8rQmJXpI1aeXIpY3jYrQUNW
+ og9YafZiwKa3WBHaZEWoz4q0ls8sjz6xvMRywY3EgjqJ5SQF4npSgNpJAVpLCv/9C65b
+ gbwKZW5kc3RyZWFtCmVuZG9iago0NCAwIG9iago0NTYKZW5kb2JqCjIyIDAgb2JqCjw8
+ IC9MZW5ndGggNDUgMCBSIC9PcmRlciAxIC9FbmNvZGUgWyAwIDEzNjQgXSAvRnVuY3Rp
+ b25UeXBlIDAgL0JpdHNQZXJTYW1wbGUKOCAvRGVjb2RlIFsgMCAxIDAgMSAwIDEgXSAv
+ RG9tYWluIFsgMCAxIF0gL1JhbmdlIFsgMCAxIDAgMSAwIDEgXSAvU2l6ZSBbIDEzNjUK
+ XSAvRmlsdGVyIC9GbGF0ZURlY29kZSA+PgpzdHJlYW0KeAGlwoVSQlEAQMG/tru7u7Hp
+ BhUDA1uxA+tTjjEy+PDFjZ1NfpC0mPjg+7vi+DvF34gLj71h95WY7egrEl+IGkdeUJwj
+ kiOsPZQj9Kw++IzhE0GZgSfsPhKw7X9E9AP+f30PqLzH99N7j2bPHTrddxje4pa5eovl
+ G1adrtwg9JoVs8vXSL9iOX/pCs2LWXQuZCm8ZEHy/CXmL5gX6LpA6Dkus3PnSD9jLn/2
+ DK2nzOidPuX3CdPyp04wf8yUwMljnB8xaXHiCLmHTPw5foj6DOMZxvSOZvh9wKj8kQNM
+ 7jMidngfh3sMWx/aQ+IuQ8aDu6hPM5hmQG9/mu87ivt2KL5Nn/DebRxu0Wu9ZwuJm/QY
+ d2+iOEX3z64UOjtTdG6o79ig+DodwtvXsbtGu+22NUQnafu3NYnKBK35LQl0Nidojqtv
+ imMYo0lmYwzLURqdNkQRGqHBbH0ElWHq8+vC6KwNobMmRGGQGsnVQSwHqHZaFUConyqz
+ lX6k+6j8s8KHei/lesu8FHook1zqwbybUoElbr5+Al7liFUKZW5kc3RyZWFtCmVuZG9i
+ ago0NSAwIG9iago0MTAKZW5kb2JqCjIgMCBvYmoKPDwgL0xhc3QgNDYgMCBSIC9GaXJz
+ dCA0NyAwIFIgPj4KZW5kb2JqCjQ3IDAgb2JqCjw8IC9QYXJlbnQgNDggMCBSIC9Db3Vu
+ dCAwIC9EZXN0IFsgMyAwIFIgL1hZWiAwIDczMyAwIF0gL1RpdGxlIChDYW52YXMgMSkK
+ Pj4KZW5kb2JqCjQ4IDAgb2JqCjw8ID4+CmVuZG9iago0NiAwIG9iago8PCAvUGFyZW50
+ IDQ4IDAgUiAvQ291bnQgMCAvRGVzdCBbIDMgMCBSIC9YWVogMCA3MzMgMCBdIC9UaXRs
+ ZSAoQ2FudmFzIDEpCj4+CmVuZG9iago0OSAwIG9iago8PCAvTGVuZ3RoIDUwIDAgUiAv
+ TGVuZ3RoMSAxMDUzMiAvRmlsdGVyIC9GbGF0ZURlY29kZSA+PgpzdHJlYW0KeAG9ent8
+ VEWW8Km6z34k6e50p9+PS6e78w4JEAgJpAlJCK8IBCFBowkkkCCMgDGKO/BFRYGIKCIP
+ xVVRh6dOmsBIA4PLsDDI7syIM4oj6646ouu6mx878+F8M0B3f6duhwzJz5kff/ibe/tU
+ 1annqVOnzjlVtztXPdgGKdANHMxa0LJiMahPKAxALi9a3rIiiaebMT6wqKvTl8SFLABu
+ 2eIVS5Yncfl5AK17ybLVA+3TrwKYPmhva2lNlsMNjEvaMSOJk9EYZ7Yv73w4iZuOYNy8
+ 7P5FA+XppxAvXt7y8MD48Anivh+0LG/DGJ+QC4PMFfc/0KmiEHwX47krVrUN1CcNSN97
+ QDDXBveDBu4DCSgY8G0CkL7WuoHHUlaOT2uebuu9aeXfglFW8XtnPqPGP1d+evFPbTdC
+ ui3ynzFDc7M+i8XseDaAnmB5v27LYInaDgNbFOpzozAVoQJhDEJu7iQbdJM98CzCqwgc
+ dJCnYDXCRoQXEPjB1H7EjpGn+ng5fJysBgeZFtbx3rlmu9em1Xl/HSXikZe9H9u+OEHs
+ uHqfE3tfCmgmacmr5BVoBS/5EQTII1ALWeTFw9nLvM1YtB9WIHQjcGpIyP4+T7H3HZIH
+ AZ5gmyB4ePK29z+L8r1fFkUp6fOeDkV5jH7mQSyc5j3lftn7T+4l3ncQDiaLDmRjjbe9
+ +93LvFs9UfJin/c5d5Rgmy3J6EE3Nn3buzx7u7e1SC2fsT1KD/Z5S7F8XljnLRmneMe4
+ L3sLQ1GZIJ7vnuHNKfqlNxMbYjUfdhoIG70u91bveCzyuKtD4xFOkANkF+SQXX2Bad7j
+ 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
+ uIoNeAQzQibCaIQqhLkIrQidCOsQnkd4A+EIwhmEDxIDD/YBg2mCemcoPmkYPnkYXjUM
+ rx6Go4Id0v+MYXjdMHzOMBznMaT9vGH4vcNwxsFb57NoGN46DFfX9pb5dwwrV/+PeEv5
+ D4aVrxqG483wkPGR/0PwLob/fzlhnKgKZW5kc3RyZWFtCmVuZG9iago1MCAwIG9iago2
+ ODEyCmVuZG9iago1MSAwIG9iago8PCAvVHlwZSAvRm9udERlc2NyaXB0b3IgL0FzY2Vu
+ dCA3NzAgL0NhcEhlaWdodCA2ODQgL0Rlc2NlbnQgLTIzMCAvRmxhZ3MgMzIKL0ZvbnRC
+ Qm94IFstOTUxIC00ODEgMTQ0NSAxMTIyXSAvRm9udE5hbWUgL1ZWWEZIWitIZWx2ZXRp
+ Y2EgL0l0YWxpY0FuZ2xlIDAKL1N0ZW1WIDAgL01heFdpZHRoIDE1MDAgL1hIZWlnaHQg
+ NTEzIC9Gb250RmlsZTIgNDkgMCBSID4+CmVuZG9iago1MiAwIG9iagpbIDI3OCAwIDAg
+ MCAwIDAgMCAwIDAgMCAwIDAgMCAwIDAgMCAwIDAgMCA2NjcgMCA3MjIgNzIyIDY2NyAw
+ IDAgMCAyNzggMCAwCjU1NiAwIDcyMiAwIDAgMCA3MjIgMCA2MTEgMCA2NjcgMCAwIDAg
+ MCAwIDAgMCAwIDU1NiAwIDU1NiAwIDUwMCA1NTYgNTU2IDAKMCAwIDIyMiAwIDAgMCA4
+ MzMgNTU2IDAgMCAwIDMzMyA1MDAgMjc4IDAgNTAwIF0KZW5kb2JqCjE0IDAgb2JqCjw8
+ IC9UeXBlIC9Gb250IC9TdWJ0eXBlIC9UcnVlVHlwZSAvQmFzZUZvbnQgL1ZWWEZIWitI
+ ZWx2ZXRpY2EgL0ZvbnREZXNjcmlwdG9yCjUxIDAgUiAvV2lkdGhzIDUyIDAgUiAvRmly
+ c3RDaGFyIDQ2IC9MYXN0Q2hhciAxMTggL0VuY29kaW5nIC9NYWNSb21hbkVuY29kaW5n
+ Cj4+CmVuZG9iago1MyAwIG9iago8PCAvTGVuZ3RoIDU0IDAgUiAvTGVuZ3RoMSA5MDEy
+ IC9GaWx0ZXIgL0ZsYXRlRGVjb2RlID4+CnN0cmVhbQp4Ab1aC3RTZbbe+7zy6iNpm6ZJ
+ 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
+ LF3y+flo7Au68O9aYPWUlZUYjZcVNfiG9vzpkRNu65w5ztJ0Q1Xu4vbND5/8036WBghB
+ H/srcz3fT/Yzf0zrSrYkuHTP4AbgsMubroAuAYUMGppkYYJTOeFfaJwywph0UOyRhue1
+ mjORmokaaXz+2y8fHsZraXkoLUmtkM4Ps/U2nbT7rHTrFQL1Taffi6aRkezlieak7X+Y
+ X8KufwFLoi+9EDk6T0R8nVf4S1czD5BOdO7iltM3NgF+7l3kFJbQAecx4Wm60xdQyzRR
+ 0g3MIHsdJzThDtjO7+Ef5w/xJ9iP8CyqWCvHOVN4XmCsiM4UqkJgePpsLrCMWsmQswlj
+ wijLkwUmjHFGRZ/UD+PFBwij9ncZ8kSQTg5Th4YbAsenzgsUji/Y5OXJVaKYyjqwLHpd
+ 9NXoJvS+z9WfO8LVnz9Fc1P+xaQvTN/2S6FIO+RALllhBX0na6QvUs301W4ReaDF9KVr
+ GSyHgFwQyY9JZ05ynfQFEBqX1s/vaClo7lu3sW9wTW+wsP7qdauksbzwa6MA/ZcD/c8D
+ wI1EtxHdT/RLol8TvUh0iuhvROepYALRLCIXUQ3RAqKu2OSP8sBUGOn8O12Wp9RF6Q0z
+ 0ltmyO0z5OAMuXeGTB2b1r6M5UXtrZmRvm6GLP9/ykX5r5qRfs0M+UczZPn/Sy4qL90B
+ wP8BMGBdrQplbmRzdHJlYW0KZW5kb2JqCjU0IDAgb2JqCjU3MzgKZW5kb2JqCjU1IDAg
+ b2JqCjw8IC9UeXBlIC9Gb250RGVzY3JpcHRvciAvQXNjZW50IDc3MCAvQ2FwSGVpZ2h0
+ IDY4NCAvRGVzY2VudCAtMjMwIC9GbGFncyAzMgovRm9udEJCb3ggWy0xMDE4IC00ODEg
+ MTQzNiAxMTU5XSAvRm9udE5hbWUgL0ZVQkpTSStIZWx2ZXRpY2EtQm9sZCAvSXRhbGlj
+ QW5nbGUKMCAvU3RlbVYgMCAvTWF4V2lkdGggMTUwMCAvWEhlaWdodCA1MTMgL0ZvbnRG
+ aWxlMiA1MyAwIFIgPj4KZW5kb2JqCjU2IDAgb2JqClsgNzIyIDAgNzIyIDAgNjY3IDAg
+ MCAwIDI3OCAwIDAgMCAwIDAgMCAwIDAgNzIyIDAgMCAwIDAgMCAwIDAgMCAwIDAgMCAw
+ IDAKMCA1NTYgMCA1NTYgNjExIDU1NiAwIDAgMCAyNzggMCAwIDI3OCA4ODkgNjExIDAg
+ MCAwIDM4OSA1NTYgMzMzIDAgNTU2IF0KZW5kb2JqCjE2IDAgb2JqCjw8IC9UeXBlIC9G
+ b250IC9TdWJ0eXBlIC9UcnVlVHlwZSAvQmFzZUZvbnQgL0ZVQkpTSStIZWx2ZXRpY2Et
+ Qm9sZCAvRm9udERlc2NyaXB0b3IKNTUgMCBSIC9XaWR0aHMgNTYgMCBSIC9GaXJzdENo
+ YXIgNjUgL0xhc3RDaGFyIDExOCAvRW5jb2RpbmcgL01hY1JvbWFuRW5jb2RpbmcKPj4K
+ ZW5kb2JqCjU3IDAgb2JqCihVbnRpdGxlZCkKZW5kb2JqCjU4IDAgb2JqCihNYWMgT1Mg
+ WCAxMC42LjggUXVhcnR6IFBERkNvbnRleHQpCmVuZG9iago1OSAwIG9iagooS2F0aWUg
+ TWNDb3JtaWNrKQplbmRvYmoKNjAgMCBvYmoKKE9tbmlHcmFmZmxlIFByb2Zlc3Npb25h
+ bCkKZW5kb2JqCjYxIDAgb2JqCihEOjIwMTExMDIwMjIwOTQyWjAwJzAwJykKZW5kb2Jq
+ CjEgMCBvYmoKPDwgL1RpdGxlIDU3IDAgUiAvQXV0aG9yIDU5IDAgUiAvUHJvZHVjZXIg
+ NTggMCBSIC9DcmVhdG9yIDYwIDAgUiAvQ3JlYXRpb25EYXRlCjYxIDAgUiAvTW9kRGF0
+ ZSA2MSAwIFIgPj4KZW5kb2JqCnhyZWYKMCA2MgowMDAwMDAwMDAwIDY1NTM1IGYgCjAw
+ MDAwMzM0MDYgMDAwMDAgbiAKMDAwMDAxODk5NCAwMDAwMCBuIAowMDAwMDAyNTg1IDAw
+ MDAwIG4gCjAwMDAwMTU2OTAgMDAwMDAgbiAKMDAwMDAwMDAyMiAwMDAwMCBuIAowMDAw
+ MDAyNTY1IDAwMDAwIG4gCjAwMDAwMDI2ODkgMDAwMDAgbiAKMDAwMDAwODY3NSAwMDAw
+ MCBuIAowMDAwMDAzNzU1IDAwMDAwIG4gCjAwMDAwMDQyNTggMDAwMDAgbiAKMDAwMDAw
+ NDI3OCAwMDAwMCBuIAowMDAwMDA0ODEzIDAwMDAwIG4gCjAwMDAwMTU2NTMgMDAwMDAg
+ biAKMDAwMDAyNjYxMSAwMDAwMCBuIAowMDAwMDAzMTExIDAwMDAwIG4gCjAwMDAwMzMw
+ MjggMDAwMDAgbiAKMDAwMDAwMjk1MCAwMDAwMCBuIAowMDAwMDAzMjcyIDAwMDAwIG4g
+ CjAwMDAwMDM0MzMgMDAwMDAgbiAKMDAwMDAwMzU5NCAwMDAwMCBuIAowMDAwMDA3Nzc4
+ IDAwMDAwIG4gCjAwMDAwMTgzNDkgMDAwMDAgbiAKMDAwMDAxNzY1OCAwMDAwMCBuIAow
+ MDAwMDE2OTY3IDAwMDAwIG4gCjAwMDAwMTYyNzYgMDAwMDAgbiAKMDAwMDAxNTg1MyAw
+ MDAwMCBuIAowMDAwMDE0Nzg4IDAwMDAwIG4gCjAwMDAwMDU5MjkgMDAwMDAgbiAKMDAw
+ MDAwNjg5OCAwMDAwMCBuIAowMDAwMDA0ODMzIDAwMDAwIG4gCjAwMDAwMDU5MDkgMDAw
+ MDAgbiAKMDAwMDAwNjkxOCAwMDAwMCBuIAowMDAwMDA3NzU4IDAwMDAwIG4gCjAwMDAw
+ MDc4MTUgMDAwMDAgbiAKMDAwMDAwODY1NSAwMDAwMCBuIAowMDAwMDA4NzExIDAwMDAw
+ IG4gCjAwMDAwMTQ3NjcgMDAwMDAgbiAKMDAwMDAxNDgyNSAwMDAwMCBuIAowMDAwMDE1
+ NjMzIDAwMDAwIG4gCjAwMDAwMTU3NzMgMDAwMDAgbiAKMDAwMDAxNjI1NiAwMDAwMCBu
+ IAowMDAwMDE2OTQ3IDAwMDAwIG4gCjAwMDAwMTc2MzggMDAwMDAgbiAKMDAwMDAxODMy
+ OSAwMDAwMCBuIAowMDAwMDE4OTc0IDAwMDAwIG4gCjAwMDAwMTkxNTcgMDAwMDAgbiAK
+ MDAwMDAxOTA0MiAwMDAwMCBuIAowMDAwMDE5MTM1IDAwMDAwIG4gCjAwMDAwMTkyNTAg
+ MDAwMDAgbiAKMDAwMDAyNjE1MyAwMDAwMCBuIAowMDAwMDI2MTc0IDAwMDAwIG4gCjAw
+ MDAwMjYzOTkgMDAwMDAgbiAKMDAwMDAyNjc4NiAwMDAwMCBuIAowMDAwMDMyNjE0IDAw
+ MDAwIG4gCjAwMDAwMzI2MzUgMDAwMDAgbiAKMDAwMDAzMjg2NiAwMDAwMCBuIAowMDAw
+ MDMzMjA4IDAwMDAwIG4gCjAwMDAwMzMyMzUgMDAwMDAgbiAKMDAwMDAzMzI4NyAwMDAw
+ MCBuIAowMDAwMDMzMzIxIDAwMDAwIG4gCjAwMDAwMzMzNjQgMDAwMDAgbiAKdHJhaWxl
+ cgo8PCAvU2l6ZSA2MiAvUm9vdCA0MCAwIFIgL0luZm8gMSAwIFIgL0lEIFsgPDQ3NmJj
+ NzlkZDc0MDQwZDE3MjBiNTkyNTY2YzIzYWYxPgo8NDc2YmM3OWRkNzQwNDBkMTcyMGI1
+ OTI1NjZjMjNhZjE+IF0gPj4Kc3RhcnR4cmVmCjMzNTI2CiUlRU9GCjEgMCBvYmoKPDwv
+ QXV0aG9yIChLYXRpZSBNY0Nvcm1pY2spL0NyZWF0aW9uRGF0ZSAoRDoyMDExMTAxMjE4
+ MzQwMFopL0NyZWF0b3IgKE9tbmlHcmFmZmxlIFByb2Zlc3Npb25hbCA1LjIpL01vZERh
+ dGUgKEQ6MjAxMTEwMjAyMjA5MDBaKS9Qcm9kdWNlciA1OCAwIFIgL1RpdGxlIChDYWxl
+ bmRhci1kYXRhbW9kZWwtbmV3LmdyYWZmbGUpPj4KZW5kb2JqCnhyZWYKMSAxCjAwMDAw
+ MzQ5MjQgMDAwMDAgbiAKdHJhaWxlcgo8PC9JRCBbPDQ3NmJjNzlkZDc0MDQwZDE3MjBi
+ NTkyNTY2YzIzYWYxPiA8NDc2YmM3OWRkNzQwNDBkMTcyMGI1OTI1NjZjMjNhZjE+XSAv
+ SW5mbyAxIDAgUiAvUHJldiAzMzUyNiAvUm9vdCA0MCAwIFIgL1NpemUgNjI+PgpzdGFy
+ dHhyZWYKMzUxMjUKJSVFT0YK
+ </data>
+ <key>QuickLookThumbnail</key>
+ <data>
+ TU0AKgAADeKAP+BP8AQWDQeEQmFQuGQ2HQ+IRGJROKRWLReMRmNROBwSNx+QSGIPWSAB
+ 4ScAAKVSKIQOUysMTGWTOaRqOzWcTmKOKeAAET+XgKGS6DgGjACXUYA0OBAClACSPUAB
+ +qTqrVeETesVusOevUim0SFU+k0eD2Wl2em09+W0AB64Vy5TWtXO7SyvOcAPu+AB5N5o
+ ABugIOgATBUCgB8PwBz4EY0APx+gACPh4AB4gYKgAJAmCPl8wUDgsD5SDS6qB+76uN3X
+ Wa+LubZAB7bUAOFlsIAOoGAgAMJTNoADwfvoALx0BgABZ7wQPgZ5ZF/t4AOgMkQACh4M
+ sAPccGUAEMP6UB+UACH0bD1Ryxev3Q9y/EAPT6WCCU+1fej2is2uzNOpoDQEAARQK98D
+ oW10EQWgxyQcAB3wi/qPIMsj/KW9qnP3C77AABUPgAEkRQZEkFRJBCeHE3Z1HVCcNLSk
+ L+AbGYABPG0TwXE0cPccMesUfB8JbDj8xeiiVKEEskx3A8dSW2CTsu2p7AAAsqopFkWg
+ tLSMJdLQLSc90mzBMaGGrMwABXNMyTWhsxTZN8zGrNE1TfOsAKbO08oLOM5hXPU6zdP8
+ lz5NM/UFNdA0PE9CTpRUwUTR0F0ZQ1IyXSFKvfHpwqmqtMR3S9PVDUS6QzUaHnwcwAGc
+ ax+AAGQZA8yMgIKtx8H26J+ATL4IN2ABpm3VoKAe4wCgaCYAAYBJ7gAaxrKkBwFKWBQG
+ MmdB3saDIHoKBIEVabByAUAAaBlL51G+brqno0oVBaEifVMiNQXgd5pgAVhnuMDh9HaA
+ BvGzVIMBiEaUn0dIAGwdwRAAKgaMmbh4AMvxrTkAwS4UDAIgIABqHIpYOHobIAHOBDVA
+ yByCHUbMVAkFAOPmd4GOGJAQgAbJgmsvYDgTAgYBk5bfXgh15aClh+MWygEY1WjFVanw
+ CaUhFWsXjWkoad51HeAAIgsBumapqGiaFUuwvUd2zM4CQJbJMOx7W1lJ7c9Wh7inO4bo
+ 1m57umm7b0u2876kW+cArm/8Gj/BcMq/C8SisgSCWvIAAFnJxrG/GJzxfLokttWkxz2F
+ ioKgAJi5XNVJPHTJwe/VgAaXXU41XSdSmnM7idZ41abx3H8AABqEgsYIUex6novx46yn
+ +dggCQKILCngtOgoGaUFAN4j2cJwp7CEGqcjjHIfbILTGHtfL4C09QpazfKjyj7UyYah
+ B6/t+dtvsGwcx95qenf9R5yFXoIVISnh4L6H2lLA0AV+AIX5v0dq24a45X9DSHfAEf7W
+ RkiZFI1oIgRifD+OM70xo/B/PqH2kEAQDAQFvA6rxCxBQPgLd4DkEUDXtwPbWNZ8Cqh2
+ EJKMVIZoqxWtaBfCsdg1hpHdAeBcvY8jfAcAqVIco+gYgACED8FCGn6kFBEtQAAOgSGl
+ fo/V/0YwAPdf0Mcc8BofRsKdFuLT/ykQCjpHNGoEHeA9BNGKMcOGyRoAAMMccdIyxvTb
+ HWQ0BHyEFBUBJ3gPgTx8gc/Z2Y0xxHGF4N+AciJDR2IZIt4Ecz7kGBgBYggQQUyShvJR
+ 1I1RxnGHSPd38nSCPak4hiT0oZcSjISAgf5kwdSRjMfaW0Yx3j0MmPAejvADAFgCQofU
+ 0QADFGIL8AANQag6WQjQiZZgNASbBKuQswyKOcAANydBmB4jxAAA+dwAAOzxAAAuek5C
+ LR+dMS4bs+wAAQn8AAdtAZ4TyRSAAEdB0qJWnskKcdCyGUFPKY0DdE2DjYGwdkFEWWzD
+ uABRug1CD8UOgHKyhw6aTG0NsCClSRRr0tAACmmBCD4jlAAP2mxby40ipHQ2haUEVoto
+ OwOiJCKWjXpfTFIg36lAARm10CtT6dRkmLORKRt0fIFYUAerRDFms4BVV8hk5p9roA1W
+ Wpk3J7T4aIXx/VYwAAcrgsgBjMSHuIIW6tZY4K9UfYGgKGz2K1KiH9YMwU/AJ2HbQ2oi
+ Y1LGOScoROnyWEQojSPOKqbplNUJMTWUDRGLGDUscCwjBeQATROMamyz2B0WrR+kGlUK
+ yN2ftCR+pUmkPrhAvbmfNJG3IRayOu4Fk13WVI3XYi1NjJ1utzEydy2nDJiHw8UfABGY
+ gELcARqpC0gKtJ/OEg4+B3qpHcPhcIEmMgAHmO46KHm1ANaBelFo/wJKxbU8UdY6qOAI
+ A0rG85CCogAHHgFAiBq/Esq6ACr4KiWGgNCN7Bx5z0k/aAQZoyQTHGmVo0e7F3iIJBHM
+ OI6IBgJAOWQfOjo8iCAOASzsAgBX9X4IKXBrplh1m7Hsb4DwGgIlMoaNwXAmAADEH0YW
+ zpkxwjmMaCQDRjbBjoAAMwa2NQSgrZcP4BNzgE2iBOO8ZRewWglX6M1gwBx9O8BICo4w
+ wRoMxCGDhXgCwSM+ASOAYiqhyEEAiBy0QMgSY7tMv3B88TCz0AWTiotRwUk4HlotkRX0
+ RLuqGO8bgyAADIGmXodg9WdgiAUvwbg+zNgRASxoBtdB4jaRUAkDbagPgxZoNQZBlwVg
+ UayOcBrah0U0dGO60A+gXhDOWARbQMgWkFGILobZlAHGNA8DAHAAANYTTvZe7ZCGNPFH
+ mPJjQCQHMaH4Pc6I8x+mJAiAgxLTTaD7Y1iQ6I8gC4k26xrcFHL2JUhOT4BrGmr0cAIA
+ 5tQ/B5UcV1Z0BQAneToG4ACp+oQI47KtoemGiSrUmYNVU9DNFZHzabuBZYDQDJBxQ13F
+ W3h7qtVa/psCVh7DySnv5cLTi/DqVa2nb26GlDuHUPMzm3aOj2s2BauhCrApOr0OAAFy
+ wAYrZ2Vydc7Lmly4oACwbvAM9VbD0NEhslU3IoGYVt3U7CroAp2NrXDVTdYPfQFflvsB
+ sKuIPjhIrBaF6B4DoDJ3R6qtmQY00jVCgDoHOZcCgDmYgFAPycA/dwJDyMCMkdTEWuGN
+ HYOVfgGAOrhHiP55oDx6l6AKCwHrox5VGGiN2HoDgRg1AAC3aJCM/1utf0nFanu0GvPo
+ 8VBw5K+WaISqhVQ0F+D7HayFkfdwMdAnaAzEg/vJ4AHs7weg60gglA+YkcI9WXA6A9p4
+ fyxwADsSmAblbWgQmbGyNky641YoexJR2QY3RzQ9AeCL1QKALbSIR7cAHubhGUaeUc9q
+ LmwY0AOo9i6UU8wqIKKAw4ImuAxq0WOiqwSKT1ACKu64rcS8n6n+QY/4rgZcQYwCkGsq
+ omA2T/AqdOAAtqnmnq6QR24Q/6QYn0n44ax2sO+8TZBOJo/47ALg/WTArcqCSWrY7C67
+ BW0KTHByJAHZCWnUnZAkpCScwcOpAkTGv/BC92SqMSU+t4NeHnC8AA6092afAYRJCGGJ
+ DOAACDDUTq7UQgQlCDCgSZC4LmGjDqZq/OAACjD094TetkosoudCdET1D+ABDqGiAACV
+ ESrOa6PfCSIgp8FREipwVjESCUT+rcF1EyAADTE4T/CWh6FVFCAACBFIowiyuINeSaD2
+ FanYG8HWf0kUm6eiIOH6LcHmHQZCACAGY0AqA6iyFADGbVDiK4DWFGayHcHqMnFiIYHe
+ HItAHuHgycA0BYOwLUfOISAYAOKEE2DCsULsH8KaDIE+o4IA8He8AA9HW3gABgWEAADQ
+ qIQBEYkAADEn/EwA/4vFIrGI1ERQGQKAEAUAfGInGo/KAAVUi7AA63m/YlHY7HovG4pO
+ 5zO4jOn8+nrEQCAwAAwMCQAvj0FQAAgDN5ZU6pVamQ0M6gA/X9OptLI/Xp5GZ9RI7YZr
+ UQAwD2Fqtb7hVH5XQARKzNQA+3xBAIBwbHAFZKJY4vUrVGZ7ZoqGwhgVKawpVJVOowUU
+ PWpk/pRlLxLJvG7FnY/UYqwUJbgFULjq9YPz26K3nJ/nqnn9ng9FhbUw0MF9Zv7e/H7F
+ yAfXTm9pycFodxo7UGwngVQc6dU8nUyeg+O63jFweFKMFnzmqHEXM881KMCMRBEWe4dB
+ srLF2IigxT9VwP1LB6dnOrYFpGKQSIiXpnn2AB4rKiINr+ABynmiQDsWAKLnKfD5NsYx
+ GAy/cPIm4SLh8O7jtIAANAZC0IoxBqIwglKzJ/DKLAADgKAIABVDw6qwJUqYmD02B1He
+ zQ9jspwOnWfQAHkjYOA0ipunYi55njHAjBaip4nTJZ7gawJ3AIoxkkkdwAFK7oAGQSkO
+ tSqUPv0HI2HMAAYCOCIAEOHCInEfqjHMbrNBeDSaGQcjAhwECaGueijAYBKjAAcZ8AAd
+ QHgOp5jnekhos0ZRLA1OEPxCAAdDY/6KRwNwuL+IYPoifSNmwbJ+AAEoYUwAJ5SWYpzo
+ qEAGRwDwGIidJoQUNZeVqDrwAAVpBN860fJYJQ6v+dZ4IuDgHo7L4AAWtQOAOzRmpgAC
+ usCG4QIqe53o2AzNUowJ0G5Wpxo+ZRNVDN1RQ8HAznKhoHRwDB/s0BAKqMdkpgADAHIu
+ dJ8IqD4HLSgp8oidh0wQAALpGBh1Vqa57ouZhOA3fr91IHI0P+lYOguowQgewIDYMABy
+ HmioKwcfB9s0dACsCCsMW+AyInwerNGWdDNA8C8cFcQtox6laUCNU9KnczTbRm275s6j
+ ydoqnpnFJlF+ZS4AaC7gLhNwsmvMFsG4RgiuyLIaBTA5tTgVJtk6a65TmOZuzCAADwMR
+ wWRHPvaWrIwIozTodMiM2jbDv3wnMIqaBU7Q/O+tWGQrnGAC5zexEYw9zcYmkVe+dE1d
+ SBkLGApx1fNbCla1A/xQAFmSfHaq+XZeN4/keT5Xl+Y36AgADwEAAAMAAAABAEoAAAEB
+ AAMAAAABAEwAAAECAAMAAAAEAAAOnAEDAAMAAAABAAUAAAEGAAMAAAABAAIAAAERAAQA
+ AAABAAAACAESAAMAAAABAAEAAAEVAAMAAAABAAQAAAEWAAMAAAABAEwAAAEXAAQAAAAB
+ AAAN2gEcAAMAAAABAAEAAAE9AAMAAAABAAIAAAFSAAMAAAABAAEAAAFTAAMAAAAEAAAO
+ pIdzAAcAABnsAAAOrAAAAAAACAAIAAgACAABAAEAAQABAAAZ7GFwcGwCEAAAbW50clJH
+ QiBYWVogB9sACAABAA0AFQAyYWNzcEFQUEwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ APbWAAEAAAAA0y1hcHBsAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAARZGVzYwAAAVAAAABiZHNjbQAAAbQAAAJCY3BydAAAA/gAAADQd3Rw
+ dAAABMgAAAAUclhZWgAABNwAAAAUZ1hZWgAABPAAAAAUYlhZWgAABQQAAAAUclRSQwAA
+ BRgAAAgMYWFyZwAADSQAAAAgdmNndAAADUQAAAYSbmRpbgAAE1gAAAY+Y2hhZAAAGZgA
+ AAAsbW1vZAAAGcQAAAAoYlRSQwAABRgAAAgMZ1RSQwAABRgAAAgMYWFiZwAADSQAAAAg
+ YWFnZwAADSQAAAAgZGVzYwAAAAAAAAAIRGlzcGxheQAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAG1sdWMAAAAAAAAAEgAAAAxubE5MAAAAFgAAAOhkYURLAAAAHAAAAP5w
+ bFBMAAAAEgAAARplblVTAAAAEgAAASxuYk5PAAAAEgAAAT5mckZSAAAAFgAAAVBwdEJS
+ AAAAGAAAAWZwdFBUAAAAFgAAAX56aENOAAAADAAAAZRlc0VTAAAAEgAAAaBqYUpQAAAA
+ DgAAAbJydVJVAAAAJAAAAcBzdlNFAAAAEAAAAeR6aFRXAAAADgAAAfRkZURFAAAAEAAA
+ AgJmaUZJAAAAEAAAAhJpdElUAAAAFAAAAiJrb0tSAAAADAAAAjYASwBsAGUAdQByAGUA
+ bgAtAEwAQwBEAEwAQwBEAC0AZgBhAHIAdgBlAHMAawDmAHIAbQBLAG8AbABvAHIAIABM
+ AEMARABDAG8AbABvAHIAIABMAEMARABGAGEAcgBnAGUALQBMAEMARABMAEMARAAgAGMA
+ bwB1AGwAZQB1AHIATABDAEQAIABDAG8AbABvAHIAaQBkAG8ATABDAEQAIABhACAAQwBv
+ AHIAZQBzX2mCcgAgAEwAQwBEAEwAQwBEACAAYwBvAGwAbwByMKsw6TD8ACAATABDAEQE
+ JgQyBDUEQgQ9BD4EOQAgBBYEGgAtBDQEOARBBD8EOwQ1BDkARgDkAHIAZwAtAEwAQwBE
+ X2mCcm2yZnaYb3k6VmgARgBhAHIAYgAtAEwAQwBEAFYA5AByAGkALQBMAEMARABMAEMA
+ RAAgAGMAbwBsAG8AcgBpzuy37AAgAEwAQwBEAAB0ZXh0AAAAAENvcHlyaWdodCBBcHBs
+ ZSwgSW5jLiwgMjAxMQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAWFlaIAAAAAAAAPNSAAEAAAAB
+ Fs9YWVogAAAAAAAAba8AADhpAAABXlhZWiAAAAAAAABikAAAui0AAAarWFlaIAAAAAAA
+ ACaWAAANagAAyyRjdXJ2AAAAAAAABAAAAAAFAAoADwAUABkAHgAjACgALQAyADYAOwBA
+ AEUASgBPAFQAWQBeAGMAaABtAHIAdwB8AIEAhgCLAJAAlQCaAJ8AowCoAK0AsgC3ALwA
+ wQDGAMsA0ADVANsA4ADlAOsA8AD2APsBAQEHAQ0BEwEZAR8BJQErATIBOAE+AUUBTAFS
+ AVkBYAFnAW4BdQF8AYMBiwGSAZoBoQGpAbEBuQHBAckB0QHZAeEB6QHyAfoCAwIMAhQC
+ HQImAi8COAJBAksCVAJdAmcCcQJ6AoQCjgKYAqICrAK2AsECywLVAuAC6wL1AwADCwMW
+ AyEDLQM4A0MDTwNaA2YDcgN+A4oDlgOiA64DugPHA9MD4APsA/kEBgQTBCAELQQ7BEgE
+ VQRjBHEEfgSMBJoEqAS2BMQE0wThBPAE/gUNBRwFKwU6BUkFWAVnBXcFhgWWBaYFtQXF
+ BdUF5QX2BgYGFgYnBjcGSAZZBmoGewaMBp0GrwbABtEG4wb1BwcHGQcrBz0HTwdhB3QH
+ hgeZB6wHvwfSB+UH+AgLCB8IMghGCFoIbgiCCJYIqgi+CNII5wj7CRAJJQk6CU8JZAl5
+ CY8JpAm6Cc8J5Qn7ChEKJwo9ClQKagqBCpgKrgrFCtwK8wsLCyILOQtRC2kLgAuYC7AL
+ yAvhC/kMEgwqDEMMXAx1DI4MpwzADNkM8w0NDSYNQA1aDXQNjg2pDcMN3g34DhMOLg5J
+ DmQOfw6bDrYO0g7uDwkPJQ9BD14Peg+WD7MPzw/sEAkQJhBDEGEQfhCbELkQ1xD1ERMR
+ MRFPEW0RjBGqEckR6BIHEiYSRRJkEoQSoxLDEuMTAxMjE0MTYxODE6QTxRPlFAYUJxRJ
+ FGoUixStFM4U8BUSFTQVVhV4FZsVvRXgFgMWJhZJFmwWjxayFtYW+hcdF0EXZReJF64X
+ 0hf3GBsYQBhlGIoYrxjVGPoZIBlFGWsZkRm3Gd0aBBoqGlEadxqeGsUa7BsUGzsbYxuK
+ G7Ib2hwCHCocUhx7HKMczBz1HR4dRx1wHZkdwx3sHhYeQB5qHpQevh7pHxMfPh9pH5Qf
+ vx/qIBUgQSBsIJggxCDwIRwhSCF1IaEhziH7IiciVSKCIq8i3SMKIzgjZiOUI8Ij8CQf
+ JE0kfCSrJNolCSU4JWgllyXHJfcmJyZXJocmtyboJxgnSSd6J6sn3CgNKD8ocSiiKNQp
+ Bik4KWspnSnQKgIqNSpoKpsqzysCKzYraSudK9EsBSw5LG4soizXLQwtQS12Last4S4W
+ Lkwugi63Lu4vJC9aL5Evxy/+MDUwbDCkMNsxEjFKMYIxujHyMioyYzKbMtQzDTNGM38z
+ uDPxNCs0ZTSeNNg1EzVNNYc1wjX9Njc2cjauNuk3JDdgN5w31zgUOFA4jDjIOQU5Qjl/
+ Obw5+To2OnQ6sjrvOy07azuqO+g8JzxlPKQ84z0iPWE9oT3gPiA+YD6gPuA/IT9hP6I/
+ 4kAjQGRApkDnQSlBakGsQe5CMEJyQrVC90M6Q31DwEQDREdEikTORRJFVUWaRd5GIkZn
+ RqtG8Ec1R3tHwEgFSEtIkUjXSR1JY0mpSfBKN0p9SsRLDEtTS5pL4kwqTHJMuk0CTUpN
+ k03cTiVObk63TwBPSU+TT91QJ1BxULtRBlFQUZtR5lIxUnxSx1MTU19TqlP2VEJUj1Tb
+ VShVdVXCVg9WXFapVvdXRFeSV+BYL1h9WMtZGllpWbhaB1pWWqZa9VtFW5Vb5Vw1XIZc
+ 1l0nXXhdyV4aXmxevV8PX2Ffs2AFYFdgqmD8YU9homH1YklinGLwY0Njl2PrZEBklGTp
+ ZT1lkmXnZj1mkmboZz1nk2fpaD9olmjsaUNpmmnxakhqn2r3a09rp2v/bFdsr20IbWBt
+ uW4SbmtuxG8eb3hv0XArcIZw4HE6cZVx8HJLcqZzAXNdc7h0FHRwdMx1KHWFdeF2Pnab
+ dvh3VnezeBF4bnjMeSp5iXnnekZ6pXsEe2N7wnwhfIF84X1BfaF+AX5ifsJ/I3+Ef+WA
+ R4CogQqBa4HNgjCCkoL0g1eDuoQdhICE44VHhauGDoZyhteHO4efiASIaYjOiTOJmYn+
+ imSKyoswi5aL/IxjjMqNMY2Yjf+OZo7OjzaPnpAGkG6Q1pE/kaiSEZJ6kuOTTZO2lCCU
+ ipT0lV+VyZY0lp+XCpd1l+CYTJi4mSSZkJn8mmia1ZtCm6+cHJyJnPedZJ3SnkCerp8d
+ n4uf+qBpoNihR6G2oiailqMGo3aj5qRWpMelOKWpphqmi6b9p26n4KhSqMSpN6mpqhyq
+ j6sCq3Wr6axcrNCtRK24ri2uoa8Wr4uwALB1sOqxYLHWskuywrM4s660JbSctRO1irYB
+ tnm28Ldot+C4WbjRuUq5wro7urW7LrunvCG8m70VvY++Cr6Evv+/er/1wHDA7MFnwePC
+ X8Lbw1jD1MRRxM7FS8XIxkbGw8dBx7/IPci8yTrJuco4yrfLNsu2zDXMtc01zbXONs62
+ zzfPuNA50LrRPNG+0j/SwdNE08bUSdTL1U7V0dZV1tjXXNfg2GTY6Nls2fHadtr724Dc
+ BdyK3RDdlt4c3qLfKd+v4DbgveFE4cziU+Lb42Pj6+Rz5PzlhOYN5pbnH+ep6DLovOlG
+ 6dDqW+rl63Dr++yG7RHtnO4o7rTvQO/M8Fjw5fFy8f/yjPMZ86f0NPTC9VD13vZt9vv3
+ ivgZ+Kj5OPnH+lf65/t3/Af8mP0p/br+S/7c/23//3BhcmEAAAAAAAMAAAACZmYAAPKn
+ AAANWQAAE9AAAAoOdmNndAAAAAAAAAAAAAMBAAACAAAAVgEuAesCnQNeBCUE6gXABpgH
+ cAhSCUUKNgsvDC4NKw44D0sQYBF1EpUTuRThFgwXQRhyGa0a6xwpHWoesB/4IUQikCPi
+ JTEmhyfdKTUqkCvsLUUuoy/+MVwyujQaNXg21TgzOY467DxHPaA++kBSQaVC+URLRZpG
+ 6Eg0SXtKvkwBTUBOek+wUONSEVM9VGRVhVagV7NYv1nDWsBbuVyvXaZenF+QYIJhcWJe
+ Y0xkN2UiZg1m92fhaMppsmqaa4JsaW1QbjVvF2/3cNNxq3J/c090H3Tvdb52jndceCt4
+ +nnKepp7aXw4fQZ9036ff2yAQoEkghSDD4QQhRGGEIcNiAmJBIn/ivmL8ozrjeKO2o/S
+ kMuRwpK5k66Uo5WZlo6Xg5h7mXmagpuYnLWd0J7in+yg8KHwovCj76Tupe2m66foqOSp
+ 4arjq/GtEa5Dr36wt7Hfsvi0B7UTth+3Krg1uT+6SbtTvGK9eL6Yv8HA6MIEwxPEGsUg
+ xirHN8hCyULKKMrvy4rMGcyhzT/N7M6tz3LQOdEB0c3SntNx1EXVGdXu1sPXl9ho2TbZ
+ /9rA23rcM9zs3a3ec9884Abg0uGc4mbjMeP75MbllOZl5zroEujq6b7qjOtX7CHs6e2x
+ 7nrvQvAL8NXxrfKe87T09/Zm99r5QPqU++D9M/6U//8AAABWASMBsAJZAxIDyASGBUsG
+ FQbdB7MIjAlsClULRAwzDSkOJQ8oEC8RNRJGE1YUbhWEFqMXxBjrGhEbPhxpHZoezB//
+ ITgidCOuJOomKydoKKgp6ystLHIttS75MD8xgTLHNAs1TDaON9E5EzpQO448yj4GPz9A
+ dkGoQttEC0U6RmJHiUirSctK6UwCTRdOJ08zUDpROlIzUyRUDlT1VdpWwFekWIpZblpT
+ WzdcG1z/XeJexF+mYIZhZGJAYxxj92TRZatmhWdeaDdpEGnoar9rl2xubUVuGm7tb79w
+ jnFaciJy6XOwdHd1OnX9dr53f3hAeQR5yHqNe1B8E3zVfZd+W38jf/CAw4GfgoODboRa
+ hUeGNIchiAyI94niisyLtoygjYiOco9dkEyRP5I1ky6UKJUilhyXF5gRmQqaBJr8m/Sc
+ 653gntef0aDQodWi36PrpPimA6cOqBmpJKowqzysRq1PrlmvZbB2sYyyqLPEtN618bcB
+ uBC5Ibozu0a8W71wvoa/m8Cpwa3CpMOQxHTFVMYyxxHH8cjUybnKn8uFzGvNUc44zyHQ
+ C9D40ePSzdOy1JfVfdZj10vYNNkd2gXa7NvU3Lvdo96N33zgcOFr4m3jdOR95Ybmkeeb
+ 6KXpsOq668Psze3b7vjwOfGk80L1C/b0+Oj60vyi/ln//wAAAFYBHAGNAigCywNtBBsE
+ ywWCBj4G+Ae9CIcJWQozCw4L6AzJDbMOng+NEIMRehJ2E3kUeRV9FoYXjxidGa8axBvY
+ HO4eDR8kIEIhYCKDI6MkxSXpJw4oMSlVKnsrnyzELekvETA3MVoyezOeNL813jb+OBs5
+ OTpSO2k8fj2RPqM/sUC8QcVCykPMRMtFx0a/R7NIokmKSm5LS0wgTPRNxk6XT2lQOVEH
+ UdZSpVNzVEBVDFXXVqRXcFg7WQZZ0FqaW2VcLlz2Xb5ehl9OYBNg12GaYl5jH2PgZKBl
+ YGYfZt9noGhgaR9p3mqda1lsE2zObYluRW8Bb7twdHEncdhyiHM3c+d0lnVEdfJ2oHdO
+ d/t4qXlWegJ6r3tbfAV8sH1bfgV+sH9egBSA0YGWgmWDOIQOhOWFvYaUh2uIQYkXie2K
+ wYuUjGaNN44KjuCPuJCSkXKSU5M1lBmU/pXklsqXr5iTmXaaWZs6nBqc953VnrWfm6CN
+ oYaihKOFpIelh6aFp32obalYqkWrO6w9rUuuYa98sJixtLLNs+W0+7YRtya4PLlRume7
+ fryVvaq+vL/HwMrBycLFw8HEvcW4xrPHrcinyZ/KmcuSzIzNhs6Dz4XQkdGo0snT8dUd
+ 1knXdtii2c7a+dwk3VPej9/g4WnjGOT15wXpfuzD8ZP4JP//AABuZGluAAAAAAAABjYA
+ AKZFAABWgAAAUf8AAKhRAAAllAAADLkAAFANAABUOQACa4UAAhHrAAGcKAADAQAAAgAA
+ AAEABAAJABAAGQAjAC8APQBLAFsAbAB+AJIApgC7ANEA6QEBARoBNAFPAWsBhwGlAcMB
+ 4gICAiMCRQJnAosCrwLUAvoDIQNIA3EDmgPEA+8EGwRHBHUEowTTBQMFNAVnBZoFzgYD
+ BjkGcAaoBuIHHAdYB5QH0ggRCFEIkwjVCRkJXwmmCe4KOAqDCtALHgtuC8AMFAxqDMEN
+ Gw13DdUONg6ZDv8PZw/SEEEQsxEqEaYSJxKvEzsTzBRfFPQVjRYqFssXcBgXGMMZcRoi
+ GtYbjRxIHQYdxh6KH1EgHCDtIcQioyOLJHolbSZkJ18oXilgKmUrbSx5LYkuni+6MNcx
+ 6jLuM+Q01DXDNrY3rjiqOak6qjuwPLg9xD7TP+VA+UIPQylERkVnRotHsUjbSgdLMkxX
+ TXJOg0+PUJ5Rt1LbVAlVPlZ3V7NY8lo0W3hcwV4NX1xgqWHsYx1kP2VXZm1niGiyae1r
+ N2yJbd9vNnCQce5zT3SydhV3dHjKehd7Xnyoff9/aIDhgmGD34VZhtWIWYn8i+iOjpGd
+ lBqWSphwmpicuJ7OoOGi9qUOpympS6t4rbqwHrKitSu3nrn/vFy+u8Egw4rF+choytPN
+ NM+L0ePUTdbO2WDb+d6X4Tjj3+aE6PvrIuz+7qTwJPGf8xn0ovY+9+f5mPtC/N7+cv//
+ AAAAAQAFAAsAEwAdACkANwBGAFcAaQB8AJEApwC+ANYA7wEKASUBQgFfAX4BngG+AeAC
+ AgImAkoCcAKWAr4C5gMQAzoDZQORA78D7QQcBE0EfgSxBOQFGQVOBYUFvQX2BjAGbAao
+ BuYHJQdmB6gH6wgvCHUIvQkGCVAJnQnqCjoKiwrfCzQLiwvkDD8MnQz9DWANxQ4tDpcP
+ BQ92D+sQYxDgEWIR6hJ5Ew8TqhRHFOgVixYxFtoXhhg0GOYZmxpUGxAb0hyYHWIeLx8A
+ H9UgrSGJImcjSiQxJRsmCCb7J/Qo9Cn8Kw0sIy0+LmAviTC5MeozHDRQNYs2zDgROVc6
+ mTvTPQE+Jj9GQGZBiEKtQ9VFAkYyR2ZInUnXSxZMVk2WTtNQDlFHUn9TulT3VjZXeFi9
+ WgVbUFyfXfJfSmCkYf1jUWSgZepnM2h9actrHWxxbcZvHXB2cdNzNHSXdfx3X3i+ehh7
+ bnzGfiN/ioD4gmqD3YVQhsOIN4mtiyKMmo4Xj5+ROpLtlLiWl5iCmnGcX55KoDSiH6QO
+ pf+n8qnmq9ityK+8sbmzwbXPt92567v5vgrAIMI6xFjGecibyrrM0M7b0NjSzNS81qzY
+ ndqR3Ifef+B54nfkeOZ76HjqXewW7abvF/Bp8aPy1fP39Rf2M/dQ+HP5mfrN/Af9Uf6k
+ //8AAAABAAYADQAXACMAMQBCAFQAaAB9AJQArQDHAOIA/wEdATwBXQF+AaEBxgHrAhIC
+ OgJjAo0CuALlAxMDQQNyA6MD1gQJBD4EdQSsBOUFHwVbBZgF1gYWBlcGmgbeByMHagez
+ B/4ISgiYCOgJOgmNCeMKOgqUCvALTwuwDBMMeQziDU4NvQ4wDqUPHw+cEB4QpBExEcQS
+ XxMCE6oUVxUHFbsWdBcwF/AYtBl9GkkbGBvsHMQdoB5/H2MgTCE5IiojISQfJSEmKSc2
+ KEkpXyp5K5csui3iLxIwSjGGMsM0BTVRNq04Ezl/OvE8aT3oP2xA9kKGRBxFukdfSQtK
+ vExpTgVPi1EAUm9T3VVOVsJYO1m4WzlcwF5OX+FheGMPZKNmNGfAaUtq12xjbfFvgXEV
+ cq90TXXwd5l5SnsBfLh+Y3/+gY6DGISihi2HvYlUiviMro5ukCqR05NqlPOWdZf1mXea
+ /JyGnhSfpqE7otOkbaYKp6ipSKrprIyuNK/ksaGzbLVEtyK5BLrpvNG+vcCtwqLEmsaU
+ yJHKj8yPzovQfdJe1DDV9dey2W3bKdzm3qXgZuIq4/HlvOeF6UTq8eyI7fLvSfCM8bfy
+ 3fPs9Pn14/bJ95L4PPjm+YT5+fpu+uP7WPu//BT8afy+/RT9af2+/gj+UP6Y/t//J/9v
+ /7f//wAAc2YzMgAAAAAAAQxCAAAF3v//8yYAAAeSAAD9kf//+6L///2jAAAD3AAAwGxt
+ bW9kAAAAAAAABhAAAJy7AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ </data>
+ <key>ReadOnly</key>
+ <string>NO</string>
+ <key>RowAlign</key>
+ <integer>1</integer>
+ <key>RowSpacing</key>
+ <real>36</real>
+ <key>SheetTitle</key>
+ <string>Canvas 1</string>
+ <key>SmartAlignmentGuidesActive</key>
+ <string>YES</string>
+ <key>SmartDistanceGuidesActive</key>
+ <string>YES</string>
+ <key>UniqueID</key>
+ <integer>1</integer>
+ <key>UseEntirePage</key>
+ <false/>
+ <key>VPages</key>
+ <integer>1</integer>
+ <key>WindowInfo</key>
+ <dict>
+ <key>CurrentSheet</key>
+ <integer>0</integer>
+ <key>ExpandedCanvases</key>
+ <array>
+ <dict>
+ <key>name</key>
+ <string>Canvas 1</string>
+ </dict>
+ </array>
+ <key>Frame</key>
+ <string>{{34, 76}, {710, 887}}</string>
+ <key>ListView</key>
+ <true/>
+ <key>OutlineWidth</key>
+ <integer>142</integer>
+ <key>RightSidebar</key>
+ <false/>
+ <key>ShowRuler</key>
+ <true/>
+ <key>Sidebar</key>
+ <true/>
+ <key>SidebarWidth</key>
+ <integer>120</integer>
+ <key>VisibleRegion</key>
+ <string>{{0, 0}, {575, 733}}</string>
+ <key>Zoom</key>
+ <real>1</real>
+ <key>ZoomValues</key>
+ <array>
+ <array>
+ <string>Canvas 1</string>
+ <real>1</real>
+ <real>1</real>
+ </array>
+ </array>
+ </dict>
+ <key>saveQuickLookFiles</key>
+ <string>YES</string>
+</dict>
+</plist>
diff --git a/docs/html/images/providers/datamodel.png b/docs/html/images/providers/datamodel.png
new file mode 100644
index 0000000..a14c328
--- /dev/null
+++ b/docs/html/images/providers/datamodel.png
Binary files differ
diff --git a/docs/html/sdk/ndk/index.jd b/docs/html/sdk/ndk/index.jd
index f87e1f6..afbad57 100644
--- a/docs/html/sdk/ndk/index.jd
+++ b/docs/html/sdk/ndk/index.jd
@@ -1,18 +1,19 @@
ndk=true
-ndk.win_download=android-ndk-r6b-windows.zip
-ndk.win_bytes=67670219
-ndk.win_checksum=f496b48fffb6d341303de170a081b812
+ndk.win_download=android-ndk-r7-windows.zip
+ndk.win_bytes=81270552
+ndk.win_checksum=55483482cf2b75e8dd1a5d9a7caeb6e5
-ndk.mac_download=android-ndk-r6b-darwin-x86.tar.bz2
-ndk.mac_bytes=52798843
-ndk.mac_checksum=65f2589ac1b08aabe3183f9ed1a8ce8e
+ndk.mac_download=android-ndk-r7-darwin-x86.tar.bz2
+ndk.mac_bytes=71262092
+ndk.mac_checksum=817ca5675a1dd44078098e43070f19b6
-ndk.linux_download=android-ndk-r6b-linux-x86.tar.bz2
-ndk.linux_bytes=46532436
-ndk.linux_checksum=309f35e49b64313cfb20ac428df4cec2
+ndk.linux_download=android-ndk-r7-linux-x86.tar.bz2
+ndk.linux_bytes=64884365
+ndk.linux_checksum=bf15e6b47bf50824c4b96849bf003ca3
page.title=Android NDK
+
@jd:body
<h2 id="notes">Revisions</h2>
@@ -61,6 +62,310 @@
<div class="toggleable open">
<a href="#" onclick="return toggleDiv(this)"><img src=
"{@docRoot}assets/images/triangle-opened.png" class="toggle-img" height="9px" width="9px">
+ Android NDK, Revision 7</a> <em>(November 2011)</em>
+
+ <div class="toggleme">
+ <p>This release of the NDK includes new features to support the Android 4.0 platform as well
+ as many other additions and improvements:</p>
+
+ <dl>
+ <dt>New features</dt>
+
+ <dd>
+ <ul>
+ <li>Added official NDK APIs for Android 4.0 (API level 14), which adds the following
+ native features to the platform:
+
+ <ul>
+ <li>Added native multimedia API based on the Khronos Group OpenMAX AL™ 1.0.1
+ standard. The new <code><OMXAL/OpenMAXAL.h></code> and
+ <code><OMXAL/OpenMAXAL_Android.h></code> headers allow applications targeting
+ API level 14 to perform multimedia output directly from native code by using a new
+ Android-specific buffer queue interface. For more details, see
+ <code>docs/openmaxal/index.html</code> and <a href=
+ "http://www.khronos.org/openmax/">http://www.khronos.org/openmax/</a>.</li>
+
+ <li>Updated the native audio API based on the Khronos Group OpenSL ES 1.0.1™
+ standard. With API Level 14, you can now decode compressed audio (e.g. MP3, AAC,
+ Vorbis) to PCM. For more details, see <code>docs/opensles/index.html</code> and
+ <a href=
+ "http://www.khronos.org/opensles">http://www.khronos.org/opensles/</a>.</li>
+ </ul>
+ </li>
+
+ <li>Added CCache support. To speed up large rebuilds, define the
+ <code>NDK_CCACHE</code> environment variable to <code>ccache</code> (or the path to
+ your <code>ccache</code> binary). When declared, the NDK build system automatically
+ uses CCache when compiling any source file. For example:
+ <pre>
+export NDK_CCACHE=ccache
+</pre>
+ <p class="note"><strong>Note:</strong> CCache is not included in the NDK release
+ so you must have it installed prior to using it. For more information about CCache, see
+ <a href="http://ccache.samba.org">http://ccache.samba.org</a>.</p>
+ </li>
+
+ <li>Added support for setting <code>APP_ABI</code> to <code>all</code> to indicate that
+ you want to build your NDK modules for all the ABIs supported by your given NDK
+ release. This means that either one of the following two lines in your
+ <code>Application.mk</code> are equivalent with this release:
+ <pre>
+APP_ABI := all
+APP_ABI := armeabi armeabi-v7a x86
+</pre>
+
+ <p>This also works if you define <code>APP_ABI</code> when calling
+ <code>ndk-build</code> from the command-line, which is a quick way to check that your
+ project builds for all supported ABIs without changing the project's
+ <code>Application.mk file</code>. For example:</p>
+ <pre>
+ndk-build APP_ABI=all
+</pre>
+ </li>
+
+ <li>Added a <code>LOCAL_CPP_FEATURES</code> variable in <code>Android.mk</code> that
+ allows you to declare which C++ features (RTTI or Exceptions) your module uses. This
+ ensures that the final linking works correctly if you have prebuilt modules that depend
+ on these features. See <code>docs/ANDROID-MK.html</code> and
+ <code>docs/CPLUSPLUS-SUPPORT.html</code> for more details.</li>
+
+ <li>Shortened paths to source and object files that are used in build commands. When
+ invoking <code>$NDK/ndk-build</code> from your project path, the paths to the source,
+ object, and binary files that are passed to the build commands are significantly
+ shorter now, because they are passed relative to the current directory. This is useful
+ when building projects with a lot of source files, to avoid limits on the maximum
+ command line length supported by your host operating system. The behavior is unchanged
+ if you invoke <code>ndk-build</code> from a sub-directory of your project tree, or if
+ you define <code>NDK_PROJECT_PATH</code> to point to a specific directory.</li>
+ </ul>
+ </dd>
+
+ <dt>Experimental features</dt>
+
+ <dd>
+ You can now build your NDK source files on Windows <em>without</em> Cygwin by calling the
+ <code>ndk-build.cmd</code> script from the command line from your project path. The
+ script takes exactly the same arguments as the original <code>ndk-build</code> script.
+ The Windows NDK package comes with its own prebuilt binaries for GNU Make, Awk and other
+ tools required by the build. You should not need to install anything else to get a
+ working build system.
+
+ <p class="caution"><strong>Important:</strong> <code>ndk-gdb</code> does not work on
+ Windows, so you still need Cygwin to debug.</p>
+
+ <p>This feature is still experimental, so feel free to try it and report issues on the
+ <a href="http://b.android.com">public bug database</a> or <a href=
+ "http://groups.google.com/group/android-ndk">public forum</a>. All samples and unit tests
+ shipped with the NDK succesfully compile with this feature.</p>
+ </dd>
+
+ <dt>Important bug fixes</dt>
+
+ <dd>
+ <ul>
+ <li>Imported shared libraries are now installed by default to the target installation
+ location (<code>libs/<abi></code>) if <code>APP_MODULES</code> is not defined in
+ your <code>Application.mk</code>. For example, if a top-level module <code>foo</code>
+ imports a module <code>bar</code>, then both <code>libfoo.so</code> and
+ <code>libbar.so</code> are copied to the install location. Previously, only
+ <code>libfoo.so</code> was copied, unless you listed <code>bar</code> in your
+ <code>APP_MODULES</code> too. If you define <code>APP_MODULES</code> explicitly, the
+ behavior is unchanged.</li>
+
+ <li><code>ndk-gdb</code> now works correctly for activities with multiple categories in
+ their MAIN intent filters.</li>
+
+ <li>Static library imports are now properly transitive. For example, if a top-level
+ module <code>foo</code> imports static library <code>bar</code> that imports static
+ library <code>zoo</code>, the <code>libfoo.so</code> will now be linked against both
+ <code>libbar.a</code> and <code>libzoo.a</code>.</li>
+ </ul>
+ </dd>
+
+ <dt>Other changes</dt>
+
+ <dd>
+ <ul>
+ <li><code>docs/NATIVE-ACTIVITY.HTML</code>: Fixed typo. The minimum API level should be
+ 9, not 8 for native activities.</li>
+
+ <li><code>docs/STABLE-APIS.html</code>: Added missing documentation listing EGL as a
+ supported stable API, starting from API level 9.</li>
+
+ <li><code>download-toolchain-sources.sh</code>: Updated to download the toolchain
+ sources from <a href="http://android.googlesource.com">android.googlesource.com</a>,
+ which is the new location for the AOSP servers.</li>
+
+ <li>Added a new C++ support runtime named <code>gabi++</code>. More details about it
+ are available in the updated <code>docs/CPLUSPLUS-SUPPORT.html</code>.</li>
+
+ <li>Added a new C++ support runtime named <code>gnustl_shared</code> that corresponds
+ to the shared library version of GNU libstdc++ v3 (GPLv3 license). See more info at
+ <code>docs/CPLUSPLUS-SUPPORT.html</code></li>
+
+ <li>Added support for RTTI in the STLport C++ runtimes (no support for
+ exceptions).</li>
+
+ <li>Added support for multiple file extensions in <code>LOCAL_CPP_EXTENSION</code>. For
+ example, to compile both <code>foo.cpp</code> and <code>bar.cxx</code> as C++ sources,
+ declare the following:
+ <pre>
+LOCAL_CPP_EXTENSION := .cpp .cxx
+</pre>
+ </li>
+
+ <li>Removed many unwanted exported symbols from the link-time shared system libraries
+ provided by the NDK. This ensures that code generated with the standalone toolchain
+ doesn't risk to accidentally depend on a non-stable ABI symbol (e.g. any libgcc.a
+ symbol that changes each time the toolchain used to build the platform is changed)</li>
+
+ <li>Refreshed the EGL and OpenGLES Khronos headers to support more extensions. Note
+ that this does <em>not</em> change the NDK ABIs for the corresponding libraries,
+ because each extension must be probed at runtime by the client application.
+
+ <p>The extensions that are available depend on your actual device and GPU drivers,
+ not the platform version the device runs on. The header changes simply add new
+ constants and types to make it easier to use the extensions when they have been
+ probed with <code>eglGetProcAddress()</code> or <code>glGetProcAddress()</code>. The
+ following list describes the newly supported extensions:</p>
+
+ <dl>
+ <dt>GLES 1.x</dt>
+
+ <dd>
+ <ul>
+ <li><code>GL_OES_vertex_array_object</code></li>
+
+ <li><code>GL_OES_EGL_image_external</code></li>
+
+ <li><code>GL_APPLE_texture_2D_limited_npot</code></li>
+
+ <li><code>GL_EXT_blend_minmax</code></li>
+
+ <li><code>GL_EXT_discard_framebuffer</code></li>
+
+ <li><code>GL_EXT_multi_draw_arrays</code></li>
+
+ <li><code>GL_EXT_read_format_bgra</code></li>
+
+ <li><code>GL_EXT_texture_filter_anisotropic</code></li>
+
+ <li><code>GL_EXT_texture_format_BGRA8888</code></li>
+
+ <li><code>GL_EXT_texture_lod_bias</code></li>
+
+ <li><code>GL_IMG_read_format</code></li>
+
+ <li><code>GL_IMG_texture_compression_pvrtc</code></li>
+
+ <li><code>GL_IMG_texture_env_enhanced_fixed_function</code></li>
+
+ <li><code>GL_IMG_user_clip_plane</code></li>
+
+ <li><code>GL_IMG_multisampled_render_to_texture</code></li>
+
+ <li><code>GL_NV_fence</code></li>
+
+ <li><code>GL_QCOM_driver_control</code></li>
+
+ <li><code>GL_QCOM_extended_get</code></li>
+
+ <li><code>GL_QCOM_extended_get2</code></li>
+
+ <li><code>GL_QCOM_perfmon_global_mode</code></li>
+
+ <li><code>GL_QCOM_writeonly_rendering</code></li>
+
+ <li><code>GL_QCOM_tiled_rendering</code></li>
+ </ul>
+ </dd>
+
+ <dt>GLES 2.0</dt>
+
+ <dd>
+ <ul>
+ <li><code>GL_OES_element_index_uint</code></li>
+
+ <li><code>GL_OES_get_program_binary</code></li>
+
+ <li><code>GL_OES_mapbuffer</code></li>
+
+ <li><code>GL_OES_packed_depth_stencil</code></li>
+
+ <li><code>GL_OES_texture_3D</code></li>
+
+ <li><code>GL_OES_texture_float</code></li>
+
+ <li><code>GL_OES_texture_float_linear</code></li>
+
+ <li><code>GL_OES_texture_half_float_linear</code></li>
+
+ <li><code>GL_OES_texture_npot</code></li>
+
+ <li><code>GL_OES_vertex_array_object</code></li>
+
+ <li><code>GL_OES_EGL_image_external</code></li>
+
+ <li><code>GL_AMD_program_binary_Z400</code></li>
+
+ <li><code>GL_EXT_blend_minmax</code></li>
+
+ <li><code>GL_EXT_discard_framebuffer</code></li>
+
+ <li><code>GL_EXT_multi_draw_arrays</code></li>
+
+ <li><code>GL_EXT_read_format_bgra</code></li>
+
+ <li><code>GL_EXT_texture_format_BGRA8888</code></li>
+
+ <li><code>GL_EXT_texture_compression_dxt1</code></li>
+
+ <li><code>GL_IMG_program_binary</code></li>
+
+ <li><code>GL_IMG_read_format</code></li>
+
+ <li><code>GL_IMG_shader_binary</code></li>
+
+ <li><code>GL_IMG_texture_compression_pvrtc</code></li>
+
+ <li><code>GL_IMG_multisampled_render_to_texture</code></li>
+
+ <li><code>GL_NV_coverage_sample</code></li>
+
+ <li><code>GL_NV_depth_nonlinear</code></li>
+
+ <li><code>GL_QCOM_extended_get</code></li>
+
+ <li><code>GL_QCOM_extended_get2</code></li>
+
+ <li><code>GL_QCOM_writeonly_rendering</code></li>
+
+ <li><code>GL_QCOM_tiled_rendering</code></li>
+ </ul>
+ </dd>
+
+ <dt>EGL</dt>
+
+ <dd>
+ <ul>
+ <li><code>EGL_ANDROID_recordable</code></li>
+
+ <li><code>EGL_NV_system_time</code></li>
+ </ul>
+ </dd>
+ </dl>
+ </li>
+ </ul>
+ </dd>
+ </dl>
+ </div>
+</div>
+
+
+
+<div class="toggleable closed">
+ <a href="#" onclick="return toggleDiv(this)"><img src=
+ "{@docRoot}assets/images/triangle-closed.png" class="toggle-img" height="9px" width="9px">
Android NDK, Revision 6b</a> <em>(August 2011)</em>
<div class="toggleme">
diff --git a/docs/html/sdk/sdk_toc.cs b/docs/html/sdk/sdk_toc.cs
index 9a18f7da..afe6a6e 100644
--- a/docs/html/sdk/sdk_toc.cs
+++ b/docs/html/sdk/sdk_toc.cs
@@ -192,7 +192,8 @@
<span style="display:none" class="zh-TW"></span>
</h2>
<ul>
- <li><a href="<?cs var:toroot ?>sdk/ndk/index.html">Android NDK, r6b</a>
+ <li><a href="<?cs var:toroot ?>sdk/ndk/index.html">Android NDK, r7</a>
+ <span class="new">new!</span>
</li>
<li><a href="<?cs var:toroot ?>sdk/ndk/overview.html">What is the NDK?</a></li>
</ul>
diff --git a/graphics/java/android/graphics/Bitmap.java b/graphics/java/android/graphics/Bitmap.java
index 79acd55..380b3d8 100644
--- a/graphics/java/android/graphics/Bitmap.java
+++ b/graphics/java/android/graphics/Bitmap.java
@@ -604,10 +604,13 @@
}
Bitmap bm = nativeCreate(null, 0, width, width, height, config.nativeInt, true);
if (config == Config.ARGB_8888 && !hasAlpha) {
- bm.eraseColor(0xff000000);
+ nativeErase(bm.mNativeBitmap, 0xff000000);
nativeSetHasAlpha(bm.mNativeBitmap, hasAlpha);
} else {
- bm.eraseColor(0);
+ // No need to initialize it to zeroes; it is backed by a VM byte array
+ // which is by definition preinitialized to all zeroes.
+ //
+ //nativeErase(bm.mNativeBitmap, 0);
}
return bm;
}
diff --git a/graphics/java/android/graphics/SurfaceTexture.java b/graphics/java/android/graphics/SurfaceTexture.java
index 29fab11..0521e69 100644
--- a/graphics/java/android/graphics/SurfaceTexture.java
+++ b/graphics/java/android/graphics/SurfaceTexture.java
@@ -17,6 +17,7 @@
package android.graphics;
import java.lang.ref.WeakReference;
+
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
@@ -141,6 +142,12 @@
* android.view.Surface#lockCanvas} is called. For OpenGL ES, the EGLSurface should be
* destroyed (via eglDestroySurface), made not-current (via eglMakeCurrent), and then recreated
* (via eglCreateWindowSurface) to ensure that the new default size has taken effect.
+ *
+ * The width and height parameters must be no greater than the minimum of
+ * GL_MAX_VIEWPORT_DIMS and GL_MAX_TEXTURE_SIZE (see
+ * {@link javax.microedition.khronos.opengles.GL10#glGetIntegerv glGetIntegerv}).
+ * An error due to invalid dimensions might not be reported until
+ * updateTexImage() is called.
*/
public void setDefaultBufferSize(int width, int height) {
nativeSetDefaultBufferSize(width, height);
@@ -152,7 +159,10 @@
* implicitly bind its texture to the GL_TEXTURE_EXTERNAL_OES texture target.
*/
public void updateTexImage() {
- nativeUpdateTexImage();
+ int err = nativeUpdateTexImage();
+ if (err != 0) {
+ throw new RuntimeException("Error during updateTexImage (see logs)");
+ }
}
/**
@@ -258,7 +268,7 @@
private native void nativeGetTransformMatrix(float[] mtx);
private native long nativeGetTimestamp();
private native void nativeSetDefaultBufferSize(int width, int height);
- private native void nativeUpdateTexImage();
+ private native int nativeUpdateTexImage();
private native int nativeGetQueuedCount();
private native void nativeRelease();
diff --git a/graphics/java/android/renderscript/RSSurfaceView.java b/graphics/java/android/renderscript/RSSurfaceView.java
index 199952c..20eb93f 100644
--- a/graphics/java/android/renderscript/RSSurfaceView.java
+++ b/graphics/java/android/renderscript/RSSurfaceView.java
@@ -30,7 +30,7 @@
import android.view.SurfaceView;
/**
- * The Surface View for a graphics renderscript (RenderScriptGL) to draw on.
+ * The Surface View for a graphics renderscript (RenderScriptGL) to draw on.
*/
public class RSSurfaceView extends SurfaceView implements SurfaceHolder.Callback {
private SurfaceHolder mSurfaceHolder;
@@ -77,7 +77,7 @@
* This method is part of the SurfaceHolder.Callback interface, and is
* not normally called or subclassed by clients of RSSurfaceView.
*/
- public void surfaceDestroyed(SurfaceHolder holder) {
+ public synchronized void surfaceDestroyed(SurfaceHolder holder) {
// Surface will be destroyed when we return
if (mRS != null) {
mRS.setSurface(null, 0, 0);
@@ -88,7 +88,7 @@
* This method is part of the SurfaceHolder.Callback interface, and is
* not normally called or subclassed by clients of RSSurfaceView.
*/
- public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
+ public synchronized void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
if (mRS != null) {
mRS.setSurface(holder, w, h);
}
@@ -125,7 +125,7 @@
return rs;
}
- public void destroyRenderScriptGL() {
+ public synchronized void destroyRenderScriptGL() {
mRS.destroy();
mRS = null;
}
diff --git a/include/gui/SurfaceTexture.h b/include/gui/SurfaceTexture.h
index e2d6179e..d7dd4d6 100644
--- a/include/gui/SurfaceTexture.h
+++ b/include/gui/SurfaceTexture.h
@@ -79,7 +79,11 @@
// pointed to by the buf argument and a status of OK is returned. If no
// slot is available then a status of -EBUSY is returned and buf is
// unmodified.
- virtual status_t dequeueBuffer(int *buf, uint32_t w, uint32_t h,
+ // The width and height parameters must be no greater than the minimum of
+ // GL_MAX_VIEWPORT_DIMS and GL_MAX_TEXTURE_SIZE (see: glGetIntegerv).
+ // An error due to invalid dimensions might not be reported until
+ // updateTexImage() is called.
+ virtual status_t dequeueBuffer(int *buf, uint32_t width, uint32_t height,
uint32_t format, uint32_t usage);
// queueBuffer returns a filled buffer to the SurfaceTexture. In addition, a
@@ -176,7 +180,11 @@
// requestBuffers when a with and height of zero is requested.
// A call to setDefaultBufferSize() may trigger requestBuffers() to
// be called from the client.
- status_t setDefaultBufferSize(uint32_t w, uint32_t h);
+ // The width and height parameters must be no greater than the minimum of
+ // GL_MAX_VIEWPORT_DIMS and GL_MAX_TEXTURE_SIZE (see: glGetIntegerv).
+ // An error due to invalid dimensions might not be reported until
+ // updateTexImage() is called.
+ status_t setDefaultBufferSize(uint32_t width, uint32_t height);
// getCurrentBuffer returns the buffer associated with the current image.
sp<GraphicBuffer> getCurrentBuffer() const;
diff --git a/include/media/mediametadataretriever.h b/include/media/mediametadataretriever.h
index 9aa6700..534afce 100644
--- a/include/media/mediametadataretriever.h
+++ b/include/media/mediametadataretriever.h
@@ -54,6 +54,7 @@
METADATA_KEY_BITRATE = 20,
METADATA_KEY_TIMED_TEXT_LANGUAGES = 21,
METADATA_KEY_IS_DRM = 22,
+ METADATA_KEY_LOCATION = 23,
// Add more here...
};
diff --git a/include/media/stagefright/MetaData.h b/include/media/stagefright/MetaData.h
index 57f678c..4cdee17 100644
--- a/include/media/stagefright/MetaData.h
+++ b/include/media/stagefright/MetaData.h
@@ -85,6 +85,7 @@
kKeyDate = 'date', // cstring
kKeyWriter = 'writ', // cstring
kKeyCompilation = 'cpil', // cstring
+ kKeyLocation = 'loc ', // cstring
kKeyTimeScale = 'tmsl', // int32_t
// video profile and level
diff --git a/libs/gui/tests/SurfaceTexture_test.cpp b/libs/gui/tests/SurfaceTexture_test.cpp
index 5daafd5..93ebfb9 100644
--- a/libs/gui/tests/SurfaceTexture_test.cpp
+++ b/libs/gui/tests/SurfaceTexture_test.cpp
@@ -1520,4 +1520,36 @@
EXPECT_EQ(1, buffers[2]->getStrongCount());
}
+TEST_F(SurfaceTextureGLTest, InvalidWidthOrHeightFails) {
+ int texHeight = 16;
+ ANativeWindowBuffer* anb;
+
+ GLint maxTextureSize;
+ glGetIntegerv(GL_MAX_TEXTURE_SIZE, &maxTextureSize);
+
+ // make sure it works with small textures
+ mST->setDefaultBufferSize(16, texHeight);
+ EXPECT_EQ(NO_ERROR, mANW->dequeueBuffer(mANW.get(), &anb));
+ EXPECT_EQ(16, anb->width);
+ EXPECT_EQ(texHeight, anb->height);
+ EXPECT_EQ(NO_ERROR, mANW->queueBuffer(mANW.get(), anb));
+ EXPECT_EQ(NO_ERROR, mST->updateTexImage());
+
+ // make sure it works with GL_MAX_TEXTURE_SIZE
+ mST->setDefaultBufferSize(maxTextureSize, texHeight);
+ EXPECT_EQ(NO_ERROR, mANW->dequeueBuffer(mANW.get(), &anb));
+ EXPECT_EQ(maxTextureSize, anb->width);
+ EXPECT_EQ(texHeight, anb->height);
+ EXPECT_EQ(NO_ERROR, mANW->queueBuffer(mANW.get(), anb));
+ EXPECT_EQ(NO_ERROR, mST->updateTexImage());
+
+ // make sure it fails with GL_MAX_TEXTURE_SIZE+1
+ mST->setDefaultBufferSize(maxTextureSize+1, texHeight);
+ EXPECT_EQ(NO_ERROR, mANW->dequeueBuffer(mANW.get(), &anb));
+ EXPECT_EQ(maxTextureSize+1, anb->width);
+ EXPECT_EQ(texHeight, anb->height);
+ EXPECT_EQ(NO_ERROR, mANW->queueBuffer(mANW.get(), anb));
+ ASSERT_NE(NO_ERROR, mST->updateTexImage());
+}
+
} // namespace android
diff --git a/libs/hwui/Caches.cpp b/libs/hwui/Caches.cpp
index 75b07de..f293cba 100644
--- a/libs/hwui/Caches.cpp
+++ b/libs/hwui/Caches.cpp
@@ -46,22 +46,16 @@
// Constructors/destructor
///////////////////////////////////////////////////////////////////////////////
-Caches::Caches(): Singleton<Caches>(), blend(false), lastSrcMode(GL_ZERO),
- lastDstMode(GL_ZERO), currentProgram(NULL) {
+Caches::Caches(): Singleton<Caches>(), mInitialized(false) {
GLint maxTextureUnits;
glGetIntegerv(GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS, &maxTextureUnits);
if (maxTextureUnits < REQUIRED_TEXTURE_UNITS_COUNT) {
LOGW("At least %d texture units are required!", REQUIRED_TEXTURE_UNITS_COUNT);
}
- glGenBuffers(1, &meshBuffer);
- glBindBuffer(GL_ARRAY_BUFFER, meshBuffer);
- glBufferData(GL_ARRAY_BUFFER, sizeof(gMeshVertices), gMeshVertices, GL_STATIC_DRAW);
-
glGetIntegerv(GL_MAX_TEXTURE_SIZE, &maxTextureSize);
- mCurrentBuffer = meshBuffer;
- mRegionMesh = NULL;
+ init();
mDebugLevel = readDebugLevel();
LOGD("Enabling debug mode %d", mDebugLevel);
@@ -71,8 +65,40 @@
#endif
}
-Caches::~Caches() {
+void Caches::init() {
+ if (mInitialized) return;
+
+ glGenBuffers(1, &meshBuffer);
+ glBindBuffer(GL_ARRAY_BUFFER, meshBuffer);
+ glBufferData(GL_ARRAY_BUFFER, sizeof(gMeshVertices), gMeshVertices, GL_STATIC_DRAW);
+
+ mCurrentBuffer = meshBuffer;
+ mRegionMesh = NULL;
+
+ blend = false;
+ lastSrcMode = GL_ZERO;
+ lastDstMode = GL_ZERO;
+ currentProgram = NULL;
+
+ mInitialized = true;
+}
+
+void Caches::terminate() {
+ if (!mInitialized) return;
+
+ glDeleteBuffers(1, &meshBuffer);
+ mCurrentBuffer = 0;
+
+ glDeleteBuffers(1, &mRegionMeshIndices);
delete[] mRegionMesh;
+ mRegionMesh = NULL;
+
+ fboCache.clear();
+
+ programCache.clear();
+ currentProgram = NULL;
+
+ mInitialized = false;
}
///////////////////////////////////////////////////////////////////////////////
diff --git a/libs/hwui/Caches.h b/libs/hwui/Caches.h
index 9b0d7c6e..5e58a9e 100644
--- a/libs/hwui/Caches.h
+++ b/libs/hwui/Caches.h
@@ -86,7 +86,6 @@
class ANDROID_API Caches: public Singleton<Caches> {
Caches();
- ~Caches();
friend class Singleton<Caches>;
@@ -109,6 +108,11 @@
};
/**
+ * Initializes the cache.
+ */
+ void init();
+
+ /**
* Flush the cache.
*
* @param mode Indicates how much of the cache should be flushed
@@ -116,6 +120,12 @@
void flush(FlushMode mode);
/**
+ * Destroys all resources associated with this cache. This should
+ * be called after a flush(kFlushMode_Full).
+ */
+ void terminate();
+
+ /**
* Indicates whether the renderer is in debug mode.
* This debug mode provides limited information to app developers.
*/
@@ -194,6 +204,7 @@
private:
DebugLevel mDebugLevel;
+ bool mInitialized;
}; // class Caches
}; // namespace uirenderer
diff --git a/media/java/android/media/AudioService.java b/media/java/android/media/AudioService.java
index fe15605..a8daab0 100644
--- a/media/java/android/media/AudioService.java
+++ b/media/java/android/media/AudioService.java
@@ -2693,11 +2693,22 @@
mCallingUid = uid;
}
- public void unlinkToDeath() {
+ private void unlinkToDeath() {
if (mSourceRef != null && mHandler != null) {
mSourceRef.unlinkToDeath(mHandler, 0);
}
}
+
+ @Override
+ protected void finalize() throws Throwable {
+ try {
+ unlinkToDeath();
+ } catch (java.util.NoSuchElementException e) {
+ Log.w(TAG, e + " thrown by unlinkToDeath() during finalize, ignoring");
+ } finally {
+ super.finalize();
+ }
+ }
}
private Stack<FocusStackEntry> mFocusStack = new Stack<FocusStackEntry>();
@@ -2732,8 +2743,7 @@
if (!mFocusStack.empty() && mFocusStack.peek().mClientId.equals(clientToRemove))
{
//Log.i(TAG, " removeFocusStackEntry() removing top of stack");
- FocusStackEntry fse = mFocusStack.pop();
- fse.unlinkToDeath();
+ mFocusStack.pop();
if (signal) {
// notify the new top of the stack it gained focus
notifyTopOfAudioFocusStack();
@@ -2752,7 +2762,6 @@
Log.i(TAG, " AudioFocus abandonAudioFocus(): removing entry for "
+ fse.mClientId);
stackIterator.remove();
- fse.unlinkToDeath();
}
}
}
@@ -2858,6 +2867,9 @@
// if focus is already owned by this client and the reason for acquiring the focus
// hasn't changed, don't do anything
if (mFocusStack.peek().mFocusChangeType == focusChangeHint) {
+ // unlink death handler so it can be gc'ed.
+ // linkToDeath() creates a JNI global reference preventing collection.
+ cb.unlinkToDeath(afdh, 0);
return AudioManager.AUDIOFOCUS_REQUEST_GRANTED;
}
// the reason for the audio focus request has changed: remove the current top of
diff --git a/media/java/android/media/MediaMetadataRetriever.java b/media/java/android/media/MediaMetadataRetriever.java
index 10694c3..11ecd1f 100644
--- a/media/java/android/media/MediaMetadataRetriever.java
+++ b/media/java/android/media/MediaMetadataRetriever.java
@@ -458,5 +458,12 @@
* @hide
*/
public static final int METADATA_KEY_IS_DRM = 22;
+ /**
+ * This key retrieves the location information, if available.
+ * The location should be specified according to ISO-6709 standard, under
+ * a mp4/3gp box "@xyz". Location with longitude of -90 degrees and latitude
+ * of 180 degrees will be retrieved as "-90.0000+180.0000", for instance.
+ */
+ public static final int METADATA_KEY_LOCATION = 23;
// Add more here...
}
diff --git a/media/libeffects/visualizer/EffectVisualizer.cpp b/media/libeffects/visualizer/EffectVisualizer.cpp
index 3c3af8f..1a06cc6 100644
--- a/media/libeffects/visualizer/EffectVisualizer.cpp
+++ b/media/libeffects/visualizer/EffectVisualizer.cpp
@@ -47,17 +47,22 @@
VISUALIZER_STATE_ACTIVE,
};
+// maximum number of reads from same buffer before resetting capture buffer. This means
+// that the framework has stopped playing audio and we must start returning silence
+#define MAX_STALL_COUNT 10
+
struct VisualizerContext {
const struct effect_interface_s *mItfe;
effect_config_t mConfig;
- uint32_t mState;
uint32_t mCaptureIdx;
uint32_t mCaptureSize;
- uint32_t mCurrentBuf;
+ uint8_t mState;
+ uint8_t mCurrentBuf;
+ uint8_t mLastBuf;
+ uint8_t mStallCount;
uint8_t mCaptureBuf[2][VISUALIZER_CAPTURE_SIZE_MAX];
};
-
//
//--- Local functions
//
@@ -66,6 +71,8 @@
{
pContext->mCaptureIdx = 0;
pContext->mCurrentBuf = 0;
+ pContext->mLastBuf = 1;
+ pContext->mStallCount = 0;
memset(pContext->mCaptureBuf[0], 0x80, VISUALIZER_CAPTURE_SIZE_MAX);
memset(pContext->mCaptureBuf[1], 0x80, VISUALIZER_CAPTURE_SIZE_MAX);
}
@@ -417,9 +424,24 @@
memcpy(pReplyData,
pContext->mCaptureBuf[pContext->mCurrentBuf ^ 1],
pContext->mCaptureSize);
+ // if audio framework has stopped playing audio although the effect is still
+ // active we must clear the capture buffer to return silence
+ if (pContext->mLastBuf == pContext->mCurrentBuf) {
+ if (pContext->mStallCount < MAX_STALL_COUNT) {
+ if (++pContext->mStallCount == MAX_STALL_COUNT) {
+ memset(pContext->mCaptureBuf[pContext->mCurrentBuf ^ 1],
+ 0x80,
+ pContext->mCaptureSize);
+ }
+ }
+ } else {
+ pContext->mStallCount = 0;
+ }
+ pContext->mLastBuf = pContext->mCurrentBuf;
} else {
memset(pReplyData, 0x80, pContext->mCaptureSize);
}
+
break;
default:
diff --git a/media/libstagefright/MPEG4Extractor.cpp b/media/libstagefright/MPEG4Extractor.cpp
index 1e24599..1ebf0a8 100644
--- a/media/libstagefright/MPEG4Extractor.cpp
+++ b/media/libstagefright/MPEG4Extractor.cpp
@@ -1136,6 +1136,41 @@
break;
}
+ // @xyz
+ case FOURCC('\xA9', 'x', 'y', 'z'):
+ {
+ // Best case the total data length inside "@xyz" box
+ // would be 8, for instance "@xyz" + "\x00\x04\x15\xc7" + "0+0/",
+ // where "\x00\x04" is the text string length with value = 4,
+ // "\0x15\xc7" is the language code = en, and "0+0" is a
+ // location (string) value with longitude = 0 and latitude = 0.
+ if (chunk_data_size < 8) {
+ return ERROR_MALFORMED;
+ }
+
+ // Worst case the location string length would be 18,
+ // for instance +90.0000-180.0000, without the trailing "/" and
+ // the string length + language code.
+ char buffer[18];
+
+ // Substracting 5 from the data size is because the text string length +
+ // language code takes 4 bytes, and the trailing slash "/" takes 1 byte.
+ off64_t location_length = chunk_data_size - 5;
+ if (location_length >= (off64_t) sizeof(buffer)) {
+ return ERROR_MALFORMED;
+ }
+
+ if (mDataSource->readAt(
+ data_offset + 4, buffer, location_length) < location_length) {
+ return ERROR_IO;
+ }
+
+ buffer[location_length] = '\0';
+ mFileMetaData->setCString(kKeyLocation, buffer);
+ *offset += chunk_size;
+ break;
+ }
+
case FOURCC('e', 's', 'd', 's'):
{
if (chunk_data_size < 4) {
diff --git a/media/libstagefright/StagefrightMetadataRetriever.cpp b/media/libstagefright/StagefrightMetadataRetriever.cpp
index c74cb5a..4491c97 100644
--- a/media/libstagefright/StagefrightMetadataRetriever.cpp
+++ b/media/libstagefright/StagefrightMetadataRetriever.cpp
@@ -418,6 +418,7 @@
{ kKeyYear, METADATA_KEY_YEAR },
{ kKeyWriter, METADATA_KEY_WRITER },
{ kKeyCompilation, METADATA_KEY_COMPILATION },
+ { kKeyLocation, METADATA_KEY_LOCATION },
};
static const size_t kNumMapEntries = sizeof(kMap) / sizeof(kMap[0]);
diff --git a/media/libstagefright/rtsp/ARTPConnection.cpp b/media/libstagefright/rtsp/ARTPConnection.cpp
index 47de4e09..cd374e2 100644
--- a/media/libstagefright/rtsp/ARTPConnection.cpp
+++ b/media/libstagefright/rtsp/ARTPConnection.cpp
@@ -220,7 +220,7 @@
}
if (it == mStreams.end()) {
- TRESPASS();
+ return;
}
mStreams.erase(it);
@@ -274,41 +274,52 @@
}
int res = select(maxSocket + 1, &rs, NULL, NULL, &tv);
- CHECK_GE(res, 0);
if (res > 0) {
- for (List<StreamInfo>::iterator it = mStreams.begin();
- it != mStreams.end(); ++it) {
+ List<StreamInfo>::iterator it = mStreams.begin();
+ while (it != mStreams.end()) {
if ((*it).mIsInjected) {
+ ++it;
continue;
}
+ status_t err = OK;
if (FD_ISSET(it->mRTPSocket, &rs)) {
- receive(&*it, true);
+ err = receive(&*it, true);
}
- if (FD_ISSET(it->mRTCPSocket, &rs)) {
- receive(&*it, false);
+ if (err == OK && FD_ISSET(it->mRTCPSocket, &rs)) {
+ err = receive(&*it, false);
}
+
+ if (err == -ECONNRESET) {
+ // socket failure, this stream is dead, Jim.
+
+ LOGW("failed to receive RTP/RTCP datagram.");
+ it = mStreams.erase(it);
+ continue;
+ }
+
+ ++it;
}
}
- postPollEvent();
-
int64_t nowUs = ALooper::GetNowUs();
if (mLastReceiverReportTimeUs <= 0
|| mLastReceiverReportTimeUs + 5000000ll <= nowUs) {
sp<ABuffer> buffer = new ABuffer(kMaxUDPSize);
- for (List<StreamInfo>::iterator it = mStreams.begin();
- it != mStreams.end(); ++it) {
+ List<StreamInfo>::iterator it = mStreams.begin();
+ while (it != mStreams.end()) {
StreamInfo *s = &*it;
if (s->mIsInjected) {
+ ++it;
continue;
}
if (s->mNumRTCPPacketsReceived == 0) {
// We have never received any RTCP packets on this stream,
// we don't even know where to send a report.
+ ++it;
continue;
}
@@ -327,16 +338,34 @@
if (buffer->size() > 0) {
LOGV("Sending RR...");
- ssize_t n = sendto(
+ ssize_t n;
+ do {
+ n = sendto(
s->mRTCPSocket, buffer->data(), buffer->size(), 0,
(const struct sockaddr *)&s->mRemoteRTCPAddr,
sizeof(s->mRemoteRTCPAddr));
+ } while (n < 0 && errno == EINTR);
+
+ if (n <= 0) {
+ LOGW("failed to send RTCP receiver report (%s).",
+ n == 0 ? "connection gone" : strerror(errno));
+
+ it = mStreams.erase(it);
+ continue;
+ }
+
CHECK_EQ(n, (ssize_t)buffer->size());
mLastReceiverReportTimeUs = nowUs;
}
+
+ ++it;
}
}
+
+ if (!mStreams.empty()) {
+ postPollEvent();
+ }
}
status_t ARTPConnection::receive(StreamInfo *s, bool receiveRTP) {
@@ -350,16 +379,19 @@
(!receiveRTP && s->mNumRTCPPacketsReceived == 0)
? sizeof(s->mRemoteRTCPAddr) : 0;
- ssize_t nbytes = recvfrom(
+ ssize_t nbytes;
+ do {
+ nbytes = recvfrom(
receiveRTP ? s->mRTPSocket : s->mRTCPSocket,
buffer->data(),
buffer->capacity(),
0,
remoteAddrLen > 0 ? (struct sockaddr *)&s->mRemoteRTCPAddr : NULL,
remoteAddrLen > 0 ? &remoteAddrLen : NULL);
+ } while (nbytes < 0 && errno == EINTR);
- if (nbytes < 0) {
- return -1;
+ if (nbytes <= 0) {
+ return -ECONNRESET;
}
buffer->setRange(0, nbytes);
diff --git a/media/libstagefright/rtsp/ARTSPConnection.cpp b/media/libstagefright/rtsp/ARTSPConnection.cpp
index bd0e491..4f0363b 100644
--- a/media/libstagefright/rtsp/ARTSPConnection.cpp
+++ b/media/libstagefright/rtsp/ARTSPConnection.cpp
@@ -187,10 +187,13 @@
return true;
}
-static void MakeSocketBlocking(int s, bool blocking) {
+static status_t MakeSocketBlocking(int s, bool blocking) {
// Make socket non-blocking.
int flags = fcntl(s, F_GETFL, 0);
- CHECK_NE(flags, -1);
+
+ if (flags == -1) {
+ return UNKNOWN_ERROR;
+ }
if (blocking) {
flags &= ~O_NONBLOCK;
@@ -198,7 +201,9 @@
flags |= O_NONBLOCK;
}
- CHECK_NE(fcntl(s, F_SETFL, flags), -1);
+ flags = fcntl(s, F_SETFL, flags);
+
+ return flags == -1 ? UNKNOWN_ERROR : OK;
}
void ARTSPConnection::onConnect(const sp<AMessage> &msg) {
@@ -302,27 +307,32 @@
reply->post();
}
+void ARTSPConnection::performDisconnect() {
+ if (mUIDValid) {
+ HTTPBase::UnRegisterSocketUserTag(mSocket);
+ }
+ close(mSocket);
+ mSocket = -1;
+
+ flushPendingRequests();
+
+ mUser.clear();
+ mPass.clear();
+ mAuthType = NONE;
+ mNonce.clear();
+
+ mState = DISCONNECTED;
+}
+
void ARTSPConnection::onDisconnect(const sp<AMessage> &msg) {
if (mState == CONNECTED || mState == CONNECTING) {
- if (mUIDValid) {
- HTTPBase::UnRegisterSocketUserTag(mSocket);
- }
- close(mSocket);
- mSocket = -1;
-
- flushPendingRequests();
+ performDisconnect();
}
sp<AMessage> reply;
CHECK(msg->findMessage("reply", &reply));
reply->setInt32("result", OK);
- mState = DISCONNECTED;
-
- mUser.clear();
- mPass.clear();
- mAuthType = NONE;
- mNonce.clear();
reply->post();
}
@@ -427,21 +437,25 @@
send(mSocket, request.c_str() + numBytesSent,
request.size() - numBytesSent, 0);
- if (n == 0) {
- // Server closed the connection.
- LOGE("Server unexpectedly closed the connection.");
+ if (n < 0 && errno == EINTR) {
+ continue;
+ }
- reply->setInt32("result", ERROR_IO);
- reply->post();
- return;
- } else if (n < 0) {
- if (errno == EINTR) {
- continue;
+ if (n <= 0) {
+ performDisconnect();
+
+ if (n == 0) {
+ // Server closed the connection.
+ LOGE("Server unexpectedly closed the connection.");
+
+ reply->setInt32("result", ERROR_IO);
+ reply->post();
+ } else {
+ LOGE("Error sending rtsp request. (%s)", strerror(errno));
+ reply->setInt32("result", -errno);
+ reply->post();
}
- LOGE("Error sending rtsp request.");
- reply->setInt32("result", -errno);
- reply->post();
return;
}
@@ -512,17 +526,22 @@
size_t offset = 0;
while (offset < size) {
ssize_t n = recv(mSocket, (uint8_t *)data + offset, size - offset, 0);
- if (n == 0) {
- // Server closed the connection.
- LOGE("Server unexpectedly closed the connection.");
- return ERROR_IO;
- } else if (n < 0) {
- if (errno == EINTR) {
- continue;
- }
- LOGE("Error reading rtsp response.");
- return -errno;
+ if (n < 0 && errno == EINTR) {
+ continue;
+ }
+
+ if (n <= 0) {
+ performDisconnect();
+
+ if (n == 0) {
+ // Server closed the connection.
+ LOGE("Server unexpectedly closed the connection.");
+ return ERROR_IO;
+ } else {
+ LOGE("Error reading rtsp response. (%s)", strerror(errno));
+ return -errno;
+ }
}
offset += (size_t)n;
@@ -681,24 +700,8 @@
if (contentLength > 0) {
response->mContent = new ABuffer(contentLength);
- size_t numBytesRead = 0;
- while (numBytesRead < contentLength) {
- ssize_t n = recv(
- mSocket, response->mContent->data() + numBytesRead,
- contentLength - numBytesRead, 0);
-
- if (n == 0) {
- // Server closed the connection.
- TRESPASS();
- } else if (n < 0) {
- if (errno == EINTR) {
- continue;
- }
-
- TRESPASS();
- }
-
- numBytesRead += (size_t)n;
+ if (receive(response->mContent->data(), contentLength) != OK) {
+ return false;
}
}
@@ -765,17 +768,20 @@
send(mSocket, response.c_str() + numBytesSent,
response.size() - numBytesSent, 0);
- if (n == 0) {
- // Server closed the connection.
- LOGE("Server unexpectedly closed the connection.");
+ if (n < 0 && errno == EINTR) {
+ continue;
+ }
- return false;
- } else if (n < 0) {
- if (errno == EINTR) {
- continue;
+ if (n <= 0) {
+ if (n == 0) {
+ // Server closed the connection.
+ LOGE("Server unexpectedly closed the connection.");
+ } else {
+ LOGE("Error sending rtsp response (%s).", strerror(errno));
}
- LOGE("Error sending rtsp response.");
+ performDisconnect();
+
return false;
}
diff --git a/media/libstagefright/rtsp/ARTSPConnection.h b/media/libstagefright/rtsp/ARTSPConnection.h
index 5cb84fd..68f2d59 100644
--- a/media/libstagefright/rtsp/ARTSPConnection.h
+++ b/media/libstagefright/rtsp/ARTSPConnection.h
@@ -91,6 +91,8 @@
AString mUserAgent;
+ void performDisconnect();
+
void onConnect(const sp<AMessage> &msg);
void onDisconnect(const sp<AMessage> &msg);
void onCompleteConnection(const sp<AMessage> &msg);
diff --git a/media/libstagefright/rtsp/MyHandler.h b/media/libstagefright/rtsp/MyHandler.h
index 6a5efa4..794c60b 100644
--- a/media/libstagefright/rtsp/MyHandler.h
+++ b/media/libstagefright/rtsp/MyHandler.h
@@ -463,8 +463,17 @@
mBaseURL = tmp;
}
- CHECK_GT(mSessionDesc->countTracks(), 1u);
- setupTrack(1);
+ if (mSessionDesc->countTracks() < 2) {
+ // There's no actual tracks in this session.
+ // The first "track" is merely session meta
+ // data.
+
+ LOGW("Session doesn't contain any playable "
+ "tracks. Aborting.");
+ result = ERROR_UNSUPPORTED;
+ } else {
+ setupTrack(1);
+ }
}
}
}
@@ -783,9 +792,13 @@
}
if (mNumAccessUnitsReceived == 0) {
+#if 1
LOGI("stream ended? aborting.");
(new AMessage('abor', id()))->post();
break;
+#else
+ LOGI("haven't seen an AU in a looong time.");
+#endif
}
mNumAccessUnitsReceived = 0;
diff --git a/nfc-extras/java/com/android/nfc_extras/NfcAdapterExtras.java b/nfc-extras/java/com/android/nfc_extras/NfcAdapterExtras.java
index 99cbb86..62213de 100644
--- a/nfc-extras/java/com/android/nfc_extras/NfcAdapterExtras.java
+++ b/nfc-extras/java/com/android/nfc_extras/NfcAdapterExtras.java
@@ -16,8 +16,7 @@
package com.android.nfc_extras;
-import android.annotation.SdkConstant;
-import android.annotation.SdkConstant.SdkConstantType;
+import android.content.Context;
import android.nfc.INfcAdapterExtras;
import android.nfc.NfcAdapter;
import android.os.RemoteException;
@@ -60,10 +59,14 @@
// best effort recovery
private static NfcAdapter sAdapter;
private static INfcAdapterExtras sService;
- private static NfcAdapterExtras sSingleton;
- private static NfcExecutionEnvironment sEmbeddedEe;
- private static CardEmulationRoute sRouteOff;
- private static CardEmulationRoute sRouteOnWhenScreenOn;
+ private static final CardEmulationRoute ROUTE_OFF =
+ new CardEmulationRoute(CardEmulationRoute.ROUTE_OFF, null);
+
+ private final NfcExecutionEnvironment mEmbeddedEe;
+ private final CardEmulationRoute mRouteOnWhenScreenOn;
+
+ final Context mContext;
+ final String mPackageName;
/** get service handles */
private static void initService() {
@@ -84,31 +87,35 @@
* @return the {@link NfcAdapterExtras} object for the given {@link NfcAdapter}
*/
public static NfcAdapterExtras get(NfcAdapter adapter) {
- synchronized(NfcAdapterExtras.class) {
- if (sSingleton == null) {
+ Context context = adapter.getContext();
+ if (context == null) {
+ throw new UnsupportedOperationException(
+ "You must pass a context to your NfcAdapter to use the NFC extras APIs");
+ }
+
+ synchronized (NfcAdapterExtras.class) {
+ if (sService == null) {
try {
sAdapter = adapter;
- sSingleton = new NfcAdapterExtras();
- sEmbeddedEe = new NfcExecutionEnvironment(sSingleton);
- sRouteOff = new CardEmulationRoute(CardEmulationRoute.ROUTE_OFF, null);
- sRouteOnWhenScreenOn = new CardEmulationRoute(
- CardEmulationRoute.ROUTE_ON_WHEN_SCREEN_ON, sEmbeddedEe);
initService();
} finally {
if (sService == null) {
- sRouteOnWhenScreenOn = null;
- sRouteOff = null;
- sEmbeddedEe = null;
- sSingleton = null;
sAdapter = null;
}
}
}
- return sSingleton;
}
+
+ return new NfcAdapterExtras(context);
}
- private NfcAdapterExtras() {}
+ private NfcAdapterExtras(Context context) {
+ mContext = context.getApplicationContext();
+ mPackageName = context.getPackageName();
+ mEmbeddedEe = new NfcExecutionEnvironment(this);
+ mRouteOnWhenScreenOn = new CardEmulationRoute(CardEmulationRoute.ROUTE_ON_WHEN_SCREEN_ON,
+ mEmbeddedEe);
+ }
/**
* Immutable data class that describes a card emulation route.
@@ -166,18 +173,16 @@
*
* <p class="note">
* Requires the {@link android.Manifest.permission#WRITE_SECURE_SETTINGS} permission.
- *
- * @return
*/
public CardEmulationRoute getCardEmulationRoute() {
try {
- int route = sService.getCardEmulationRoute();
+ int route = sService.getCardEmulationRoute(mPackageName);
return route == CardEmulationRoute.ROUTE_OFF ?
- sRouteOff :
- sRouteOnWhenScreenOn;
+ ROUTE_OFF :
+ mRouteOnWhenScreenOn;
} catch (RemoteException e) {
attemptDeadServiceRecovery(e);
- return sRouteOff;
+ return ROUTE_OFF;
}
}
@@ -189,11 +194,11 @@
* <p class="note">
* Requires the {@link android.Manifest.permission#WRITE_SECURE_SETTINGS} permission.
*
- * @param route a {@link #CardEmulationRoute}
+ * @param route a {@link CardEmulationRoute}
*/
public void setCardEmulationRoute(CardEmulationRoute route) {
try {
- sService.setCardEmulationRoute(route.route);
+ sService.setCardEmulationRoute(mPackageName, route.route);
} catch (RemoteException e) {
attemptDeadServiceRecovery(e);
}
@@ -201,7 +206,7 @@
/**
* Get the {@link NfcExecutionEnvironment} that is embedded with the
- * {@link NFcAdapter}.
+ * {@link NfcAdapter}.
*
* <p class="note">
* Requires the {@link android.Manifest.permission#WRITE_SECURE_SETTINGS} permission.
@@ -209,7 +214,7 @@
* @return a {@link NfcExecutionEnvironment}, or null if there is no embedded NFC-EE
*/
public NfcExecutionEnvironment getEmbeddedExecutionEnvironment() {
- return sEmbeddedEe;
+ return mEmbeddedEe;
}
/**
@@ -218,12 +223,12 @@
* Some implementations of NFC Adapter Extras may require applications
* to authenticate with a token, before using other methods.
*
- * @param a implementation specific token
- * @throws a {@link java.lang.SecurityException} if authentication failed
+ * @param token a implementation specific token
+ * @throws java.lang.SecurityException if authentication failed
*/
public void authenticate(byte[] token) {
try {
- sService.authenticate(token);
+ sService.authenticate(mPackageName, token);
} catch (RemoteException e) {
attemptDeadServiceRecovery(e);
}
diff --git a/nfc-extras/java/com/android/nfc_extras/NfcExecutionEnvironment.java b/nfc-extras/java/com/android/nfc_extras/NfcExecutionEnvironment.java
index 63c2de2..f47327a 100644
--- a/nfc-extras/java/com/android/nfc_extras/NfcExecutionEnvironment.java
+++ b/nfc-extras/java/com/android/nfc_extras/NfcExecutionEnvironment.java
@@ -16,20 +16,17 @@
package com.android.nfc_extras;
-import java.io.IOException;
-
import android.annotation.SdkConstant;
import android.annotation.SdkConstant.SdkConstantType;
-import android.content.Context;
-import android.nfc.INfcAdapterExtras;
-import android.nfc.NfcAdapter;
import android.os.Binder;
import android.os.Bundle;
-import android.os.IBinder;
import android.os.RemoteException;
+import java.io.IOException;
+
public class NfcExecutionEnvironment {
private final NfcAdapterExtras mExtras;
+ private final Binder mToken;
/**
* Broadcast Action: An ISO-DEP AID was selected.
@@ -115,6 +112,7 @@
NfcExecutionEnvironment(NfcAdapterExtras extras) {
mExtras = extras;
+ mToken = new Binder();
}
/**
@@ -133,7 +131,7 @@
*/
public void open() throws IOException {
try {
- Bundle b = mExtras.getService().open(new Binder());
+ Bundle b = mExtras.getService().open(mExtras.mPackageName, mToken);
throwBundle(b);
} catch (RemoteException e) {
mExtras.attemptDeadServiceRecovery(e);
@@ -151,7 +149,7 @@
*/
public void close() throws IOException {
try {
- throwBundle(mExtras.getService().close());
+ throwBundle(mExtras.getService().close(mExtras.mPackageName, mToken));
} catch (RemoteException e) {
mExtras.attemptDeadServiceRecovery(e);
throw new IOException("NFC Service was dead");
@@ -169,7 +167,7 @@
public byte[] transceive(byte[] in) throws IOException {
Bundle b;
try {
- b = mExtras.getService().transceive(in);
+ b = mExtras.getService().transceive(mExtras.mPackageName, in);
} catch (RemoteException e) {
mExtras.attemptDeadServiceRecovery(e);
throw new IOException("NFC Service was dead, need to re-open");
diff --git a/opengl/java/android/opengl/EGLLogWrapper.java b/opengl/java/android/opengl/EGLLogWrapper.java
index 6c0fdb3..36e88a2 100644
--- a/opengl/java/android/opengl/EGLLogWrapper.java
+++ b/opengl/java/android/opengl/EGLLogWrapper.java
@@ -314,6 +314,16 @@
checkError();
return result;
}
+
+ /** @hide **/
+ public boolean eglReleaseThread() {
+ begin("eglReleaseThread");
+ end();
+ boolean result = mEgl10.eglReleaseThread();
+ returns(result);
+ checkError();
+ return result;
+ }
public boolean eglSwapBuffers(EGLDisplay display, EGLSurface surface) {
begin("eglInitialize");
diff --git a/opengl/java/com/google/android/gles_jni/EGLImpl.java b/opengl/java/com/google/android/gles_jni/EGLImpl.java
index 51d6ca8..6992019 100644
--- a/opengl/java/com/google/android/gles_jni/EGLImpl.java
+++ b/opengl/java/com/google/android/gles_jni/EGLImpl.java
@@ -31,6 +31,8 @@
public native boolean eglInitialize(EGLDisplay display, int[] major_minor);
public native boolean eglQueryContext(EGLDisplay display, EGLContext context, int attribute, int[] value);
public native boolean eglQuerySurface(EGLDisplay display, EGLSurface surface, int attribute, int[] value);
+ /** @hide **/
+ public native boolean eglReleaseThread();
public native boolean eglChooseConfig(EGLDisplay display, int[] attrib_list, EGLConfig[] configs, int config_size, int[] num_config);
public native boolean eglGetConfigAttrib(EGLDisplay display, EGLConfig config, int attribute, int[] value);
public native boolean eglGetConfigs(EGLDisplay display, EGLConfig[] configs, int config_size, int[] num_config);
@@ -44,6 +46,9 @@
public native boolean eglCopyBuffers(EGLDisplay display, EGLSurface surface, Object native_pixmap);
public native boolean eglWaitGL();
public native boolean eglWaitNative(int engine, Object bindTarget);
+
+ /** @hide **/
+ public static native int getInitCount(EGLDisplay display);
public EGLContext eglCreateContext(EGLDisplay display, EGLConfig config, EGLContext share_context, int[] attrib_list) {
int eglContextId = _eglCreateContext(display, config, share_context, attrib_list);
@@ -85,7 +90,7 @@
eglSurfaceId = _eglCreateWindowSurface(display, config, sur, attrib_list);
} else if (native_window instanceof SurfaceTexture) {
eglSurfaceId = _eglCreateWindowSurfaceTexture(display, config,
- (SurfaceTexture) native_window, attrib_list);
+ native_window, attrib_list);
} else {
throw new java.lang.UnsupportedOperationException(
"eglCreateWindowSurface() can only be called with an instance of " +
diff --git a/opengl/java/javax/microedition/khronos/egl/EGL10.java b/opengl/java/javax/microedition/khronos/egl/EGL10.java
index 2ae793a..cf58888 100644
--- a/opengl/java/javax/microedition/khronos/egl/EGL10.java
+++ b/opengl/java/javax/microedition/khronos/egl/EGL10.java
@@ -114,6 +114,8 @@
boolean eglQueryContext(EGLDisplay display, EGLContext context, int attribute, int[] value);
String eglQueryString(EGLDisplay display, int name);
boolean eglQuerySurface(EGLDisplay display, EGLSurface surface, int attribute, int[] value);
+ /** @hide **/
+ boolean eglReleaseThread();
boolean eglSwapBuffers(EGLDisplay display, EGLSurface surface);
boolean eglTerminate(EGLDisplay display);
boolean eglWaitGL();
diff --git a/opengl/libs/EGL/egl_display.h b/opengl/libs/EGL/egl_display.h
index 1c1092c..e0a367d 100644
--- a/opengl/libs/EGL/egl_display.h
+++ b/opengl/libs/EGL/egl_display.h
@@ -91,6 +91,8 @@
inline bool isValid() const { return magic == '_dpy'; }
inline bool isAlive() const { return isValid(); }
+ inline uint32_t getRefsCount() const { return refs; }
+
struct strings_t {
char const * vendor;
char const * version;
diff --git a/packages/SettingsProvider/res/values/defaults.xml b/packages/SettingsProvider/res/values/defaults.xml
index 0891525..7a98615 100644
--- a/packages/SettingsProvider/res/values/defaults.xml
+++ b/packages/SettingsProvider/res/values/defaults.xml
@@ -133,8 +133,4 @@
<bool name="def_dtmf_tones_enabled">true</bool>
<!-- Default for UI touch sounds enabled -->
<bool name="def_sound_effects_enabled">true</bool>
-
- <!-- Default for Messaging app notifications enabled -->
- <bool name="def_messaging_app_notifications_on">true</bool>
-
</resources>
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java b/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
index 44194f0..5495d08 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
@@ -1472,10 +1472,6 @@
loadBooleanSetting(stmt, Settings.Secure.TOUCH_EXPLORATION_ENABLED,
R.bool.def_touch_exploration_enabled);
-
- loadBooleanSetting(stmt, Settings.Secure.MESSAGING_APP_NOTIFICATIONS,
- R.bool.def_messaging_app_notifications_on);
-
} finally {
if (stmt != null) stmt.close();
}
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_notification_open.png b/packages/SystemUI/res/drawable-hdpi/ic_notification_open.png
index d697c2f..cd9a54a 100644
--- a/packages/SystemUI/res/drawable-hdpi/ic_notification_open.png
+++ b/packages/SystemUI/res/drawable-hdpi/ic_notification_open.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_notification_open.png b/packages/SystemUI/res/drawable-mdpi/ic_notification_open.png
index 839c134..5661eaf 100644
--- a/packages/SystemUI/res/drawable-mdpi/ic_notification_open.png
+++ b/packages/SystemUI/res/drawable-mdpi/ic_notification_open.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_notification_open.png b/packages/SystemUI/res/drawable-xhdpi/ic_notification_open.png
index 4f8c987..98455cf 100644
--- a/packages/SystemUI/res/drawable-xhdpi/ic_notification_open.png
+++ b/packages/SystemUI/res/drawable-xhdpi/ic_notification_open.png
Binary files differ
diff --git a/packages/SystemUI/res/layout/signal_cluster_view.xml b/packages/SystemUI/res/layout/signal_cluster_view.xml
index 93ac22e..9be9041 100644
--- a/packages/SystemUI/res/layout/signal_cluster_view.xml
+++ b/packages/SystemUI/res/layout/signal_cluster_view.xml
@@ -51,7 +51,7 @@
android:visibility="gone"
android:id="@+id/spacer"
/>
- <FrameLayout
+ <!--<FrameLayout
android:id="@+id/wimax_combo"
android:layout_height="wrap_content"
android:layout_width="wrap_content"
@@ -72,6 +72,7 @@
android:layout_gravity="center|bottom"
/>
</FrameLayout>
+ -->
<FrameLayout
android:layout_height="wrap_content"
android:layout_width="wrap_content"
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index a0d7b13..fc81f8e 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -257,10 +257,16 @@
<string name="accessibility_wifi_three_bars">Wi-Fi three bars.</string>
<!-- Content description of the WIFI signal when it is full for accessibility (not shown on the screen). [CHAR LIMIT=NONE] -->
<string name="accessibility_wifi_signal_full">WiFi signal full.</string>
+
+ <!-- Content description of the WiMAX signal when no signal for accessibility (not shown on the screen). [CHAR LIMIT=NONE] -->
<string name="accessibility_no_wimax">No WiMAX.</string>
+ <!-- Content description of the WiMAX signal when it is one bar for accessibility (not shown on the screen). [CHAR LIMIT=NONE] -->
<string name="accessibility_wimax_one_bar">WiMAX one bar.</string>
+ <!-- Content description of the WiMAX signal when it is two bars for accessibility (not shown on the screen). [CHAR LIMIT=NONE] -->
<string name="accessibility_wimax_two_bars">WiMAX two bars.</string>
+ <!-- Content description of the WiMAX signal when it is three bars for accessibility (not shown on the screen). [CHAR LIMIT=NONE] -->
<string name="accessibility_wimax_three_bars">WiMAX three bars.</string>
+ <!-- Content description of the WiMAX signal when it is full for accessibility (not shown on the screen). [CHAR LIMIT=NONE] -->
<string name="accessibility_wimax_signal_full">WiMAX signal full.</string>
<!-- Content description of the data connection type GPRS for accessibility (not shown on the screen). [CHAR LIMIT=NONE] -->
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBar.java
index 2e1803e..2be35b7 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBar.java
@@ -118,15 +118,20 @@
WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
| WindowManager.LayoutParams.FLAG_TOUCHABLE_WHEN_WAKING
| WindowManager.LayoutParams.FLAG_SPLIT_TOUCH,
- PixelFormat.OPAQUE);
+ // We use a pixel format of RGB565 for the status bar to save memory bandwidth and
+ // to ensure that the layer can be handled by HWComposer. On some devices the
+ // HWComposer is unable to handle SW-rendered RGBX_8888 layers.
+ PixelFormat.RGB_565);
// the status bar should be in an overlay if possible
final Display defaultDisplay
= ((WindowManager)mContext.getSystemService(Context.WINDOW_SERVICE))
.getDefaultDisplay();
- if (ActivityManager.isHighEndGfx(defaultDisplay)) {
- lp.flags |= WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED;
- }
+
+ // We explicitly leave FLAG_HARDWARE_ACCELERATED out of the flags. The status bar occupies
+ // very little screen real-estate and is updated fairly frequently. By using CPU rendering
+ // for the status bar, we prevent the GPU from having to wake up just to do these small
+ // updates, which should help keep power consumption down.
lp.gravity = getStatusBarGravity();
lp.setTitle("StatusBar");
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 b0e6968..51fb262 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
@@ -350,11 +350,11 @@
(SignalClusterView)sb.findViewById(R.id.signal_cluster);
mNetworkController.addSignalCluster(signalCluster);
signalCluster.setNetworkController(mNetworkController);
- final ImageView wimaxRSSI =
- (ImageView)sb.findViewById(R.id.wimax_signal);
- if (wimaxRSSI != null) {
- mNetworkController.addWimaxIconView(wimaxRSSI);
- }
+// final ImageView wimaxRSSI =
+// (ImageView)sb.findViewById(R.id.wimax_signal);
+// if (wimaxRSSI != null) {
+// mNetworkController.addWimaxIconView(wimaxRSSI);
+// }
// Recents Panel
mRecentTasksLoader = new RecentTasksLoader(context);
updateRecentsPanel();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkController.java
index f77e93f..55a5b0a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkController.java
@@ -111,6 +111,7 @@
com.android.internal.R.drawable.stat_sys_tether_bluetooth;
//wimax
+ private boolean mWimaxSupported = false;
private boolean mIsWimaxEnabled = false;
private boolean mWimaxConnected = false;
private boolean mWimaxIdle = false;
@@ -213,9 +214,9 @@
filter.addAction(ConnectivityManager.INET_CONDITION_ACTION);
filter.addAction(Intent.ACTION_CONFIGURATION_CHANGED);
filter.addAction(Intent.ACTION_AIRPLANE_MODE_CHANGED);
- boolean isWimaxConfigEnabled = mContext.getResources().getBoolean(
+ mWimaxSupported = mContext.getResources().getBoolean(
com.android.internal.R.bool.config_wimaxEnabled);
- if(isWimaxConfigEnabled) {
+ if(mWimaxSupported) {
filter.addAction(WimaxManagerConstants.WIMAX_NETWORK_STATE_CHANGED_ACTION);
filter.addAction(WimaxManagerConstants.SIGNAL_LEVEL_CHANGED_ACTION);
filter.addAction(WimaxManagerConstants.NET_4G_STATE_CHANGED_ACTION);
@@ -262,19 +263,36 @@
public void addSignalCluster(SignalCluster cluster) {
mSignalClusters.add(cluster);
+ refreshSignalCluster(cluster);
+ }
+
+ public void refreshSignalCluster(SignalCluster cluster) {
cluster.setWifiIndicators(
mWifiConnected, // only show wifi in the cluster if connected
mWifiIconId,
mWifiActivityIconId,
mContentDescriptionWifi);
- cluster.setMobileDataIndicators(
- mHasMobileDataFeature,
- mShowPhoneRSSIForData ? mPhoneSignalIconId : mDataSignalIconId,
- mMobileActivityIconId,
- mDataTypeIconId,
- mContentDescriptionPhoneSignal,
- mContentDescriptionDataType);
+ if (mIsWimaxEnabled && mWimaxConnected) {
+ // wimax is special
+ cluster.setMobileDataIndicators(
+ true,
+ mWimaxIconId,
+ mMobileActivityIconId,
+ mDataTypeIconId,
+ mContentDescriptionWimax,
+ mContentDescriptionDataType);
+ } else {
+ // normal mobile data
+ cluster.setMobileDataIndicators(
+ mHasMobileDataFeature,
+ mShowPhoneRSSIForData ? mPhoneSignalIconId : mDataSignalIconId,
+ mMobileActivityIconId,
+ mDataTypeIconId,
+ mContentDescriptionPhoneSignal,
+ mContentDescriptionDataType);
+ }
+ cluster.setIsAirplaneMode(mAirplaneMode);
}
public void setStackedMode(boolean stacked) {
@@ -311,7 +329,7 @@
} else if (action.equals(WimaxManagerConstants.NET_4G_STATE_CHANGED_ACTION) ||
action.equals(WimaxManagerConstants.SIGNAL_LEVEL_CHANGED_ACTION) ||
action.equals(WimaxManagerConstants.WIMAX_NETWORK_STATE_CHANGED_ACTION)) {
- updateWimaxState(intent);
+ updateWimaxState(intent);
refreshViews();
}
}
@@ -466,91 +484,100 @@
}
private final void updateDataNetType() {
- switch (mDataNetType) {
- case TelephonyManager.NETWORK_TYPE_UNKNOWN:
- if (!mShowAtLeastThreeGees) {
- mDataIconList = TelephonyIcons.DATA_G[mInetCondition];
- mDataTypeIconId = 0;
- mContentDescriptionDataType = mContext.getString(
- R.string.accessibility_data_connection_gprs);
- break;
- } else {
- // fall through
- }
- case TelephonyManager.NETWORK_TYPE_EDGE:
- if (!mShowAtLeastThreeGees) {
- mDataIconList = TelephonyIcons.DATA_E[mInetCondition];
- mDataTypeIconId = R.drawable.stat_sys_data_connected_e;
- mContentDescriptionDataType = mContext.getString(
- R.string.accessibility_data_connection_edge);
- break;
- } else {
- // fall through
- }
- case TelephonyManager.NETWORK_TYPE_UMTS:
- mDataIconList = TelephonyIcons.DATA_3G[mInetCondition];
- mDataTypeIconId = R.drawable.stat_sys_data_connected_3g;
- mContentDescriptionDataType = mContext.getString(
- R.string.accessibility_data_connection_3g);
- break;
- case TelephonyManager.NETWORK_TYPE_HSDPA:
- case TelephonyManager.NETWORK_TYPE_HSUPA:
- case TelephonyManager.NETWORK_TYPE_HSPA:
- case TelephonyManager.NETWORK_TYPE_HSPAP:
- if (mHspaDataDistinguishable) {
- mDataIconList = TelephonyIcons.DATA_H[mInetCondition];
- mDataTypeIconId = R.drawable.stat_sys_data_connected_h;
- mContentDescriptionDataType = mContext.getString(
- R.string.accessibility_data_connection_3_5g);
- } else {
+ if (mIsWimaxEnabled && mWimaxConnected) {
+ // wimax is a special 4g network not handled by telephony
+ mDataIconList = TelephonyIcons.DATA_4G[mInetCondition];
+ mDataTypeIconId = R.drawable.stat_sys_data_connected_4g;
+ mContentDescriptionDataType = mContext.getString(
+ R.string.accessibility_data_connection_4g);
+ } else {
+ switch (mDataNetType) {
+ case TelephonyManager.NETWORK_TYPE_UNKNOWN:
+ if (!mShowAtLeastThreeGees) {
+ mDataIconList = TelephonyIcons.DATA_G[mInetCondition];
+ mDataTypeIconId = 0;
+ mContentDescriptionDataType = mContext.getString(
+ R.string.accessibility_data_connection_gprs);
+ break;
+ } else {
+ // fall through
+ }
+ case TelephonyManager.NETWORK_TYPE_EDGE:
+ if (!mShowAtLeastThreeGees) {
+ mDataIconList = TelephonyIcons.DATA_E[mInetCondition];
+ mDataTypeIconId = R.drawable.stat_sys_data_connected_e;
+ mContentDescriptionDataType = mContext.getString(
+ R.string.accessibility_data_connection_edge);
+ break;
+ } else {
+ // fall through
+ }
+ case TelephonyManager.NETWORK_TYPE_UMTS:
mDataIconList = TelephonyIcons.DATA_3G[mInetCondition];
mDataTypeIconId = R.drawable.stat_sys_data_connected_3g;
mContentDescriptionDataType = mContext.getString(
R.string.accessibility_data_connection_3g);
- }
- break;
- case TelephonyManager.NETWORK_TYPE_CDMA:
- // display 1xRTT for IS95A/B
- mDataIconList = TelephonyIcons.DATA_1X[mInetCondition];
- mDataTypeIconId = R.drawable.stat_sys_data_connected_1x;
- mContentDescriptionDataType = mContext.getString(
- R.string.accessibility_data_connection_cdma);
- break;
- case TelephonyManager.NETWORK_TYPE_1xRTT:
- mDataIconList = TelephonyIcons.DATA_1X[mInetCondition];
- mDataTypeIconId = R.drawable.stat_sys_data_connected_1x;
- mContentDescriptionDataType = mContext.getString(
- R.string.accessibility_data_connection_cdma);
- break;
- case TelephonyManager.NETWORK_TYPE_EVDO_0: //fall through
- case TelephonyManager.NETWORK_TYPE_EVDO_A:
- case TelephonyManager.NETWORK_TYPE_EVDO_B:
- case TelephonyManager.NETWORK_TYPE_EHRPD:
- mDataIconList = TelephonyIcons.DATA_3G[mInetCondition];
- mDataTypeIconId = R.drawable.stat_sys_data_connected_3g;
- mContentDescriptionDataType = mContext.getString(
- R.string.accessibility_data_connection_3g);
- break;
- case TelephonyManager.NETWORK_TYPE_LTE:
- mDataIconList = TelephonyIcons.DATA_4G[mInetCondition];
- mDataTypeIconId = R.drawable.stat_sys_data_connected_4g;
- mContentDescriptionDataType = mContext.getString(
- R.string.accessibility_data_connection_4g);
- break;
- default:
- if (!mShowAtLeastThreeGees) {
- mDataIconList = TelephonyIcons.DATA_G[mInetCondition];
- mDataTypeIconId = R.drawable.stat_sys_data_connected_g;
+ break;
+ case TelephonyManager.NETWORK_TYPE_HSDPA:
+ case TelephonyManager.NETWORK_TYPE_HSUPA:
+ case TelephonyManager.NETWORK_TYPE_HSPA:
+ case TelephonyManager.NETWORK_TYPE_HSPAP:
+ if (mHspaDataDistinguishable) {
+ mDataIconList = TelephonyIcons.DATA_H[mInetCondition];
+ mDataTypeIconId = R.drawable.stat_sys_data_connected_h;
+ mContentDescriptionDataType = mContext.getString(
+ R.string.accessibility_data_connection_3_5g);
+ } else {
+ mDataIconList = TelephonyIcons.DATA_3G[mInetCondition];
+ mDataTypeIconId = R.drawable.stat_sys_data_connected_3g;
+ mContentDescriptionDataType = mContext.getString(
+ R.string.accessibility_data_connection_3g);
+ }
+ break;
+ case TelephonyManager.NETWORK_TYPE_CDMA:
+ // display 1xRTT for IS95A/B
+ mDataIconList = TelephonyIcons.DATA_1X[mInetCondition];
+ mDataTypeIconId = R.drawable.stat_sys_data_connected_1x;
mContentDescriptionDataType = mContext.getString(
- R.string.accessibility_data_connection_gprs);
- } else {
+ R.string.accessibility_data_connection_cdma);
+ break;
+ case TelephonyManager.NETWORK_TYPE_1xRTT:
+ mDataIconList = TelephonyIcons.DATA_1X[mInetCondition];
+ mDataTypeIconId = R.drawable.stat_sys_data_connected_1x;
+ mContentDescriptionDataType = mContext.getString(
+ R.string.accessibility_data_connection_cdma);
+ break;
+ case TelephonyManager.NETWORK_TYPE_EVDO_0: //fall through
+ case TelephonyManager.NETWORK_TYPE_EVDO_A:
+ case TelephonyManager.NETWORK_TYPE_EVDO_B:
+ case TelephonyManager.NETWORK_TYPE_EHRPD:
mDataIconList = TelephonyIcons.DATA_3G[mInetCondition];
mDataTypeIconId = R.drawable.stat_sys_data_connected_3g;
mContentDescriptionDataType = mContext.getString(
R.string.accessibility_data_connection_3g);
- }
- break;
+ break;
+ case TelephonyManager.NETWORK_TYPE_LTE:
+ mDataIconList = TelephonyIcons.DATA_4G[mInetCondition];
+ mDataTypeIconId = R.drawable.stat_sys_data_connected_4g;
+ mContentDescriptionDataType = mContext.getString(
+ R.string.accessibility_data_connection_4g);
+ break;
+ default:
+ if (!mShowAtLeastThreeGees) {
+ mDataIconList = TelephonyIcons.DATA_G[mInetCondition];
+ mDataTypeIconId = R.drawable.stat_sys_data_connected_g;
+ mContentDescriptionDataType = mContext.getString(
+ R.string.accessibility_data_connection_gprs);
+ } else {
+ mDataIconList = TelephonyIcons.DATA_3G[mInetCondition];
+ mDataTypeIconId = R.drawable.stat_sys_data_connected_3g;
+ mContentDescriptionDataType = mContext.getString(
+ R.string.accessibility_data_connection_3g);
+ }
+ break;
+ }
}
+
if ((isCdma() && isCdmaEri()) || mPhone.isNetworkRoaming()) {
mDataTypeIconId = R.drawable.stat_sys_data_connected_roam;
}
@@ -763,8 +790,7 @@
}
- // ===== Wimax ===================================================================
-
+ // ===== Wimax ===================================================================
private final void updateWimaxState(Intent intent) {
final String action = intent.getAction();
boolean wasConnected = mWimaxConnected;
@@ -772,42 +798,41 @@
int wimaxStatus = intent.getIntExtra(WimaxManagerConstants.EXTRA_4G_STATE,
WimaxManagerConstants.NET_4G_STATE_UNKNOWN);
mIsWimaxEnabled = (wimaxStatus ==
- WimaxManagerConstants.NET_4G_STATE_ENABLED)? true : false;
+ WimaxManagerConstants.NET_4G_STATE_ENABLED);
} else if (action.equals(WimaxManagerConstants.SIGNAL_LEVEL_CHANGED_ACTION)) {
mWimaxSignal = intent.getIntExtra(WimaxManagerConstants.EXTRA_NEW_SIGNAL_LEVEL, 0);
} else if (action.equals(WimaxManagerConstants.WIMAX_NETWORK_STATE_CHANGED_ACTION)) {
- mWimaxState = intent.getIntExtra(WimaxManagerConstants.EXTRA_WIMAX_STATE,
+ mWimaxState = intent.getIntExtra(WimaxManagerConstants.EXTRA_WIMAX_STATE,
WimaxManagerConstants.NET_4G_STATE_UNKNOWN);
mWimaxExtraState = intent.getIntExtra(
WimaxManagerConstants.EXTRA_WIMAX_STATE_DETAIL,
WimaxManagerConstants.NET_4G_STATE_UNKNOWN);
mWimaxConnected = (mWimaxState ==
- WimaxManagerConstants.WIMAX_STATE_CONNECTED) ? true : false;
- mWimaxIdle = (mWimaxExtraState == WimaxManagerConstants.WIMAX_IDLE)? true : false;
+ WimaxManagerConstants.WIMAX_STATE_CONNECTED);
+ mWimaxIdle = (mWimaxExtraState == WimaxManagerConstants.WIMAX_IDLE);
}
+ updateDataNetType();
updateWimaxIcons();
}
- private void updateWimaxIcons() {
- Slog.d(TAG, "in .... updateWimaxIcons function : "+mIsWimaxEnabled);
- if (mIsWimaxEnabled) {
- if (mWimaxConnected) {
- Slog.d(TAG, "in .... updateWimaxIcons function WiMAX COnnected");
- if (mWimaxIdle)
- mWimaxIconId = WimaxIcons.WIMAX_IDLE;
- else
- mWimaxIconId = WimaxIcons.WIMAX_SIGNAL_STRENGTH[mInetCondition][mWimaxSignal];
- mContentDescriptionWimax = mContext.getString(
- AccessibilityContentDescriptions.WIMAX_CONNECTION_STRENGTH[mWimaxSignal]);
- } else {
- Slog.d(TAG, "in .... updateWimaxIcons function WiMAX Disconnected");
- mWimaxIconId = WimaxIcons.WIMAX_DISCONNECTED;
- mContentDescriptionWimax = mContext.getString(R.string.accessibility_no_wimax);
- }
- } else {
- Slog.d(TAG, "in .... updateWimaxIcons function wimax icon id 0");
- mWimaxIconId = 0;
- }
+
+ private void updateWimaxIcons() {
+ if (mIsWimaxEnabled) {
+ if (mWimaxConnected) {
+ if (mWimaxIdle)
+ mWimaxIconId = WimaxIcons.WIMAX_IDLE;
+ else
+ mWimaxIconId = WimaxIcons.WIMAX_SIGNAL_STRENGTH[mInetCondition][mWimaxSignal];
+ mContentDescriptionWimax = mContext.getString(
+ AccessibilityContentDescriptions.WIMAX_CONNECTION_STRENGTH[mWimaxSignal]);
+ } else {
+ mWimaxIconId = WimaxIcons.WIMAX_DISCONNECTED;
+ mContentDescriptionWimax = mContext.getString(R.string.accessibility_no_wimax);
+ }
+ } else {
+ mWimaxIconId = 0;
}
+ }
+
// ===== Full or limited Internet connectivity ==================================
private void updateConnectivity(Intent intent) {
@@ -827,14 +852,14 @@
mInetCondition = (connectionStatus > INET_CONDITION_THRESHOLD ? 1 : 0);
if (info != null && info.getType() == ConnectivityManager.TYPE_BLUETOOTH) {
- mBluetoothTethered = info.isConnected() ? true: false;
+ mBluetoothTethered = info.isConnected();
} else {
mBluetoothTethered = false;
}
// We want to update all the icons, all at once, for any condition change
updateDataNetType();
- updateWimaxIcons();
+ updateWimaxIcons();
updateDataIcon();
updateTelephonySignalStrength();
updateWifiIcons();
@@ -921,7 +946,7 @@
combinedSignalIconId = mDataSignalIconId;
}
- else if (!mDataConnected && !mWifiConnected && !mBluetoothTethered) {
+ else if (!mDataConnected && !mWifiConnected && !mBluetoothTethered && !mWimaxConnected) {
// pretty much totally disconnected
label = context.getString(R.string.status_bar_settings_signal_meter_disconnected);
@@ -961,23 +986,12 @@
if (mLastPhoneSignalIconId != mPhoneSignalIconId
|| mLastDataDirectionOverlayIconId != combinedActivityIconId
|| mLastWifiIconId != mWifiIconId
+ || mLastWimaxIconId != mWimaxIconId
|| mLastDataTypeIconId != mDataTypeIconId)
{
// NB: the mLast*s will be updated later
for (SignalCluster cluster : mSignalClusters) {
- cluster.setWifiIndicators(
- mWifiConnected, // only show wifi in the cluster if connected
- mWifiIconId,
- mWifiActivityIconId,
- mContentDescriptionWifi);
- cluster.setMobileDataIndicators(
- mHasMobileDataFeature,
- mShowPhoneRSSIForData ? mPhoneSignalIconId : mDataSignalIconId,
- mMobileActivityIconId,
- mDataTypeIconId,
- mContentDescriptionPhoneSignal,
- mContentDescriptionDataType);
- cluster.setIsAirplaneMode(mAirplaneMode);
+ refreshSignalCluster(cluster);
}
}
@@ -1152,11 +1166,22 @@
pw.println(mWifiLevel);
pw.print(" mWifiSsid=");
pw.println(mWifiSsid);
- pw.print(String.format(" mWifiIconId=0x%08x/%s",
+ pw.println(String.format(" mWifiIconId=0x%08x/%s",
mWifiIconId, getResourceName(mWifiIconId)));
pw.print(" mWifiActivity=");
pw.println(mWifiActivity);
+ if (mWimaxSupported) {
+ pw.println(" - wimax ------");
+ pw.print(" mIsWimaxEnabled="); pw.println(mIsWimaxEnabled);
+ pw.print(" mWimaxConnected="); pw.println(mWimaxConnected);
+ pw.print(" mWimaxIdle="); pw.println(mWimaxIdle);
+ pw.println(String.format(" mWimaxIconId=0x%08x/%s",
+ mWimaxIconId, getResourceName(mWimaxIconId)));
+ pw.println(String.format(" mWimaxSignal=%d", mWimaxSignal));
+ pw.println(String.format(" mWimaxState=%d", mWimaxState));
+ pw.println(String.format(" mWimaxExtraState=%d", mWimaxExtraState));
+ }
pw.println(" - Bluetooth ----");
pw.print(" mBtReverseTethered=");
@@ -1190,7 +1215,7 @@
pw.print(" mLastDataTypeIconId=0x");
pw.print(Integer.toHexString(mLastDataTypeIconId));
pw.print("/");
- pw.println(getResourceName(mLastCombinedSignalIconId));
+ pw.println(getResourceName(mLastDataTypeIconId));
pw.print(" mLastLabel=");
pw.print(mLastLabel);
pw.println("");
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/WimaxIcons.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/WimaxIcons.java
index 8605489..d3d4338 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/WimaxIcons.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/WimaxIcons.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2008 The Android Open Source Project
+ * Copyright (C) 2011 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.
@@ -16,22 +16,13 @@
package com.android.systemui.statusbar.policy;
+import com.android.systemui.statusbar.policy.TelephonyIcons;
import com.android.systemui.R;
class WimaxIcons {
- static final int[][] WIMAX_SIGNAL_STRENGTH = {
- { R.drawable.stat_sys_data_wimax_signal_0,
- R.drawable.stat_sys_data_wimax_signal_1,
- R.drawable.stat_sys_data_wimax_signal_2,
- R.drawable.stat_sys_data_wimax_signal_3 },
- { R.drawable.stat_sys_data_wimax_signal_0_fully,
- R.drawable.stat_sys_data_wimax_signal_1_fully,
- R.drawable.stat_sys_data_wimax_signal_2_fully,
- R.drawable.stat_sys_data_wimax_signal_3_fully }
- };
+ static final int[][] WIMAX_SIGNAL_STRENGTH = TelephonyIcons.DATA_SIGNAL_STRENGTH;
- static final int WIMAX_DISCONNECTED =
- R.drawable.stat_sys_data_wimax_signal_disconnected;
- static final int WIMAX_IDLE = R.drawable.stat_sys_data_wimax_signal_idle;
- static final int WIFI_LEVEL_COUNT = WIMAX_SIGNAL_STRENGTH[0].length;
+ static final int WIMAX_DISCONNECTED = WIMAX_SIGNAL_STRENGTH[0][0];
+
+ static final int WIMAX_IDLE = WIMAX_DISCONNECTED; // XXX: unclear if we need a different icon
}
diff --git a/policy/src/com/android/internal/policy/impl/KeyguardViewMediator.java b/policy/src/com/android/internal/policy/impl/KeyguardViewMediator.java
index c802bc1..b514689 100644
--- a/policy/src/com/android/internal/policy/impl/KeyguardViewMediator.java
+++ b/policy/src/com/android/internal/policy/impl/KeyguardViewMediator.java
@@ -830,12 +830,13 @@
* action should be posted to a handler.
*
* @param keyCode The keycode of the key that woke the device
+ * @param isDocked True if the device is in the dock
* @return Whether we poked the wake lock (and turned the screen on)
*/
- public boolean onWakeKeyWhenKeyguardShowingTq(int keyCode) {
+ public boolean onWakeKeyWhenKeyguardShowingTq(int keyCode, boolean isDocked) {
if (DEBUG) Log.d(TAG, "onWakeKeyWhenKeyguardShowing(" + keyCode + ")");
- if (isWakeKeyWhenKeyguardShowing(keyCode)) {
+ if (isWakeKeyWhenKeyguardShowing(keyCode, isDocked)) {
// give the keyguard view manager a chance to adjust the state of the
// keyguard based on the key that woke the device before poking
// the wake lock
@@ -846,11 +847,22 @@
}
}
- private boolean isWakeKeyWhenKeyguardShowing(int keyCode) {
+ /**
+ * When the keyguard is showing we ignore some keys that might otherwise typically
+ * be considered wake keys. We filter them out here.
+ *
+ * {@link KeyEvent#KEYCODE_POWER} is notably absent from this list because it
+ * is always considered a wake key.
+ */
+ private boolean isWakeKeyWhenKeyguardShowing(int keyCode, boolean isDocked) {
switch (keyCode) {
+ // ignore volume keys unless docked
case KeyEvent.KEYCODE_VOLUME_UP:
case KeyEvent.KEYCODE_VOLUME_DOWN:
case KeyEvent.KEYCODE_VOLUME_MUTE:
+ return isDocked;
+
+ // ignore media and camera keys
case KeyEvent.KEYCODE_MUTE:
case KeyEvent.KEYCODE_HEADSETHOOK:
case KeyEvent.KEYCODE_MEDIA_PLAY:
diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
index aa1c81c..921f331 100755
--- a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
+++ b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
@@ -360,6 +360,9 @@
int mResettingSystemUiFlags = 0;
// Bits that we are currently always keeping cleared.
int mForceClearedSystemUiFlags = 0;
+ // What we last reported to system UI about whether the compatibility
+ // menu needs to be displayed.
+ boolean mLastFocusNeedsMenu = false;
FakeWindow mHideNavFakeWindow = null;
@@ -370,8 +373,6 @@
static final Rect mTmpNavigationFrame = new Rect();
WindowState mTopFullscreenOpaqueWindowState;
- WindowState mTopAppWindowState;
- WindowState mLastTopAppWindowState;
boolean mTopIsFullscreen;
boolean mForceStatusBar;
boolean mHideLockScreen;
@@ -1184,7 +1185,13 @@
}
public int getConfigDisplayHeight(int fullWidth, int fullHeight, int rotation) {
- return getNonDecorDisplayHeight(fullWidth, fullHeight, rotation);
+ // This is the same as getNonDecorDisplayHeight, unless the status bar
+ // can hide. If the status bar can hide, we don't count that as part
+ // of the decor; however for purposes of configurations, we do want to
+ // exclude it since applications can't generally use that part of the
+ // screen.
+ return getNonDecorDisplayHeight(fullWidth, fullHeight, rotation)
+ - (mStatusBarCanHide ? mStatusBarHeight : 0);
}
public boolean doesForceHide(WindowState win, WindowManager.LayoutParams attrs) {
@@ -2244,7 +2251,6 @@
/** {@inheritDoc} */
public void beginAnimationLw(int displayWidth, int displayHeight) {
mTopFullscreenOpaqueWindowState = null;
- mTopAppWindowState = null;
mForceStatusBar = false;
mHideLockScreen = false;
@@ -2282,12 +2288,6 @@
}
}
}
- if (mTopAppWindowState == null && win.isVisibleOrBehindKeyguardLw()) {
- if (attrs.type >= FIRST_APPLICATION_WINDOW
- && attrs.type <= LAST_APPLICATION_WINDOW) {
- mTopAppWindowState = win;
- }
- }
}
/** {@inheritDoc} */
@@ -2343,35 +2343,6 @@
mTopIsFullscreen = topIsFullscreen;
- if (mTopAppWindowState != null && mTopAppWindowState != mLastTopAppWindowState) {
- mLastTopAppWindowState = mTopAppWindowState;
-
- final boolean topNeedsMenu = (mTopAppWindowState.getAttrs().flags
- & WindowManager.LayoutParams.FLAG_NEEDS_MENU_KEY) != 0;
-
- mHandler.post(new Runnable() {
- public void run() {
- if (mStatusBarService == null) {
- // This is the one that can not go away, but it doesn't come up
- // before the window manager does, so don't fail if it doesn't
- // exist. This works as long as no fullscreen windows come up
- // before the status bar service does.
- mStatusBarService = IStatusBarService.Stub.asInterface(
- ServiceManager.getService("statusbar"));
- }
- final IStatusBarService sbs = mStatusBarService;
- if (mStatusBarService != null) {
- try {
- sbs.topAppWindowChanged(topNeedsMenu);
- } catch (RemoteException e) {
- // This should be impossible because we're in the same process.
- mStatusBarService = null;
- }
- }
- }
- });
- }
-
// Hide the key guard if a visible window explicitly specifies that it wants to be displayed
// when the screen is locked
if (mKeyguard != null) {
@@ -2480,7 +2451,7 @@
// keyguard, then we need to have it turn on the
// screen once it is shown.
mKeyguardMediator.onWakeKeyWhenKeyguardShowingTq(
- KeyEvent.KEYCODE_POWER);
+ KeyEvent.KEYCODE_POWER, mDockMode != Intent.EXTRA_DOCK_STATE_UNDOCKED);
}
} else {
// Light up the keyboard if we are sliding up.
@@ -2700,7 +2671,8 @@
if (down && isWakeKey) {
if (keyguardActive) {
// If the keyguard is showing, let it decide what to do with the wake key.
- mKeyguardMediator.onWakeKeyWhenKeyguardShowingTq(keyCode);
+ mKeyguardMediator.onWakeKeyWhenKeyguardShowingTq(keyCode,
+ mDockMode != Intent.EXTRA_DOCK_STATE_UNDOCKED);
} else {
// Otherwise, wake the device ourselves.
result |= ACTION_POKE_USER_ACTIVITY;
@@ -3704,10 +3676,13 @@
& ~mResettingSystemUiFlags
& ~mForceClearedSystemUiFlags;
int diff = visibility ^ mLastSystemUiFlags;
- if (diff == 0) {
+ final boolean needsMenu = (mFocusedWindow.getAttrs().flags
+ & WindowManager.LayoutParams.FLAG_NEEDS_MENU_KEY) != 0;
+ if (diff == 0 && mLastFocusNeedsMenu == needsMenu) {
return 0;
}
mLastSystemUiFlags = visibility;
+ mLastFocusNeedsMenu = needsMenu;
mHandler.post(new Runnable() {
public void run() {
if (mStatusBarService == null) {
@@ -3717,6 +3692,7 @@
if (mStatusBarService != null) {
try {
mStatusBarService.setSystemUiVisibility(visibility);
+ mStatusBarService.topAppWindowChanged(needsMenu);
} catch (RemoteException e) {
// not much to be done
mStatusBarService = null;
@@ -3749,6 +3725,10 @@
pw.print(" mForceClearedSystemUiFlags=0x");
pw.println(Integer.toHexString(mForceClearedSystemUiFlags));
}
+ if (mLastFocusNeedsMenu) {
+ pw.print(prefix); pw.print("mLastFocusNeedsMenu=");
+ pw.println(mLastFocusNeedsMenu);
+ }
pw.print(prefix); pw.print("mUiMode="); pw.print(mUiMode);
pw.print(" mDockMode="); pw.print(mDockMode);
pw.print(" mCarDockRotation="); pw.print(mCarDockRotation);
diff --git a/services/audioflinger/AudioFlinger.cpp b/services/audioflinger/AudioFlinger.cpp
index ff262f1..780c0d2 100644
--- a/services/audioflinger/AudioFlinger.cpp
+++ b/services/audioflinger/AudioFlinger.cpp
@@ -7028,11 +7028,17 @@
AudioFlinger::EffectChain::EffectChain(const wp<ThreadBase>& wThread,
int sessionId)
- : mThread(wThread), mSessionId(sessionId), mActiveTrackCnt(0), mTrackCnt(0),
+ : mThread(wThread), mSessionId(sessionId), mActiveTrackCnt(0), mTrackCnt(0), mTailBufferCount(0),
mOwnInBuffer(false), mVolumeCtrlIdx(-1), mLeftVolume(UINT_MAX), mRightVolume(UINT_MAX),
mNewLeftVolume(UINT_MAX), mNewRightVolume(UINT_MAX)
{
mStrategy = AudioSystem::getStrategyForStream(AUDIO_STREAM_MUSIC);
+ sp<ThreadBase> thread = mThread.promote();
+ if (thread == 0) {
+ return;
+ }
+ mMaxTailBuffers = ((kProcessTailDurationMs * thread->sampleRate()) / 1000) /
+ thread->frameCount();
}
AudioFlinger::EffectChain::~EffectChain()
@@ -7100,22 +7106,31 @@
}
bool isGlobalSession = (mSessionId == AUDIO_SESSION_OUTPUT_MIX) ||
(mSessionId == AUDIO_SESSION_OUTPUT_STAGE);
- bool tracksOnSession = false;
+ // always process effects unless no more tracks are on the session and the effect tail
+ // has been rendered
+ bool doProcess = true;
if (!isGlobalSession) {
- tracksOnSession = (trackCnt() != 0);
- }
+ bool tracksOnSession = (trackCnt() != 0);
- // if no track is active, input buffer must be cleared here as the mixer process
- // will not do it
- if (tracksOnSession &&
- activeTrackCnt() == 0) {
- size_t numSamples = thread->frameCount() * thread->channelCount();
- memset(mInBuffer, 0, numSamples * sizeof(int16_t));
+ if (!tracksOnSession && mTailBufferCount == 0) {
+ doProcess = false;
+ }
+
+ if (activeTrackCnt() == 0) {
+ // if no track is active and the effect tail has not been rendered,
+ // the input buffer must be cleared here as the mixer process will not do it
+ if (tracksOnSession || mTailBufferCount > 0) {
+ size_t numSamples = thread->frameCount() * thread->channelCount();
+ memset(mInBuffer, 0, numSamples * sizeof(int16_t));
+ if (mTailBufferCount > 0) {
+ mTailBufferCount--;
+ }
+ }
+ }
}
size_t size = mEffects.size();
- // do not process effect if no track is present in same audio session
- if (isGlobalSession || tracksOnSession) {
+ if (doProcess) {
for (size_t i = 0; i < size; i++) {
mEffects[i]->process();
}
diff --git a/services/audioflinger/AudioFlinger.h b/services/audioflinger/AudioFlinger.h
index 4b794ef..897bc78 100644
--- a/services/audioflinger/AudioFlinger.h
+++ b/services/audioflinger/AudioFlinger.h
@@ -1247,6 +1247,10 @@
// corresponding to a suspend all request.
static const int kKeyForSuspendAll = 0;
+ // minimum duration during which we force calling effect process when last track on
+ // a session is stopped or removed to allow effect tail to be rendered
+ static const int kProcessTailDurationMs = 1000;
+
void process_l();
void lock() {
@@ -1287,7 +1291,8 @@
void decTrackCnt() { android_atomic_dec(&mTrackCnt); }
int32_t trackCnt() { return mTrackCnt;}
- void incActiveTrackCnt() { android_atomic_inc(&mActiveTrackCnt); }
+ void incActiveTrackCnt() { android_atomic_inc(&mActiveTrackCnt);
+ mTailBufferCount = mMaxTailBuffers; }
void decActiveTrackCnt() { android_atomic_dec(&mActiveTrackCnt); }
int32_t activeTrackCnt() { return mActiveTrackCnt;}
@@ -1338,6 +1343,8 @@
int16_t *mOutBuffer; // chain output buffer
volatile int32_t mActiveTrackCnt; // number of active tracks connected
volatile int32_t mTrackCnt; // number of tracks connected
+ int32_t mTailBufferCount; // current effect tail buffer count
+ int32_t mMaxTailBuffers; // maximum effect tail buffers
bool mOwnInBuffer; // true if the chain owns its input buffer
int mVolumeCtrlIdx; // index of insert effect having control over volume
uint32_t mLeftVolume; // previous volume on left channel
diff --git a/services/java/com/android/server/ConnectivityService.java b/services/java/com/android/server/ConnectivityService.java
index 4af6112..6e4aca7 100644
--- a/services/java/com/android/server/ConnectivityService.java
+++ b/services/java/com/android/server/ConnectivityService.java
@@ -514,7 +514,9 @@
continue;
}
mCurrentLinkProperties[netType] = null;
- if (mNetConfigs[netType].isDefault()) mNetTrackers[netType].reconnect();
+ if (mNetTrackers[netType] != null && mNetConfigs[netType].isDefault()) {
+ mNetTrackers[netType].reconnect();
+ }
}
IBinder b = ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE);
@@ -1595,6 +1597,7 @@
if (checkType == prevNetType) continue;
if (mNetConfigs[checkType] == null) continue;
if (!mNetConfigs[checkType].isDefault()) continue;
+ if (mNetTrackers[checkType] == null) continue;
// Enabling the isAvailable() optimization caused mobile to not get
// selected if it was in the middle of error handling. Specifically
diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java
index 05d42ada..cd63090 100644
--- a/services/java/com/android/server/am/ActivityManagerService.java
+++ b/services/java/com/android/server/am/ActivityManagerService.java
@@ -1669,7 +1669,7 @@
final void setFocusedActivityLocked(ActivityRecord r) {
if (mFocusedActivity != r) {
mFocusedActivity = r;
- mWindowManager.setFocusedApp(r, true);
+ mWindowManager.setFocusedApp(r.appToken, true);
}
}
@@ -2346,7 +2346,8 @@
// XXX we are not dealing with propagating grantedUriPermissions...
// those are not yet exposed to user code, so there is no need.
int res = mMainStack.startActivityLocked(r.app.thread, intent,
- r.resolvedType, null, 0, aInfo, resultTo, resultWho,
+ r.resolvedType, null, 0, aInfo,
+ resultTo != null ? resultTo.appToken : null, resultWho,
requestCode, -1, r.launchedFromUid, false, false, null);
Binder.restoreCallingIdentity(origId);
@@ -2429,10 +2430,10 @@
return;
}
final long origId = Binder.clearCallingIdentity();
- mWindowManager.setAppOrientation(r, requestedOrientation);
+ mWindowManager.setAppOrientation(r.appToken, requestedOrientation);
Configuration config = mWindowManager.updateOrientationFromAppTokens(
mConfiguration,
- r.mayFreezeScreenLocked(r.app) ? r : null);
+ r.mayFreezeScreenLocked(r.app) ? r.appToken : null);
if (config != null) {
r.frozenBeforeDestroy = true;
if (!updateConfigurationLocked(config, r, false)) {
@@ -2449,7 +2450,7 @@
if (r == null) {
return ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
}
- return mWindowManager.getAppOrientation(r);
+ return mWindowManager.getAppOrientation(r.appToken);
}
}
@@ -2515,7 +2516,7 @@
for (int i=0; i<activities.size(); i++) {
ActivityRecord r = activities.get(i);
if (!r.finishing) {
- int index = mMainStack.indexOfTokenLocked(r);
+ int index = mMainStack.indexOfTokenLocked(r.appToken);
if (index >= 0) {
mMainStack.finishActivityLocked(r, index, Activity.RESULT_CANCELED,
null, "finish-heavy");
@@ -2617,7 +2618,7 @@
int i;
for (i=mMainStack.mHistory.size()-1; i>=0; i--) {
ActivityRecord r = (ActivityRecord)mMainStack.mHistory.get(i);
- if (r == token) {
+ if (r.appToken == token) {
return true;
}
if (r.fullscreen && !r.finishing) {
@@ -2705,9 +2706,9 @@
r.makeFinishing();
mMainStack.mHistory.remove(i);
r.takeFromHistory();
- mWindowManager.removeAppToken(r);
+ mWindowManager.removeAppToken(r.appToken);
if (VALIDATE_TOKENS) {
- mWindowManager.validateAppTokens(mMainStack.mHistory);
+ mMainStack.validateAppTokensLocked();
}
r.removeUriPermissionsLocked();
@@ -5173,10 +5174,10 @@
if (topThumbnail != null) {
if (localLOGV) Slog.v(TAG, "Requesting top thumbnail");
try {
- topThumbnail.requestThumbnail(topRecord);
+ topThumbnail.requestThumbnail(topRecord.appToken);
} catch (Exception e) {
Slog.w(TAG, "Exception thrown when requesting thumbnail", e);
- sendPendingThumbnail(null, topRecord, null, null, true);
+ sendPendingThumbnail(null, topRecord.appToken, null, null, true);
}
}
@@ -5547,7 +5548,7 @@
TaskRecord lastTask = null;
for (int i=0; i<N; i++) {
ActivityRecord r = (ActivityRecord)mMainStack.mHistory.get(i);
- if (r == token) {
+ if (r.appToken == token) {
if (!onlyRoot || lastTask != r.task) {
return r.task.taskId;
}
@@ -5568,7 +5569,7 @@
for (int i=0; i<N; i++) {
ActivityRecord r = (ActivityRecord)mMainStack.mHistory.get(i);
if (r.realActivity.equals(className)
- && r != token && lastTask != r.task) {
+ && r.appToken != token && lastTask != r.task) {
if (r.stack.finishActivityLocked(r, i, Activity.RESULT_CANCELED,
null, "others")) {
i--;
@@ -7112,7 +7113,7 @@
// process, then terminate it to avoid getting in a loop.
Slog.w(TAG, " Force finishing activity "
+ r.intent.getComponent().flattenToShortString());
- int index = mMainStack.indexOfTokenLocked(r);
+ int index = mMainStack.indexOfActivityLocked(r);
r.stack.finishActivityLocked(r, index,
Activity.RESULT_CANCELED, null, "crashed");
// Also terminate any activities below it that aren't yet
@@ -8631,8 +8632,8 @@
try {
TransferPipe tp = new TransferPipe();
try {
- r.app.thread.dumpActivity(tp.getWriteFd().getFileDescriptor(), r,
- innerPrefix, args);
+ r.app.thread.dumpActivity(tp.getWriteFd().getFileDescriptor(),
+ r.appToken, innerPrefix, args);
tp.go(fd);
} finally {
tp.kill();
@@ -9048,8 +9049,8 @@
try {
TransferPipe tp = new TransferPipe();
try {
- r.app.thread.dumpActivity(tp.getWriteFd().getFileDescriptor(), r,
- innerPrefix, args);
+ r.app.thread.dumpActivity(tp.getWriteFd().getFileDescriptor(),
+ r.appToken, innerPrefix, args);
// Short timeout, since blocking here can
// deadlock with the application.
tp.go(fd, 2000);
diff --git a/services/java/com/android/server/am/ActivityRecord.java b/services/java/com/android/server/am/ActivityRecord.java
index 00e6cb2..951a946 100644
--- a/services/java/com/android/server/am/ActivityRecord.java
+++ b/services/java/com/android/server/am/ActivityRecord.java
@@ -29,6 +29,7 @@
import android.graphics.Bitmap;
import android.os.Build;
import android.os.Bundle;
+import android.os.IBinder;
import android.os.Message;
import android.os.Process;
import android.os.RemoteException;
@@ -48,9 +49,10 @@
/**
* An entry in the history stack, representing an activity.
*/
-final class ActivityRecord extends IApplicationToken.Stub {
+final class ActivityRecord {
final ActivityManagerService service; // owner
final ActivityStack stack; // owner
+ final IApplicationToken.Stub appToken; // window manager token
final ActivityInfo info; // all about me
final int launchedFromUid; // always the uid who started the activity.
final Intent intent; // the original intent that generated us
@@ -200,6 +202,70 @@
}
}
+ static class Token extends IApplicationToken.Stub {
+ final WeakReference<ActivityRecord> weakActivity;
+
+ Token(ActivityRecord activity) {
+ weakActivity = new WeakReference<ActivityRecord>(activity);
+ }
+
+ @Override public void windowsDrawn() throws RemoteException {
+ ActivityRecord activity = weakActivity.get();
+ if (activity != null) {
+ activity.windowsDrawn();
+ }
+ }
+
+ @Override public void windowsVisible() throws RemoteException {
+ ActivityRecord activity = weakActivity.get();
+ if (activity != null) {
+ activity.windowsVisible();
+ }
+ }
+
+ @Override public void windowsGone() throws RemoteException {
+ ActivityRecord activity = weakActivity.get();
+ if (activity != null) {
+ activity.windowsGone();
+ }
+ }
+
+ @Override public boolean keyDispatchingTimedOut() throws RemoteException {
+ ActivityRecord activity = weakActivity.get();
+ if (activity != null) {
+ return activity.keyDispatchingTimedOut();
+ }
+ return false;
+ }
+
+ @Override public long getKeyDispatchingTimeout() throws RemoteException {
+ ActivityRecord activity = weakActivity.get();
+ if (activity != null) {
+ return activity.getKeyDispatchingTimeout();
+ }
+ return 0;
+ }
+
+ public String toString() {
+ StringBuilder sb = new StringBuilder(128);
+ sb.append("Token{");
+ sb.append(Integer.toHexString(System.identityHashCode(this)));
+ sb.append(' ');
+ sb.append(weakActivity.get());
+ sb.append('}');
+ return sb.toString();
+ }
+ }
+
+ static ActivityRecord forToken(IBinder token) {
+ try {
+ return token != null ? ((Token)token).weakActivity.get() : null;
+ } catch (ClassCastException e) {
+ Slog.w(ActivityManagerService.TAG, "Bad activity token: " + token, e);
+ return null;
+ }
+ }
+
ActivityRecord(ActivityManagerService _service, ActivityStack _stack, ProcessRecord _caller,
int _launchedFromUid, Intent _intent, String _resolvedType,
ActivityInfo aInfo, Configuration _configuration,
@@ -207,6 +273,7 @@
boolean _componentSpecified) {
service = _service;
stack = _stack;
+ appToken = new Token(this);
info = aInfo;
launchedFromUid = _launchedFromUid;
intent = _intent;
@@ -445,7 +512,7 @@
ar.add(intent);
service.grantUriPermissionFromIntentLocked(callingUid, packageName,
intent, getUriPermissionsLocked());
- app.thread.scheduleNewIntent(ar, this);
+ app.thread.scheduleNewIntent(ar, appToken);
sent = true;
} catch (RemoteException e) {
Slog.w(ActivityManagerService.TAG,
@@ -470,14 +537,14 @@
void pauseKeyDispatchingLocked() {
if (!keysPaused) {
keysPaused = true;
- service.mWindowManager.pauseKeyDispatching(this);
+ service.mWindowManager.pauseKeyDispatching(appToken);
}
}
void resumeKeyDispatchingLocked() {
if (keysPaused) {
keysPaused = false;
- service.mWindowManager.resumeKeyDispatching(this);
+ service.mWindowManager.resumeKeyDispatching(appToken);
}
}
@@ -512,14 +579,14 @@
public void startFreezingScreenLocked(ProcessRecord app, int configChanges) {
if (mayFreezeScreenLocked(app)) {
- service.mWindowManager.startAppFreezingScreen(this, configChanges);
+ service.mWindowManager.startAppFreezingScreen(appToken, configChanges);
}
}
public void stopFreezingScreenLocked(boolean force) {
if (force || frozenBeforeDestroy) {
frozenBeforeDestroy = false;
- service.mWindowManager.stopAppFreezingScreen(this, force);
+ service.mWindowManager.stopAppFreezingScreen(appToken, force);
}
}
@@ -687,7 +754,7 @@
}
if (app != null && app.thread != null) {
try {
- app.thread.scheduleSleeping(this, _sleeping);
+ app.thread.scheduleSleeping(appToken, _sleeping);
if (sleeping && !stack.mGoingToSleepActivities.contains(this)) {
stack.mGoingToSleepActivities.add(this);
}
diff --git a/services/java/com/android/server/am/ActivityStack.java b/services/java/com/android/server/am/ActivityStack.java
index 8435eaa..c892cb1 100644
--- a/services/java/com/android/server/am/ActivityStack.java
+++ b/services/java/com/android/server/am/ActivityStack.java
@@ -145,7 +145,12 @@
* running) activities. It contains HistoryRecord objects.
*/
final ArrayList<ActivityRecord> mHistory = new ArrayList<ActivityRecord>();
-
+
+ /**
+ * Used for validating app tokens with window manager.
+ */
+ final ArrayList<IBinder> mValidateAppTokens = new ArrayList<IBinder>();
+
/**
* List of running activities, sorted by recent usage.
* The first entry in the list is the least recently used.
@@ -294,11 +299,11 @@
}
} break;
case PAUSE_TIMEOUT_MSG: {
- IBinder token = (IBinder)msg.obj;
+ ActivityRecord r = (ActivityRecord)msg.obj;
// We don't at this point know if the activity is fullscreen,
// so we need to be conservative and assume it isn't.
- Slog.w(TAG, "Activity pause timeout for " + token);
- activityPaused(token, true);
+ Slog.w(TAG, "Activity pause timeout for " + r);
+ activityPaused(r != null ? r.appToken : null, true);
} break;
case IDLE_TIMEOUT_MSG: {
if (mService.mDidDexOpt) {
@@ -310,20 +315,20 @@
}
// We don't at this point know if the activity is fullscreen,
// so we need to be conservative and assume it isn't.
- IBinder token = (IBinder)msg.obj;
- Slog.w(TAG, "Activity idle timeout for " + token);
- activityIdleInternal(token, true, null);
+ ActivityRecord r = (ActivityRecord)msg.obj;
+ Slog.w(TAG, "Activity idle timeout for " + r);
+ activityIdleInternal(r != null ? r.appToken : null, true, null);
} break;
case DESTROY_TIMEOUT_MSG: {
- IBinder token = (IBinder)msg.obj;
+ ActivityRecord r = (ActivityRecord)msg.obj;
// We don't at this point know if the activity is fullscreen,
// so we need to be conservative and assume it isn't.
- Slog.w(TAG, "Activity destroy timeout for " + token);
- activityDestroyed(token);
+ Slog.w(TAG, "Activity destroy timeout for " + r);
+ activityDestroyed(r != null ? r.appToken : null);
} break;
case IDLE_NOW_MSG: {
- IBinder token = (IBinder)msg.obj;
- activityIdleInternal(token, false, null);
+ ActivityRecord r = (ActivityRecord)msg.obj;
+ activityIdleInternal(r != null ? r.appToken : null, false, null);
} break;
case LAUNCH_TIMEOUT_MSG: {
if (mService.mDidDexOpt) {
@@ -397,7 +402,7 @@
while (i >= 0) {
ActivityRecord r = mHistory.get(i);
// Note: the taskId check depends on real taskId fields being non-zero
- if (!r.finishing && (token != r) && (taskId != r.task.taskId)) {
+ if (!r.finishing && (token != r.appToken) && (taskId != r.task.taskId)) {
return r;
}
i--;
@@ -406,23 +411,17 @@
}
final int indexOfTokenLocked(IBinder token) {
- try {
- ActivityRecord r = (ActivityRecord)token;
- return mHistory.indexOf(r);
- } catch (ClassCastException e) {
- Slog.w(TAG, "Bad activity token: " + token, e);
- return -1;
- }
+ return mHistory.indexOf(ActivityRecord.forToken(token));
+ }
+
+ final int indexOfActivityLocked(ActivityRecord r) {
+ return mHistory.indexOf(r);
}
final ActivityRecord isInStackLocked(IBinder token) {
- try {
- ActivityRecord r = (ActivityRecord)token;
- if (mHistory.contains(r)) {
- return r;
- }
- } catch (ClassCastException e) {
- Slog.w(TAG, "Bad activity token: " + token, e);
+ ActivityRecord r = ActivityRecord.forToken(token);
+ if (mHistory.contains(r)) {
+ return r;
}
return null;
}
@@ -517,7 +516,7 @@
throws RemoteException {
r.startFreezingScreenLocked(app, 0);
- mService.mWindowManager.setAppVisibility(r, true);
+ mService.mWindowManager.setAppVisibility(r.appToken, true);
// Have the window manager re-evaluate the orientation of
// the screen based on the new activity order. Note that
@@ -528,7 +527,7 @@
if (checkConfig) {
Configuration config = mService.mWindowManager.updateOrientationFromAppTokens(
mService.mConfiguration,
- r.mayFreezeScreenLocked(app) ? r : null);
+ r.mayFreezeScreenLocked(app) ? r.appToken : null);
mService.updateConfigurationLocked(config, r, false);
}
@@ -590,7 +589,7 @@
profileFd = null;
}
}
- app.thread.scheduleLaunchActivity(new Intent(r.intent), r,
+ app.thread.scheduleLaunchActivity(new Intent(r.intent), r.appToken,
System.identityHashCode(r), r.info, mService.mConfiguration,
r.compat, r.icicle, results, newIntents, !andResume,
mService.isNextTransitionForward(), profileFile, profileFd,
@@ -624,7 +623,7 @@
+ r.intent.getComponent().flattenToShortString()
+ ", giving up", e);
mService.appDiedLocked(app, app.pid, app.thread);
- requestFinishActivityLocked(r, Activity.RESULT_CANCELED, null,
+ requestFinishActivityLocked(r.appToken, Activity.RESULT_CANCELED, null,
"2nd-crash");
return false;
}
@@ -821,7 +820,7 @@
}
if (w > 0) {
- return mService.mWindowManager.screenshotApplications(who, w, h);
+ return mService.mWindowManager.screenshotApplications(who.appToken, w, h);
}
return null;
}
@@ -856,8 +855,8 @@
EventLog.writeEvent(EventLogTags.AM_PAUSE_ACTIVITY,
System.identityHashCode(prev),
prev.shortComponentName);
- prev.app.thread.schedulePauseActivity(prev, prev.finishing, userLeaving,
- prev.configChangeFlags);
+ prev.app.thread.schedulePauseActivity(prev.appToken, prev.finishing,
+ userLeaving, prev.configChangeFlags);
if (mMainStack) {
mService.updateUsageStats(prev, false);
}
@@ -1129,7 +1128,7 @@
if (!r.visible) {
if (DEBUG_VISBILITY) Slog.v(
TAG, "Starting and making visible: " + r);
- mService.mWindowManager.setAppVisibility(r, true);
+ mService.mWindowManager.setAppVisibility(r.appToken, true);
}
if (r != starting) {
startSpecificActivityLocked(r, false, false);
@@ -1153,10 +1152,10 @@
if (DEBUG_VISBILITY) Slog.v(
TAG, "Making visible and scheduling visibility: " + r);
try {
- mService.mWindowManager.setAppVisibility(r, true);
+ mService.mWindowManager.setAppVisibility(r.appToken, true);
r.sleeping = false;
r.app.pendingUiClean = true;
- r.app.thread.scheduleWindowVisibility(r, true);
+ r.app.thread.scheduleWindowVisibility(r.appToken, true);
r.stopFreezingScreenLocked(false);
} catch (Exception e) {
// Just skip on any failure; we'll make it
@@ -1195,13 +1194,13 @@
TAG, "Making invisible: " + r);
r.visible = false;
try {
- mService.mWindowManager.setAppVisibility(r, false);
+ mService.mWindowManager.setAppVisibility(r.appToken, false);
if ((r.state == ActivityState.STOPPING
|| r.state == ActivityState.STOPPED)
&& r.app != null && r.app.thread != null) {
if (DEBUG_VISBILITY) Slog.v(
TAG, "Scheduling invisibility: " + r);
- r.app.thread.scheduleWindowVisibility(r, false);
+ r.app.thread.scheduleWindowVisibility(r.appToken, false);
}
} catch (Exception e) {
// Just skip on any failure; we'll make it
@@ -1351,7 +1350,7 @@
// previous should actually be hidden depending on whether the
// new one is found to be full-screen or not.
if (prev.finishing) {
- mService.mWindowManager.setAppVisibility(prev, false);
+ mService.mWindowManager.setAppVisibility(prev.appToken, false);
if (DEBUG_SWITCH) Slog.v(TAG, "Not waiting for visible to hide: "
+ prev + ", waitingVisible="
+ (prev != null ? prev.waitingVisible : null)
@@ -1399,8 +1398,8 @@
? WindowManagerPolicy.TRANSIT_ACTIVITY_CLOSE
: WindowManagerPolicy.TRANSIT_TASK_CLOSE, false);
}
- mService.mWindowManager.setAppWillBeHidden(prev);
- mService.mWindowManager.setAppVisibility(prev, false);
+ mService.mWindowManager.setAppWillBeHidden(prev.appToken);
+ mService.mWindowManager.setAppVisibility(prev.appToken, false);
} else {
if (DEBUG_TRANSITION) Slog.v(TAG,
"Prepare open transition: prev=" + prev);
@@ -1414,8 +1413,8 @@
}
}
if (false) {
- mService.mWindowManager.setAppWillBeHidden(prev);
- mService.mWindowManager.setAppVisibility(prev, false);
+ mService.mWindowManager.setAppWillBeHidden(prev.appToken);
+ mService.mWindowManager.setAppVisibility(prev.appToken, false);
}
} else if (mHistory.size() > 1) {
if (DEBUG_TRANSITION) Slog.v(TAG,
@@ -1433,7 +1432,7 @@
if (DEBUG_SWITCH) Slog.v(TAG, "Resume running: " + next);
// This activity is now becoming visible.
- mService.mWindowManager.setAppVisibility(next, true);
+ mService.mWindowManager.setAppVisibility(next.appToken, true);
ActivityRecord lastResumedActivity = mResumedActivity;
ActivityState lastState = next.state;
@@ -1457,7 +1456,7 @@
synchronized (mService) {
Configuration config = mService.mWindowManager.updateOrientationFromAppTokens(
mService.mConfiguration,
- next.mayFreezeScreenLocked(next.app) ? next : null);
+ next.mayFreezeScreenLocked(next.app) ? next.appToken : null);
if (config != null) {
next.frozenBeforeDestroy = true;
}
@@ -1496,12 +1495,12 @@
if (DEBUG_RESULTS) Slog.v(
TAG, "Delivering results to " + next
+ ": " + a);
- next.app.thread.scheduleSendResult(next, a);
+ next.app.thread.scheduleSendResult(next.appToken, a);
}
}
if (next.newIntents != null) {
- next.app.thread.scheduleNewIntent(next.newIntents, next);
+ next.app.thread.scheduleNewIntent(next.newIntents, next.appToken);
}
EventLog.writeEvent(EventLogTags.AM_RESUME_ACTIVITY,
@@ -1511,7 +1510,7 @@
next.sleeping = false;
showAskCompatModeDialogLocked(next);
next.app.pendingUiClean = true;
- next.app.thread.scheduleResumeActivity(next,
+ next.app.thread.scheduleResumeActivity(next.appToken,
mService.isNextTransitionForward());
checkReadyForSleepLocked();
@@ -1528,7 +1527,7 @@
} else {
if (SHOW_APP_STARTING_PREVIEW && mMainStack) {
mService.mWindowManager.setAppStartingWindow(
- next, next.packageName, next.theme,
+ next.appToken, next.packageName, next.theme,
mService.compatibilityInfoForPackageLocked(
next.info.applicationInfo),
next.nonLocalizedLabel,
@@ -1549,7 +1548,7 @@
// If any exception gets thrown, toss away this
// activity and try the next one.
Slog.w(TAG, "Exception thrown during resume of " + next, e);
- requestFinishActivityLocked(next, Activity.RESULT_CANCELED, null,
+ requestFinishActivityLocked(next.appToken, Activity.RESULT_CANCELED, null,
"resume-exception");
return true;
}
@@ -1567,7 +1566,7 @@
} else {
if (SHOW_APP_STARTING_PREVIEW) {
mService.mWindowManager.setAppStartingWindow(
- next, next.packageName, next.theme,
+ next.appToken, next.packageName, next.theme,
mService.compatibilityInfoForPackageLocked(
next.info.applicationInfo),
next.nonLocalizedLabel,
@@ -1610,10 +1609,10 @@
}
mHistory.add(addPos, r);
r.putInHistory();
- mService.mWindowManager.addAppToken(addPos, r, r.task.taskId,
+ mService.mWindowManager.addAppToken(addPos, r.appToken, r.task.taskId,
r.info.screenOrientation, r.fullscreen);
if (VALIDATE_TOKENS) {
- mService.mWindowManager.validateAppTokens(mHistory);
+ validateAppTokensLocked();
}
return;
}
@@ -1677,7 +1676,7 @@
mNoAnimActivities.remove(r);
}
mService.mWindowManager.addAppToken(
- addPos, r, r.task.taskId, r.info.screenOrientation, r.fullscreen);
+ addPos, r.appToken, r.task.taskId, r.info.screenOrientation, r.fullscreen);
boolean doShow = true;
if (newTask) {
// Even though this activity is starting fresh, we still need
@@ -1705,19 +1704,20 @@
else if (prev.nowVisible) prev = null;
}
mService.mWindowManager.setAppStartingWindow(
- r, r.packageName, r.theme,
+ r.appToken, r.packageName, r.theme,
mService.compatibilityInfoForPackageLocked(
r.info.applicationInfo), r.nonLocalizedLabel,
- r.labelRes, r.icon, r.windowFlags, prev, showStartingIcon);
+ r.labelRes, r.icon, r.windowFlags,
+ prev != null ? prev.appToken : null, showStartingIcon);
}
} else {
// If this is the first activity, don't do any fancy animations,
// because there is nothing for it to animate on top of.
- mService.mWindowManager.addAppToken(addPos, r, r.task.taskId,
+ mService.mWindowManager.addAppToken(addPos, r.appToken, r.task.taskId,
r.info.screenOrientation, r.fullscreen);
}
if (VALIDATE_TOKENS) {
- mService.mWindowManager.validateAppTokens(mHistory);
+ validateAppTokensLocked();
}
if (doResume) {
@@ -1725,6 +1725,15 @@
}
}
+ final void validateAppTokensLocked() {
+ mValidateAppTokens.clear();
+ mValidateAppTokens.ensureCapacity(mHistory.size());
+ for (int i=0; i<mHistory.size(); i++) {
+ mValidateAppTokens.add(mHistory.get(i).appToken);
+ }
+ mService.mWindowManager.validateAppTokens(mValidateAppTokens);
+ }
+
/**
* Perform a reset of the given task, if needed as part of launching it.
* Returns the new HistoryRecord at the top of the task.
@@ -1826,7 +1835,7 @@
if (DEBUG_TASKS) Slog.v(TAG, "Start pushing activity " + target
+ " out to new task " + target.task);
}
- mService.mWindowManager.setAppGroupId(target, task.taskId);
+ mService.mWindowManager.setAppGroupId(target.appToken, task.taskId);
if (replyChainEnd < 0) {
replyChainEnd = targetI;
}
@@ -1849,11 +1858,11 @@
}
mHistory.remove(srcPos);
mHistory.add(dstPos, p);
- mService.mWindowManager.moveAppToken(dstPos, p);
- mService.mWindowManager.setAppGroupId(p, p.task.taskId);
+ mService.mWindowManager.moveAppToken(dstPos, p.appToken);
+ mService.mWindowManager.setAppGroupId(p.appToken, p.task.taskId);
dstPos++;
if (VALIDATE_TOKENS) {
- mService.mWindowManager.validateAppTokens(mHistory);
+ validateAppTokensLocked();
}
i++;
}
@@ -1985,10 +1994,10 @@
mHistory.add(lastReparentPos, p);
if (DEBUG_TASKS) Slog.v(TAG, "Pulling activity " + p
+ " in to resetting task " + task);
- mService.mWindowManager.moveAppToken(lastReparentPos, p);
- mService.mWindowManager.setAppGroupId(p, p.task.taskId);
+ mService.mWindowManager.moveAppToken(lastReparentPos, p.appToken);
+ mService.mWindowManager.setAppGroupId(p.appToken, p.task.taskId);
if (VALIDATE_TOKENS) {
- mService.mWindowManager.validateAppTokens(mHistory);
+ validateAppTokensLocked();
}
}
replyChainEnd = -1;
@@ -2081,7 +2090,7 @@
if (ret.launchMode == ActivityInfo.LAUNCH_MULTIPLE
&& (launchFlags&Intent.FLAG_ACTIVITY_SINGLE_TOP) == 0) {
if (!ret.finishing) {
- int index = indexOfTokenLocked(ret);
+ int index = indexOfTokenLocked(ret.appToken);
if (index >= 0) {
finishActivityLocked(ret, index, Activity.RESULT_CANCELED,
null, "clear");
@@ -3007,7 +3016,7 @@
return res;
}
- resultTo = outActivity[0];
+ resultTo = outActivity[0] != null ? outActivity[0].appToken : null;
}
}
} finally {
@@ -3065,7 +3074,7 @@
ArrayList<ResultInfo> list = new ArrayList<ResultInfo>();
list.add(new ResultInfo(resultWho, requestCode,
resultCode, data));
- r.app.thread.scheduleSendResult(r, list);
+ r.app.thread.scheduleSendResult(r.appToken, list);
return;
} catch (Exception e) {
Slog.w(TAG, "Exception thrown sending result to " + r, e);
@@ -3080,7 +3089,7 @@
if ((r.intent.getFlags()&Intent.FLAG_ACTIVITY_NO_HISTORY) != 0
|| (r.info.flags&ActivityInfo.FLAG_NO_HISTORY) != 0) {
if (!r.finishing) {
- requestFinishActivityLocked(r, Activity.RESULT_CANCELED, null,
+ requestFinishActivityLocked(r.appToken, Activity.RESULT_CANCELED, null,
"no-history");
}
} else if (r.app != null && r.app.thread != null) {
@@ -3098,9 +3107,9 @@
if (DEBUG_VISBILITY) Slog.v(
TAG, "Stopping visible=" + r.visible + " for " + r);
if (!r.visible) {
- mService.mWindowManager.setAppVisibility(r, false);
+ mService.mWindowManager.setAppVisibility(r.appToken, false);
}
- r.app.thread.scheduleStopActivity(r, r.visible, r.configChangeFlags);
+ r.app.thread.scheduleStopActivity(r.appToken, r.visible, r.configChangeFlags);
if (mService.isSleeping()) {
r.setSleeping(true);
}
@@ -3145,7 +3154,7 @@
// normal flow and hide it once we determine that it is
// hidden by the activities in front of it.
if (localLOGV) Slog.v(TAG, "Before stopping, can hide: " + s);
- mService.mWindowManager.setAppVisibility(s, false);
+ mService.mWindowManager.setAppVisibility(s.appToken, false);
}
}
if ((!s.waitingVisible || mService.isSleeping()) && remove) {
@@ -3186,14 +3195,14 @@
boolean enableScreen = false;
synchronized (mService) {
- if (token != null) {
- mHandler.removeMessages(IDLE_TIMEOUT_MSG, token);
+ ActivityRecord r = ActivityRecord.forToken(token);
+ if (r != null) {
+ mHandler.removeMessages(IDLE_TIMEOUT_MSG, r);
}
// Get the activity record.
- int index = indexOfTokenLocked(token);
+ int index = indexOfActivityLocked(r);
if (index >= 0) {
- ActivityRecord r = mHistory.get(index);
res = r;
if (fromTimeout) {
@@ -3413,7 +3422,7 @@
: WindowManagerPolicy.TRANSIT_ACTIVITY_CLOSE, false);
// Tell window manager to prepare for this one to be removed.
- mService.mWindowManager.setAppVisibility(r, false);
+ mService.mWindowManager.setAppVisibility(r.appToken, false);
if (mPausingActivity == null) {
if (DEBUG_PAUSE) Slog.v(TAG, "Finish needs to pause: " + r);
@@ -3440,7 +3449,7 @@
private final ActivityRecord finishCurrentActivityLocked(ActivityRecord r,
int mode) {
- final int index = indexOfTokenLocked(r);
+ final int index = indexOfActivityLocked(r);
if (index < 0) {
return null;
}
@@ -3570,9 +3579,9 @@
if (DEBUG_STATES) Slog.v(TAG, "Moving to DESTROYED: " + r
+ " (removed from history)");
r.state = ActivityState.DESTROYED;
- mService.mWindowManager.removeAppToken(r);
+ mService.mWindowManager.removeAppToken(r.appToken);
if (VALIDATE_TOKENS) {
- mService.mWindowManager.validateAppTokens(mHistory);
+ validateAppTokensLocked();
}
cleanUpActivityServicesLocked(r);
r.removeUriPermissionsLocked();
@@ -3653,7 +3662,7 @@
try {
if (DEBUG_SWITCH) Slog.i(TAG, "Destroying: " + r);
- r.app.thread.scheduleDestroyActivity(r, r.finishing,
+ r.app.thread.scheduleDestroyActivity(r.appToken, r.finishing,
r.configChangeFlags);
} catch (Exception e) {
// We can just ignore exceptions here... if the process
@@ -3712,11 +3721,13 @@
final void activityDestroyed(IBinder token) {
synchronized (mService) {
- mHandler.removeMessages(DESTROY_TIMEOUT_MSG, token);
+ ActivityRecord r = ActivityRecord.forToken(token);
+ if (r != null) {
+ mHandler.removeMessages(DESTROY_TIMEOUT_MSG, r);
+ }
- int index = indexOfTokenLocked(token);
+ int index = indexOfActivityLocked(r);
if (index >= 0) {
- ActivityRecord r = mHistory.get(index);
if (r.state == ActivityState.DESTROYING) {
final long origId = Binder.clearCallingIdentity();
removeActivityFromHistoryLocked(r);
@@ -3781,7 +3792,7 @@
return;
}
- ArrayList moved = new ArrayList();
+ ArrayList<IBinder> moved = new ArrayList<IBinder>();
// Applying the affinities may have removed entries from the history,
// so get the size again.
@@ -3803,7 +3814,7 @@
}
mHistory.remove(pos);
mHistory.add(top, r);
- moved.add(0, r);
+ moved.add(0, r.appToken);
top--;
}
pos--;
@@ -3826,7 +3837,7 @@
mService.mWindowManager.moveAppTokensToTop(moved);
if (VALIDATE_TOKENS) {
- mService.mWindowManager.validateAppTokens(mHistory);
+ validateAppTokensLocked();
}
finishTaskMoveLocked(task);
@@ -3873,7 +3884,7 @@
}
}
- ArrayList moved = new ArrayList();
+ ArrayList<IBinder> moved = new ArrayList<IBinder>();
if (DEBUG_TRANSITION) Slog.v(TAG,
"Prepare to back transition: task=" + task);
@@ -3898,7 +3909,7 @@
}
mHistory.remove(pos);
mHistory.add(bottom, r);
- moved.add(r);
+ moved.add(r.appToken);
bottom++;
}
pos++;
@@ -3918,7 +3929,7 @@
}
mService.mWindowManager.moveAppTokensToBottom(moved);
if (VALIDATE_TOKENS) {
- mService.mWindowManager.validateAppTokens(mHistory);
+ validateAppTokensLocked();
}
finishTaskMoveLocked(task);
@@ -4148,7 +4159,7 @@
if (r.app != null && r.app.thread != null) {
try {
if (DEBUG_CONFIGURATION) Slog.v(TAG, "Sending new config to " + r);
- r.app.thread.scheduleActivityConfigurationChanged(r);
+ r.app.thread.scheduleActivityConfigurationChanged(r.appToken);
} catch (RemoteException e) {
// If process died, whatever.
}
@@ -4178,7 +4189,7 @@
try {
if (DEBUG_SWITCH) Slog.i(TAG, "Switch is restarting resumed " + r);
r.forceNewConfig = false;
- r.app.thread.scheduleRelaunchActivity(r, results, newIntents,
+ r.app.thread.scheduleRelaunchActivity(r.appToken, results, newIntents,
changes, !andResume, mService.mConfiguration);
// Note: don't need to call pauseIfSleepingLocked() here, because
// the caller will only pass in 'andResume' if this activity is
diff --git a/services/java/com/android/server/connectivity/Tethering.java b/services/java/com/android/server/connectivity/Tethering.java
index 423a78f..c344bc6 100644
--- a/services/java/com/android/server/connectivity/Tethering.java
+++ b/services/java/com/android/server/connectivity/Tethering.java
@@ -73,7 +73,7 @@
private Context mContext;
private final static String TAG = "Tethering";
private final static boolean DBG = true;
- private final static boolean VDBG = true;
+ private final static boolean VDBG = false;
// TODO - remove both of these - should be part of interface inspection/selection stuff
private String[] mTetherableUsbRegexs;
@@ -228,7 +228,7 @@
if (isUsb(iface)) {
// ignore usb0 down after enabling RNDIS
// we will handle disconnect in interfaceRemoved instead
- if (VDBG) Log.d(TAG, "ignoring interface down for " + iface);
+ if (VDBG) Log.d(TAG, "ignore interface down for " + iface);
} else if (sm != null) {
sm.sendMessage(TetherInterfaceSM.CMD_INTERFACE_DOWN);
mIfaces.remove(iface);
@@ -298,7 +298,6 @@
mIfaces.put(iface, sm);
sm.start();
}
- if (VDBG) Log.d(TAG, "interfaceAdded :" + iface);
}
public void interfaceRemoved(String iface) {
@@ -415,7 +414,7 @@
broadcast.putStringArrayListExtra(ConnectivityManager.EXTRA_ERRORED_TETHER,
erroredList);
mContext.sendStickyBroadcast(broadcast);
- if (VDBG) {
+ if (DBG) {
Log.d(TAG, "sendTetherStateChangedBroadcast " + availableList.size() + ", " +
activeList.size() + ", " + erroredList.size());
}
@@ -865,7 +864,7 @@
@Override
public boolean processMessage(Message message) {
- if (VDBG) Log.d(TAG, "InitialState.processMessage what=" + message.what);
+ if (DBG) Log.d(TAG, "InitialState.processMessage what=" + message.what);
boolean retValue = true;
switch (message.what) {
case CMD_TETHER_REQUESTED:
@@ -906,7 +905,7 @@
}
@Override
public boolean processMessage(Message message) {
- if (VDBG) Log.d(TAG, "StartingState.processMessage what=" + message.what);
+ if (DBG) Log.d(TAG, "StartingState.processMessage what=" + message.what);
boolean retValue = true;
switch (message.what) {
// maybe a parent class?
@@ -985,7 +984,7 @@
@Override
public boolean processMessage(Message message) {
- if (VDBG) Log.d(TAG, "TetheredState.processMessage what=" + message.what);
+ if (DBG) Log.d(TAG, "TetheredState.processMessage what=" + message.what);
boolean retValue = true;
boolean error = false;
switch (message.what) {
@@ -1061,7 +1060,7 @@
ConnectivityManager.TETHER_ERROR_MASTER_ERROR);
break;
}
- if (VDBG) Log.d(TAG, "Tether lost upstream connection " + mIfaceName);
+ if (DBG) Log.d(TAG, "Tether lost upstream connection " + mIfaceName);
sendTetherStateChangedBroadcast();
if (mUsb) {
if (!Tethering.this.configureUsbIface(false)) {
@@ -1296,7 +1295,7 @@
}
}
- if (VDBG) {
+ if (DBG) {
Log.d(TAG, "chooseUpstreamType(" + tryCell + "), preferredApn ="
+ mPreferredUpstreamMobileApn + ", got type=" + upType);
}
@@ -1328,7 +1327,7 @@
}
protected void notifyTetheredOfNewUpstreamIface(String ifaceName) {
- if (VDBG) Log.d(TAG, "notifying tethered with iface =" + ifaceName);
+ if (DBG) Log.d(TAG, "notifying tethered with iface =" + ifaceName);
mUpstreamIfaceName = ifaceName;
for (Object o : mNotifyList) {
TetherInterfaceSM sm = (TetherInterfaceSM)o;
@@ -1344,7 +1343,7 @@
}
@Override
public boolean processMessage(Message message) {
- if (VDBG) Log.d(TAG, "MasterInitialState.processMessage what=" + message.what);
+ if (DBG) Log.d(TAG, "MasterInitialState.processMessage what=" + message.what);
boolean retValue = true;
switch (message.what) {
case CMD_TETHER_MODE_REQUESTED:
@@ -1386,7 +1385,7 @@
}
@Override
public boolean processMessage(Message message) {
- if (VDBG) Log.d(TAG, "TetherModeAliveState.processMessage what=" + message.what);
+ if (DBG) Log.d(TAG, "TetherModeAliveState.processMessage what=" + message.what);
boolean retValue = true;
switch (message.what) {
case CMD_TETHER_MODE_REQUESTED:
diff --git a/services/java/com/android/server/net/NetworkStatsService.java b/services/java/com/android/server/net/NetworkStatsService.java
index 77b0d96..6365525 100644
--- a/services/java/com/android/server/net/NetworkStatsService.java
+++ b/services/java/com/android/server/net/NetworkStatsService.java
@@ -806,9 +806,7 @@
final NetworkStats networkDevSnapshot;
try {
// collect any tethering stats
- final String[] tetheredIfacePairs = mConnManager.getTetheredIfacePairs();
- final NetworkStats tetherSnapshot = mNetworkManager.getNetworkStatsTethering(
- tetheredIfacePairs);
+ final NetworkStats tetherSnapshot = getNetworkStatsTethering();
// record uid stats, folding in tethering stats
uidSnapshot = mNetworkManager.getNetworkStatsUidDetail(UID_ALL);
@@ -1505,7 +1503,7 @@
NetworkStats before, NetworkStats current, boolean collectStale, String type) {
if (before != null) {
try {
- return current.subtract(before);
+ return current.subtract(before, false);
} catch (NonMonotonicException e) {
Log.w(TAG, "found non-monotonic values; saving to dropbox");
@@ -1517,8 +1515,13 @@
builder.append("right=").append(e.right).append('\n');
mDropBox.addText(TAG_NETSTATS_ERROR, builder.toString());
- // return empty delta to avoid recording broken stats
- return new NetworkStats(0L, 10);
+ try {
+ // return clamped delta to help recover
+ return current.subtract(before, true);
+ } catch (NonMonotonicException e1) {
+ Log.wtf(TAG, "found non-monotonic values; returning empty delta", e1);
+ return new NetworkStats(0L, 10);
+ }
}
} else if (collectStale) {
// caller is okay collecting stale stats for first call.
@@ -1530,6 +1533,20 @@
}
}
+ /**
+ * Return snapshot of current tethering statistics. Will return empty
+ * {@link NetworkStats} if any problems are encountered.
+ */
+ private NetworkStats getNetworkStatsTethering() throws RemoteException {
+ try {
+ final String[] tetheredIfacePairs = mConnManager.getTetheredIfacePairs();
+ return mNetworkManager.getNetworkStatsTethering(tetheredIfacePairs);
+ } catch (IllegalStateException e) {
+ Log.wtf(TAG, "problem reading network stats", e);
+ return new NetworkStats(0L, 10);
+ }
+ }
+
private static NetworkStats computeNetworkXtSnapshotFromUid(NetworkStats uidSnapshot) {
return uidSnapshot.groupedByIface();
}
diff --git a/services/java/com/android/server/pm/Settings.java b/services/java/com/android/server/pm/Settings.java
index bfe6613..36442a0 100644
--- a/services/java/com/android/server/pm/Settings.java
+++ b/services/java/com/android/server/pm/Settings.java
@@ -63,6 +63,8 @@
import java.util.HashSet;
import java.util.Iterator;
+import libcore.io.IoUtils;
+
/**
* Holds information about dynamic settings.
*/
@@ -998,8 +1000,8 @@
FileUtils.sync(fstr);
str.close();
journal.commit();
- }
- catch (Exception e) {
+ } catch (Exception e) {
+ IoUtils.closeQuietly(str);
journal.rollback();
}
diff --git a/services/java/com/android/server/wm/InputManager.java b/services/java/com/android/server/wm/InputManager.java
index df7e0e1..a4f0a0c2 100644
--- a/services/java/com/android/server/wm/InputManager.java
+++ b/services/java/com/android/server/wm/InputManager.java
@@ -675,7 +675,13 @@
} catch (NumberFormatException e) {
}
if (result < 1) {
- result = 55;
+ // This number equates to the refresh rate * 1.5. The rate should be at least
+ // equal to the screen refresh rate. We increase the rate by 50% to compensate for
+ // the discontinuity between the actual rate that events come in at (they do
+ // not necessarily come in constantly and are not handled synchronously).
+ // Ideally, we would use Display.getRefreshRate(), but as this does not necessarily
+ // return a sensible result, we use '60' as our default assumed refresh rate.
+ result = 90;
}
return result;
}
diff --git a/services/java/com/android/server/wm/WindowManagerService.java b/services/java/com/android/server/wm/WindowManagerService.java
index 8ed7966..50321b3 100644
--- a/services/java/com/android/server/wm/WindowManagerService.java
+++ b/services/java/com/android/server/wm/WindowManagerService.java
@@ -3070,7 +3070,7 @@
// Application Window Tokens
// -------------------------------------------------------------
- public void validateAppTokens(List tokens) {
+ public void validateAppTokens(List<IBinder> tokens) {
int v = tokens.size()-1;
int m = mAppTokens.size()-1;
while (v >= 0 && m >= 0) {
@@ -5809,7 +5809,87 @@
return curSize;
}
- private int computeSmallestWidth(boolean rotated, int dw, int dh, float density) {
+ private int reduceConfigLayout(int curLayout, int rotation, float density,
+ int dw, int dh) {
+ // Get the app screen size at this rotation.
+ int w = mPolicy.getNonDecorDisplayWidth(dw, dh, rotation);
+ int h = mPolicy.getNonDecorDisplayHeight(dw, dh, rotation);
+
+ // Compute the screen layout size class for this rotation.
+ int screenLayoutSize;
+ boolean screenLayoutLong;
+ boolean screenLayoutCompatNeeded;
+ int longSize = w;
+ int shortSize = h;
+ if (longSize < shortSize) {
+ int tmp = longSize;
+ longSize = shortSize;
+ shortSize = tmp;
+ }
+ longSize = (int)(longSize/density);
+ shortSize = (int)(shortSize/density);
+
+ // These semi-magic numbers define our compatibility modes for
+ // applications with different screens. These are guarantees to
+ // app developers about the space they can expect for a particular
+ // configuration. DO NOT CHANGE!
+ if (longSize < 470) {
+ // This is shorter than an HVGA normal density screen (which
+ // is 480 pixels on its long side).
+ screenLayoutSize = Configuration.SCREENLAYOUT_SIZE_SMALL;
+ screenLayoutLong = false;
+ screenLayoutCompatNeeded = false;
+ } else {
+ // What size is this screen screen?
+ if (longSize >= 960 && shortSize >= 720) {
+ // 1.5xVGA or larger screens at medium density are the point
+ // at which we consider it to be an extra large screen.
+ screenLayoutSize = Configuration.SCREENLAYOUT_SIZE_XLARGE;
+ } else if (longSize >= 640 && shortSize >= 480) {
+ // VGA or larger screens at medium density are the point
+ // at which we consider it to be a large screen.
+ screenLayoutSize = Configuration.SCREENLAYOUT_SIZE_LARGE;
+ } else {
+ screenLayoutSize = Configuration.SCREENLAYOUT_SIZE_NORMAL;
+ }
+
+ // If this screen is wider than normal HVGA, or taller
+ // than FWVGA, then for old apps we want to run in size
+ // compatibility mode.
+ if (shortSize > 321 || longSize > 570) {
+ screenLayoutCompatNeeded = true;
+ } else {
+ screenLayoutCompatNeeded = false;
+ }
+
+ // Is this a long screen?
+ if (((longSize*3)/5) >= (shortSize-1)) {
+ // Anything wider than WVGA (5:3) is considering to be long.
+ screenLayoutLong = true;
+ } else {
+ screenLayoutLong = false;
+ }
+ }
+
+ // Now reduce the last screenLayout to not be better than what we
+ // have found.
+ if (!screenLayoutLong) {
+ curLayout = (curLayout&~Configuration.SCREENLAYOUT_LONG_MASK)
+ | Configuration.SCREENLAYOUT_LONG_NO;
+ }
+ if (screenLayoutCompatNeeded) {
+ curLayout |= Configuration.SCREENLAYOUT_COMPAT_NEEDED;
+ }
+ int curSize = curLayout&Configuration.SCREENLAYOUT_SIZE_MASK;
+ if (screenLayoutSize < curSize) {
+ curLayout = (curLayout&~Configuration.SCREENLAYOUT_SIZE_MASK)
+ | screenLayoutSize;
+ }
+ return curLayout;
+ }
+
+ private void computeSmallestWidthAndScreenLayout(boolean rotated, int dw, int dh,
+ float density, Configuration outConfig) {
// We need to determine the smallest width that will occur under normal
// operation. To this, start with the base screen size and compute the
// width under the different possible rotations. We need to un-rotate
@@ -5826,7 +5906,14 @@
sw = reduceConfigWidthSize(sw, Surface.ROTATION_90, density, unrotDh, unrotDw);
sw = reduceConfigWidthSize(sw, Surface.ROTATION_180, density, unrotDw, unrotDh);
sw = reduceConfigWidthSize(sw, Surface.ROTATION_270, density, unrotDh, unrotDw);
- return sw;
+ int sl = Configuration.SCREENLAYOUT_SIZE_XLARGE
+ | Configuration.SCREENLAYOUT_LONG_YES;
+ sl = reduceConfigLayout(sl, Surface.ROTATION_0, density, unrotDw, unrotDh);
+ sl = reduceConfigLayout(sl, Surface.ROTATION_90, density, unrotDh, unrotDw);
+ sl = reduceConfigLayout(sl, Surface.ROTATION_180, density, unrotDw, unrotDh);
+ sl = reduceConfigLayout(sl, Surface.ROTATION_270, density, unrotDh, unrotDw);
+ outConfig.smallestScreenWidthDp = sw;
+ outConfig.screenLayout = sl;
}
private int reduceCompatConfigWidthSize(int curSize, int rotation, DisplayMetrics dm,
@@ -5924,64 +6011,12 @@
/ dm.density);
config.screenHeightDp = (int)(mPolicy.getConfigDisplayHeight(dw, dh, mRotation)
/ dm.density);
- config.smallestScreenWidthDp = computeSmallestWidth(rotated, dw, dh, dm.density);
+ computeSmallestWidthAndScreenLayout(rotated, dw, dh, dm.density, config);
config.compatScreenWidthDp = (int)(config.screenWidthDp / mCompatibleScreenScale);
config.compatScreenHeightDp = (int)(config.screenHeightDp / mCompatibleScreenScale);
config.compatSmallestScreenWidthDp = computeCompatSmallestWidth(rotated, dm, dw, dh);
- // Compute the screen layout size class.
- int screenLayout;
- int longSize = mAppDisplayWidth;
- int shortSize = mAppDisplayHeight;
- if (longSize < shortSize) {
- int tmp = longSize;
- longSize = shortSize;
- shortSize = tmp;
- }
- longSize = (int)(longSize/dm.density);
- shortSize = (int)(shortSize/dm.density);
-
- // These semi-magic numbers define our compatibility modes for
- // applications with different screens. These are guarantees to
- // app developers about the space they can expect for a particular
- // configuration. DO NOT CHANGE!
- if (longSize < 470) {
- // This is shorter than an HVGA normal density screen (which
- // is 480 pixels on its long side).
- screenLayout = Configuration.SCREENLAYOUT_SIZE_SMALL
- | Configuration.SCREENLAYOUT_LONG_NO;
- } else {
- // What size is this screen screen?
- if (longSize >= 960 && shortSize >= 720) {
- // 1.5xVGA or larger screens at medium density are the point
- // at which we consider it to be an extra large screen.
- screenLayout = Configuration.SCREENLAYOUT_SIZE_XLARGE;
- } else if (longSize >= 640 && shortSize >= 480) {
- // VGA or larger screens at medium density are the point
- // at which we consider it to be a large screen.
- screenLayout = Configuration.SCREENLAYOUT_SIZE_LARGE;
- } else {
- screenLayout = Configuration.SCREENLAYOUT_SIZE_NORMAL;
- }
-
- // If this screen is wider than normal HVGA, or taller
- // than FWVGA, then for old apps we want to run in size
- // compatibility mode.
- if (shortSize > 321 || longSize > 570) {
- screenLayout |= Configuration.SCREENLAYOUT_COMPAT_NEEDED;
- }
-
- // Is this a long screen?
- if (((longSize*3)/5) >= (shortSize-1)) {
- // Anything wider than WVGA (5:3) is considering to be long.
- screenLayout |= Configuration.SCREENLAYOUT_LONG_YES;
- } else {
- screenLayout |= Configuration.SCREENLAYOUT_LONG_NO;
- }
- }
- config.screenLayout = screenLayout;
-
// Determine whether a hard keyboard is available and enabled.
boolean hardKeyboardAvailable = config.keyboard != Configuration.KEYBOARD_NOKEYS;
if (hardKeyboardAvailable != mHardKeyboardAvailable) {
diff --git a/services/sensorservice/SensorDevice.cpp b/services/sensorservice/SensorDevice.cpp
index d82a7e2..7575ebd 100644
--- a/services/sensorservice/SensorDevice.cpp
+++ b/services/sensorservice/SensorDevice.cpp
@@ -166,7 +166,11 @@
ssize_t SensorDevice::poll(sensors_event_t* buffer, size_t count) {
if (!mSensorDevice) return NO_INIT;
- return mSensorDevice->poll(mSensorDevice, buffer, count);
+ ssize_t c;
+ do {
+ c = mSensorDevice->poll(mSensorDevice, buffer, count);
+ } while (c == -EINTR);
+ return c;
}
status_t SensorDevice::activate(void* ident, int handle, int enabled)
diff --git a/services/sensorservice/SensorService.cpp b/services/sensorservice/SensorService.cpp
index c2c6b4d..6202143 100644
--- a/services/sensorservice/SensorService.cpp
+++ b/services/sensorservice/SensorService.cpp
@@ -286,7 +286,8 @@
}
} while (count >= 0 || Thread::exitPending());
- LOGW("Exiting SensorService::threadLoop!");
+ LOGW("Exiting SensorService::threadLoop => aborting...");
+ abort();
return false;
}
diff --git a/telephony/java/com/android/internal/telephony/cat/CatService.java b/telephony/java/com/android/internal/telephony/cat/CatService.java
index 5420264..5a994f3 100644
--- a/telephony/java/com/android/internal/telephony/cat/CatService.java
+++ b/telephony/java/com/android/internal/telephony/cat/CatService.java
@@ -94,6 +94,8 @@
private static final int DEV_ID_TERMINAL = 0x82;
private static final int DEV_ID_NETWORK = 0x83;
+ static final String STK_DEFAULT = "Defualt Message";
+
/* Intentionally private for singleton */
private CatService(CommandsInterface ci, IccRecords ir, Context context,
IccFileHandler fh, IccCard ic) {
@@ -157,7 +159,15 @@
}
break;
case MSG_ID_PROACTIVE_COMMAND:
- cmdParams = (CommandParams) rilMsg.mData;
+ try {
+ cmdParams = (CommandParams) rilMsg.mData;
+ } catch (ClassCastException e) {
+ // for error handling : cast exception
+ CatLog.d(this, "Fail to parse proactive command");
+ sendTerminalResponse(mCurrntCmd.mCmdDet, ResultCode.CMD_DATA_NOT_UNDERSTOOD,
+ false, 0x00, null);
+ break;
+ }
if (cmdParams != null) {
if (rilMsg.mResCode == ResultCode.OK) {
handleProactiveCommand(cmdParams);
@@ -194,6 +204,7 @@
private void handleProactiveCommand(CommandParams cmdParams) {
CatLog.d(this, cmdParams.getCommandType().name());
+ CharSequence message;
CatCmdMessage cmdMsg = new CatCmdMessage(cmdParams);
switch (cmdParams.getCommandType()) {
case SET_UP_MENU:
@@ -224,26 +235,44 @@
case CommandParamsFactory.DTTZ_SETTING:
resp = new DTTZResponseData(null);
sendTerminalResponse(cmdParams.cmdDet, ResultCode.OK, false, 0, resp);
- break;
+ return;
case CommandParamsFactory.LANGUAGE_SETTING:
resp = new LanguageResponseData(Locale.getDefault().getLanguage());
sendTerminalResponse(cmdParams.cmdDet, ResultCode.OK, false, 0, resp);
- break;
+ return;
default:
sendTerminalResponse(cmdParams.cmdDet, ResultCode.OK, false, 0, null);
return;
}
case LAUNCH_BROWSER:
+ if ((((LaunchBrowserParams) cmdParams).confirmMsg.text != null)
+ && (((LaunchBrowserParams) cmdParams).confirmMsg.text.equals(STK_DEFAULT))) {
+ message = mContext.getText(com.android.internal.R.string.launchBrowserDefault);
+ ((LaunchBrowserParams) cmdParams).confirmMsg.text = message.toString();
+ }
+ break;
case SELECT_ITEM:
case GET_INPUT:
case GET_INKEY:
+ break;
case SEND_DTMF:
case SEND_SMS:
case SEND_SS:
case SEND_USSD:
+ if ((((DisplayTextParams)cmdParams).textMsg.text != null)
+ && (((DisplayTextParams)cmdParams).textMsg.text.equals(STK_DEFAULT))) {
+ message = mContext.getText(com.android.internal.R.string.sending);
+ ((DisplayTextParams)cmdParams).textMsg.text = message.toString();
+ }
+ break;
case PLAY_TONE:
+ break;
case SET_UP_CALL:
- // nothing to do on telephony!
+ if ((((CallSetupParams) cmdParams).confirmMsg.text != null)
+ && (((CallSetupParams) cmdParams).confirmMsg.text.equals(STK_DEFAULT))) {
+ message = mContext.getText(com.android.internal.R.string.SetupCallDefault);
+ ((CallSetupParams) cmdParams).confirmMsg.text = message.toString();
+ }
break;
default:
CatLog.d(this, "Unsupported command");
diff --git a/telephony/java/com/android/internal/telephony/cat/CommandParamsFactory.java b/telephony/java/com/android/internal/telephony/cat/CommandParamsFactory.java
index 686fe46..e7fca5a 100644
--- a/telephony/java/com/android/internal/telephony/cat/CommandParamsFactory.java
+++ b/telephony/java/com/android/internal/telephony/cat/CommandParamsFactory.java
@@ -403,6 +403,7 @@
input.ucs2 = (cmdDet.commandQualifier & 0x02) != 0;
input.yesNo = (cmdDet.commandQualifier & 0x04) != 0;
input.helpAvailable = (cmdDet.commandQualifier & 0x80) != 0;
+ input.echo = true;
mCmdParams = new GetInputParams(cmdDet, input);
@@ -625,11 +626,7 @@
ComprehensionTlv ctlv = searchForTag(ComprehensionTlvTag.ALPHA_ID,
ctlvs);
- if (ctlv != null) {
- textMsg.text = ValueParser.retrieveAlphaId(ctlv);
- } else {
- throw new ResultException(ResultCode.REQUIRED_VALUES_MISSING);
- }
+ textMsg.text = ValueParser.retrieveAlphaId(ctlv);
ctlv = searchForTag(ComprehensionTlvTag.ICON_ID, ctlvs);
if (ctlv != null) {
@@ -714,9 +711,8 @@
// parse alpha identifier.
ctlv = searchForTag(ComprehensionTlvTag.ALPHA_ID, ctlvs);
- if (ctlv != null) {
- confirmMsg.text = ValueParser.retrieveAlphaId(ctlv);
- }
+ confirmMsg.text = ValueParser.retrieveAlphaId(ctlv);
+
// parse icon identifier
ctlv = searchForTag(ComprehensionTlvTag.ICON_ID, ctlvs);
if (ctlv != null) {
@@ -841,9 +837,7 @@
// get confirmation message string.
ctlv = searchForNextTag(ComprehensionTlvTag.ALPHA_ID, iter);
- if (ctlv != null) {
- confirmMsg.text = ValueParser.retrieveAlphaId(ctlv);
- }
+ confirmMsg.text = ValueParser.retrieveAlphaId(ctlv);
ctlv = searchForTag(ComprehensionTlvTag.ICON_ID, ctlvs);
if (ctlv != null) {
diff --git a/telephony/java/com/android/internal/telephony/cat/ComprehensionTlv.java b/telephony/java/com/android/internal/telephony/cat/ComprehensionTlv.java
index e5a2d31..ab26d13 100644
--- a/telephony/java/com/android/internal/telephony/cat/ComprehensionTlv.java
+++ b/telephony/java/com/android/internal/telephony/cat/ComprehensionTlv.java
@@ -94,6 +94,7 @@
startIndex = ctlv.mValueIndex + ctlv.mLength;
} else {
CatLog.d(LOG_TAG, "decodeMany: ctlv is null, stop decoding");
+ items.clear();
break;
}
}
@@ -123,7 +124,10 @@
case 0:
case 0xff:
case 0x80:
- throw new ResultException(ResultCode.CMD_DATA_NOT_UNDERSTOOD);
+ // for error handling
+ // these one make exception while decoding the abnormal command.
+ // (in case of Ghana MTN simcard , JDI simcard)
+ return null;
case 0x7f: // tag is in three-byte format
tag = ((data[curIndex] & 0xff) << 8)
diff --git a/telephony/java/com/android/internal/telephony/cat/ValueParser.java b/telephony/java/com/android/internal/telephony/cat/ValueParser.java
index 34e4811..584d96c 100644
--- a/telephony/java/com/android/internal/telephony/cat/ValueParser.java
+++ b/telephony/java/com/android/internal/telephony/cat/ValueParser.java
@@ -273,18 +273,23 @@
*/
static String retrieveAlphaId(ComprehensionTlv ctlv) throws ResultException {
- byte[] rawValue = ctlv.getRawValue();
- int valueIndex = ctlv.getValueIndex();
- int length = ctlv.getLength();
- if (length != 0) {
- try {
- return IccUtils.adnStringFieldToString(rawValue, valueIndex,
- length);
- } catch (IndexOutOfBoundsException e) {
- throw new ResultException(ResultCode.CMD_DATA_NOT_UNDERSTOOD);
+ if (ctlv != null) {
+ byte[] rawValue = ctlv.getRawValue();
+ int valueIndex = ctlv.getValueIndex();
+ int length = ctlv.getLength();
+ if (length != 0) {
+ try {
+ return IccUtils.adnStringFieldToString(rawValue, valueIndex,
+ length);
+ } catch (IndexOutOfBoundsException e) {
+ throw new ResultException(ResultCode.CMD_DATA_NOT_UNDERSTOOD);
+ }
+ } else {
+ return CatService.STK_DEFAULT;
}
+ } else {
+ return CatService.STK_DEFAULT;
}
- return null;
}
/**