Merge "Make AudioTrack control block volume field private"
diff --git a/Android.mk b/Android.mk
index 83c4b5b..5acfb86 100644
--- a/Android.mk
+++ b/Android.mk
@@ -94,6 +94,7 @@
core/java/android/bluetooth/IBluetoothHealthCallback.aidl \
core/java/android/bluetooth/IBluetoothPbap.aidl \
core/java/android/bluetooth/IBluetoothStateChangeCallback.aidl \
+ core/java/android/content/ICancellationSignal.aidl \
core/java/android/content/IClipboard.aidl \
core/java/android/content/IContentService.aidl \
core/java/android/content/IIntentReceiver.aidl \
@@ -449,8 +450,6 @@
resources/samples/training/ads-and-ux "Mobile Advertisement Integration" \
-samplecode $(sample_dir)/MultiResolution \
resources/samples/MultiResolution "Multiple Resolutions" \
- -samplecode $(sample_dir)/NFCDemo \
- resources/samples/NFCDemo "NFC Demo" \
-samplecode $(sample_dir)/training/multiscreen/newsreader \
resources/samples/newsreader "News Reader" \
-samplecode $(sample_dir)/NotePad \
diff --git a/CleanSpec.mk b/CleanSpec.mk
index fb334fc..d74d7b1 100644
--- a/CleanSpec.mk
+++ b/CleanSpec.mk
@@ -117,6 +117,8 @@
$(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/media/audio/)
$(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/fonts/DroidSans*)
$(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/media/audio/)
+$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/framework_intermediates/src/core/java/android/content)
+$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/android_stubs_current_intermediates/src/android/content)
# ************************************************
# NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST
# ************************************************
diff --git a/api/current.txt b/api/current.txt
index 7c05ed6..37b0328 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -436,7 +436,7 @@
field public static final int fadeEnabled = 16843390; // 0x101027e
field public static final int fadeOffset = 16843383; // 0x1010277
field public static final int fadeScrollbars = 16843434; // 0x10102aa
- field public static final deprecated int fadingEdge = 16842975; // 0x10100df
+ field public static final int fadingEdge = 16842975; // 0x10100df
field public static final int fadingEdgeLength = 16842976; // 0x10100e0
field public static final int fastScrollAlwaysVisible = 16843573; // 0x1010335
field public static final int fastScrollEnabled = 16843302; // 0x1010226
@@ -2288,7 +2288,8 @@
method public long getStagger(int);
method public long getStartDelay(int);
method public java.util.List<android.animation.LayoutTransition.TransitionListener> getTransitionListeners();
- method public void hideChild(android.view.ViewGroup, android.view.View);
+ method public deprecated void hideChild(android.view.ViewGroup, android.view.View);
+ method public void hideChild(android.view.ViewGroup, android.view.View, int);
method public boolean isChangingLayout();
method public boolean isRunning();
method public void removeChild(android.view.ViewGroup, android.view.View);
@@ -2300,7 +2301,8 @@
method public void setInterpolator(int, android.animation.TimeInterpolator);
method public void setStagger(int, long);
method public void setStartDelay(int, long);
- method public void showChild(android.view.ViewGroup, android.view.View);
+ method public deprecated void showChild(android.view.ViewGroup, android.view.View);
+ method public void showChild(android.view.ViewGroup, android.view.View, int);
field public static final int APPEARING = 2; // 0x2
field public static final int CHANGE_APPEARING = 0; // 0x0
field public static final int CHANGE_DISAPPEARING = 1; // 0x1
@@ -2400,6 +2402,16 @@
}
+package android.annotation {
+
+ public abstract class SuppressLint implements java.lang.annotation.Annotation {
+ }
+
+ public abstract class TargetApi implements java.lang.annotation.Annotation {
+ }
+
+}
+
package android.app {
public abstract class ActionBar {
@@ -4658,7 +4670,8 @@
public abstract class AsyncTaskLoader extends android.content.Loader {
ctor public AsyncTaskLoader(android.content.Context);
- method public boolean cancelLoad();
+ method public void cancelLoadInBackground();
+ method public boolean isLoadInBackgroundCanceled();
method public abstract D loadInBackground();
method public void onCanceled(D);
method protected D onLoadInBackground();
@@ -4701,6 +4714,18 @@
method public final void setResultExtras(android.os.Bundle);
}
+ public final class CancellationSignal {
+ ctor public CancellationSignal();
+ method public void cancel();
+ method public boolean isCanceled();
+ method public void setOnCancelListener(android.content.CancellationSignal.OnCancelListener);
+ method public void throwIfCanceled();
+ }
+
+ public static abstract interface CancellationSignal.OnCancelListener {
+ method public abstract void onCancel();
+ }
+
public class ClipData implements android.os.Parcelable {
ctor public ClipData(java.lang.CharSequence, java.lang.String[], android.content.ClipData.Item);
ctor public ClipData(android.content.ClipDescription, android.content.ClipData.Item);
@@ -4820,6 +4845,7 @@
method public android.os.ParcelFileDescriptor openPipeHelper(android.net.Uri, java.lang.String, android.os.Bundle, T, android.content.ContentProvider.PipeDataWriter<T>) throws java.io.FileNotFoundException;
method public android.content.res.AssetFileDescriptor openTypedAssetFile(android.net.Uri, java.lang.String, android.os.Bundle) throws java.io.FileNotFoundException;
method public abstract android.database.Cursor query(android.net.Uri, java.lang.String[], java.lang.String, java.lang.String[], java.lang.String);
+ method public android.database.Cursor query(android.net.Uri, java.lang.String[], java.lang.String, java.lang.String[], java.lang.String, android.content.CancellationSignal);
method protected final void setPathPermissions(android.content.pm.PathPermission[]);
method protected final void setReadPermission(java.lang.String);
method protected final void setWritePermission(java.lang.String);
@@ -4843,6 +4869,7 @@
method public android.os.ParcelFileDescriptor openFile(android.net.Uri, java.lang.String) throws java.io.FileNotFoundException, android.os.RemoteException;
method public final android.content.res.AssetFileDescriptor openTypedAssetFileDescriptor(android.net.Uri, java.lang.String, android.os.Bundle) throws java.io.FileNotFoundException, android.os.RemoteException;
method public android.database.Cursor query(android.net.Uri, java.lang.String[], java.lang.String, java.lang.String[], java.lang.String) throws android.os.RemoteException;
+ method public android.database.Cursor query(android.net.Uri, java.lang.String[], java.lang.String, java.lang.String[], java.lang.String, android.content.CancellationSignal) throws android.os.RemoteException;
method public boolean release();
method public int update(android.net.Uri, android.content.ContentValues, java.lang.String, java.lang.String[]) throws android.os.RemoteException;
}
@@ -4929,6 +4956,7 @@
method public final java.io.OutputStream openOutputStream(android.net.Uri, java.lang.String) throws java.io.FileNotFoundException;
method public final android.content.res.AssetFileDescriptor openTypedAssetFileDescriptor(android.net.Uri, java.lang.String, android.os.Bundle) throws java.io.FileNotFoundException;
method public final android.database.Cursor query(android.net.Uri, java.lang.String[], java.lang.String, java.lang.String[], java.lang.String);
+ method public final android.database.Cursor query(android.net.Uri, java.lang.String[], java.lang.String, java.lang.String[], java.lang.String, android.content.CancellationSignal);
method public final void registerContentObserver(android.net.Uri, boolean, android.database.ContentObserver);
method public static void removePeriodicSync(android.accounts.Account, java.lang.String, android.os.Bundle);
method public static void removeStatusChangeListener(java.lang.Object);
@@ -5351,6 +5379,7 @@
method public static android.content.Intent makeMainActivity(android.content.ComponentName);
method public static android.content.Intent makeMainSelectorActivity(java.lang.String, java.lang.String);
method public static android.content.Intent makeRestartActivityTask(android.content.ComponentName);
+ method public static java.lang.String normalizeMimeType(java.lang.String);
method public static android.content.Intent parseIntent(android.content.res.Resources, org.xmlpull.v1.XmlPullParser, android.util.AttributeSet) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException;
method public static android.content.Intent parseUri(java.lang.String, int) throws java.net.URISyntaxException;
method public android.content.Intent putCharSequenceArrayListExtra(java.lang.String, java.util.ArrayList<java.lang.CharSequence>);
@@ -5399,13 +5428,16 @@
method public android.content.Intent setClassName(java.lang.String, java.lang.String);
method public android.content.Intent setComponent(android.content.ComponentName);
method public android.content.Intent setData(android.net.Uri);
+ method public android.content.Intent setDataAndNormalize(android.net.Uri);
method public android.content.Intent setDataAndType(android.net.Uri, java.lang.String);
+ method public android.content.Intent setDataAndTypeAndNormalize(android.net.Uri, java.lang.String);
method public void setExtrasClassLoader(java.lang.ClassLoader);
method public android.content.Intent setFlags(int);
method public android.content.Intent setPackage(java.lang.String);
method public void setSelector(android.content.Intent);
method public void setSourceBounds(android.graphics.Rect);
method public android.content.Intent setType(java.lang.String);
+ method public android.content.Intent setTypeAndNormalize(java.lang.String);
method public deprecated java.lang.String toURI();
method public java.lang.String toUri(int);
method public void writeToParcel(android.os.Parcel, int);
@@ -5607,6 +5639,7 @@
field public static final int FLAG_GRANT_READ_URI_PERMISSION = 1; // 0x1
field public static final int FLAG_GRANT_WRITE_URI_PERMISSION = 2; // 0x2
field public static final int FLAG_INCLUDE_STOPPED_PACKAGES = 32; // 0x20
+ field public static final int FLAG_RECEIVER_FOREGROUND = 268435456; // 0x10000000
field public static final int FLAG_RECEIVER_REGISTERED_ONLY = 1073741824; // 0x40000000
field public static final int FLAG_RECEIVER_REPLACE_PENDING = 536870912; // 0x20000000
field public static final java.lang.String METADATA_DOCK_HOME = "android.dock_home";
@@ -5731,7 +5764,9 @@
public class Loader {
ctor public Loader(android.content.Context);
method public void abandon();
+ method public boolean cancelLoad();
method public java.lang.String dataToString(D);
+ method public void deliverCancellation();
method public void deliverResult(D);
method public void dump(java.lang.String, java.io.FileDescriptor, java.io.PrintWriter, java.lang.String[]);
method public void forceLoad();
@@ -5741,23 +5776,30 @@
method public boolean isReset();
method public boolean isStarted();
method protected void onAbandon();
+ method protected boolean onCancelLoad();
method public void onContentChanged();
method protected void onForceLoad();
method protected void onReset();
method protected void onStartLoading();
method protected void onStopLoading();
method public void registerListener(int, android.content.Loader.OnLoadCompleteListener<D>);
+ method public void registerOnLoadCanceledListener(android.content.Loader.OnLoadCanceledListener<D>);
method public void reset();
method public final void startLoading();
method public void stopLoading();
method public boolean takeContentChanged();
method public void unregisterListener(android.content.Loader.OnLoadCompleteListener<D>);
+ method public void unregisterOnLoadCanceledListener(android.content.Loader.OnLoadCanceledListener<D>);
}
public final class Loader.ForceLoadContentObserver extends android.database.ContentObserver {
ctor public Loader.ForceLoadContentObserver();
}
+ public static abstract interface Loader.OnLoadCanceledListener {
+ method public abstract void onLoadCanceled(android.content.Loader<D>);
+ }
+
public static abstract interface Loader.OnLoadCompleteListener {
method public abstract void onLoadComplete(android.content.Loader<D>, D);
}
@@ -5777,6 +5819,11 @@
method public int getNumSuccessfulYieldPoints();
}
+ public class OperationCanceledException extends java.lang.RuntimeException {
+ ctor public OperationCanceledException();
+ ctor public OperationCanceledException(java.lang.String);
+ }
+
public class PeriodicSync implements android.os.Parcelable {
ctor public PeriodicSync(android.accounts.Account, java.lang.String, android.os.Bundle, long);
method public int describeContents();
@@ -6791,16 +6838,19 @@
public class ContentObservable extends android.database.Observable {
ctor public ContentObservable();
- method public void dispatchChange(boolean);
- method public void notifyChange(boolean);
+ method public deprecated void dispatchChange(boolean);
+ method public void dispatchChange(boolean, android.net.Uri);
+ method public deprecated void notifyChange(boolean);
method public void registerObserver(android.database.ContentObserver);
}
public abstract class ContentObserver {
ctor public ContentObserver(android.os.Handler);
method public boolean deliverSelfNotifications();
- method public final void dispatchChange(boolean);
+ method public final deprecated void dispatchChange(boolean);
+ method public final void dispatchChange(boolean, android.net.Uri);
method public void onChange(boolean);
+ method public void onChange(boolean, android.net.Uri);
}
public abstract interface CrossProcessCursor implements android.database.Cursor {
@@ -6819,7 +6869,7 @@
public abstract interface Cursor {
method public abstract void close();
method public abstract void copyStringToBuffer(int, android.database.CharArrayBuffer);
- method public abstract void deactivate();
+ method public abstract deprecated void deactivate();
method public abstract byte[] getBlob(int);
method public abstract int getColumnCount();
method public abstract int getColumnIndex(java.lang.String);
@@ -7218,11 +7268,15 @@
method public static android.database.sqlite.SQLiteDatabase openOrCreateDatabase(java.lang.String, android.database.sqlite.SQLiteDatabase.CursorFactory);
method public static android.database.sqlite.SQLiteDatabase openOrCreateDatabase(java.lang.String, android.database.sqlite.SQLiteDatabase.CursorFactory, android.database.DatabaseErrorHandler);
method public android.database.Cursor query(boolean, java.lang.String, java.lang.String[], java.lang.String, java.lang.String[], java.lang.String, java.lang.String, java.lang.String, java.lang.String);
+ method public android.database.Cursor query(boolean, java.lang.String, java.lang.String[], java.lang.String, java.lang.String[], java.lang.String, java.lang.String, java.lang.String, java.lang.String, android.content.CancellationSignal);
method public android.database.Cursor query(java.lang.String, java.lang.String[], java.lang.String, java.lang.String[], java.lang.String, java.lang.String, java.lang.String);
method public android.database.Cursor query(java.lang.String, java.lang.String[], java.lang.String, java.lang.String[], java.lang.String, java.lang.String, java.lang.String, java.lang.String);
method public android.database.Cursor queryWithFactory(android.database.sqlite.SQLiteDatabase.CursorFactory, boolean, java.lang.String, java.lang.String[], java.lang.String, java.lang.String[], java.lang.String, java.lang.String, java.lang.String, java.lang.String);
+ method public android.database.Cursor queryWithFactory(android.database.sqlite.SQLiteDatabase.CursorFactory, boolean, java.lang.String, java.lang.String[], java.lang.String, java.lang.String[], java.lang.String, java.lang.String, java.lang.String, java.lang.String, android.content.CancellationSignal);
method public android.database.Cursor rawQuery(java.lang.String, java.lang.String[]);
+ method public android.database.Cursor rawQuery(java.lang.String, java.lang.String[], android.content.CancellationSignal);
method public android.database.Cursor rawQueryWithFactory(android.database.sqlite.SQLiteDatabase.CursorFactory, java.lang.String, java.lang.String[], java.lang.String);
+ method public android.database.Cursor rawQueryWithFactory(android.database.sqlite.SQLiteDatabase.CursorFactory, java.lang.String, java.lang.String[], java.lang.String, android.content.CancellationSignal);
method public static int releaseMemory();
method public long replace(java.lang.String, java.lang.String, android.content.ContentValues);
method public long replaceOrThrow(java.lang.String, java.lang.String, android.content.ContentValues) throws android.database.SQLException;
@@ -7344,6 +7398,7 @@
method public java.lang.String getTables();
method public android.database.Cursor query(android.database.sqlite.SQLiteDatabase, java.lang.String[], java.lang.String, java.lang.String[], java.lang.String, java.lang.String, java.lang.String);
method public android.database.Cursor query(android.database.sqlite.SQLiteDatabase, java.lang.String[], java.lang.String, java.lang.String[], java.lang.String, java.lang.String, java.lang.String, java.lang.String);
+ method public android.database.Cursor query(android.database.sqlite.SQLiteDatabase, java.lang.String[], java.lang.String, java.lang.String[], java.lang.String, java.lang.String, java.lang.String, java.lang.String, android.content.CancellationSignal);
method public void setCursorFactory(android.database.sqlite.SQLiteDatabase.CursorFactory);
method public void setDistinct(boolean);
method public void setProjectionMap(java.util.Map<java.lang.String, java.lang.String>);
@@ -7785,7 +7840,7 @@
package android.graphics {
- public class AvoidXfermode extends android.graphics.Xfermode {
+ public deprecated class AvoidXfermode extends android.graphics.Xfermode {
ctor public AvoidXfermode(int, int, android.graphics.AvoidXfermode.Mode);
}
@@ -8564,7 +8619,7 @@
field public int bytesPerPixel;
}
- public class PixelXorXfermode extends android.graphics.Xfermode {
+ public deprecated class PixelXorXfermode extends android.graphics.Xfermode {
ctor public PixelXorXfermode(int);
}
@@ -9047,14 +9102,17 @@
ctor public GradientDrawable(android.graphics.drawable.GradientDrawable.Orientation, int[]);
method public void draw(android.graphics.Canvas);
method public int getOpacity();
+ method public android.graphics.drawable.GradientDrawable.Orientation getOrientation();
method public void setAlpha(int);
method public void setColor(int);
method public void setColorFilter(android.graphics.ColorFilter);
+ method public void setColors(int[]);
method public void setCornerRadii(float[]);
method public void setCornerRadius(float);
method public void setGradientCenter(float, float);
method public void setGradientRadius(float);
method public void setGradientType(int);
+ method public void setOrientation(android.graphics.drawable.GradientDrawable.Orientation);
method public void setShape(int);
method public void setSize(int, int);
method public void setStroke(int, int);
@@ -10868,11 +10926,12 @@
}
public final class MediaRecorder.OutputFormat {
+ field public static final int AAC_ADTS = 6; // 0x6
field public static final int AMR_NB = 3; // 0x3
field public static final int AMR_WB = 4; // 0x4
field public static final int DEFAULT = 0; // 0x0
field public static final int MPEG_4 = 2; // 0x2
- field public static final int RAW_AMR = 3; // 0x3
+ field public static final deprecated int RAW_AMR = 3; // 0x3
field public static final int THREE_GPP = 1; // 0x1
}
@@ -11581,7 +11640,7 @@
method public void setNetworkPreference(int);
method public int startUsingNetworkFeature(int, java.lang.String);
method public int stopUsingNetworkFeature(int, java.lang.String);
- field public static final java.lang.String ACTION_BACKGROUND_DATA_SETTING_CHANGED = "android.net.conn.BACKGROUND_DATA_SETTING_CHANGED";
+ field public static final deprecated java.lang.String ACTION_BACKGROUND_DATA_SETTING_CHANGED = "android.net.conn.BACKGROUND_DATA_SETTING_CHANGED";
field public static final java.lang.String CONNECTIVITY_ACTION = "android.net.conn.CONNECTIVITY_CHANGE";
field public static final int DEFAULT_NETWORK_PREFERENCE = 1; // 0x1
field public static final java.lang.String EXTRA_EXTRA_INFO = "extraInfo";
@@ -11831,6 +11890,7 @@
method public abstract boolean isHierarchical();
method public boolean isOpaque();
method public abstract boolean isRelative();
+ method public android.net.Uri normalize();
method public static android.net.Uri parse(java.lang.String);
method public abstract java.lang.String toString();
method public static android.net.Uri withAppendedPath(android.net.Uri, java.lang.String);
@@ -12613,6 +12673,7 @@
ctor public NdefMessage(android.nfc.NdefRecord, android.nfc.NdefRecord...);
ctor public NdefMessage(android.nfc.NdefRecord[]);
method public int describeContents();
+ method public int getByteArrayLength();
method public android.nfc.NdefRecord[] getRecords();
method public byte[] toByteArray();
method public void writeToParcel(android.os.Parcel, int);
@@ -12633,6 +12694,8 @@
method public short getTnf();
method public byte[] getType();
method public deprecated byte[] toByteArray();
+ method public java.lang.String toMimeType();
+ method public android.net.Uri toUri();
method public void writeToParcel(android.os.Parcel, int);
field public static final android.os.Parcelable.Creator CREATOR;
field public static final byte[] RTD_ALTERNATIVE_CARRIER;
@@ -14424,6 +14487,7 @@
field public static final int HONEYCOMB_MR2 = 13; // 0xd
field public static final int ICE_CREAM_SANDWICH = 14; // 0xe
field public static final int ICE_CREAM_SANDWICH_MR1 = 15; // 0xf
+ field public static final int JELLY_BEAN = 10000; // 0x2710
}
public final class Bundle implements java.lang.Cloneable android.os.Parcelable {
@@ -17442,6 +17506,7 @@
field public static final android.net.Uri CONTENT_URI;
field public static final java.lang.String DATA_ROAMING = "data_roaming";
field public static final java.lang.String DEFAULT_INPUT_METHOD = "default_input_method";
+ field public static final java.lang.String DEVELOPMENT_SETTINGS_ENABLED = "development_settings_enabled";
field public static final java.lang.String DEVICE_PROVISIONED = "device_provisioned";
field public static final java.lang.String ENABLED_ACCESSIBILITY_SERVICES = "enabled_accessibility_services";
field public static final java.lang.String ENABLED_INPUT_METHODS = "enabled_input_methods";
@@ -17520,6 +17585,7 @@
field public static final java.lang.String ALARM_ALERT = "alarm_alert";
field public static final java.lang.String ALWAYS_FINISH_ACTIVITIES = "always_finish_activities";
field public static final deprecated java.lang.String ANDROID_ID = "android_id";
+ field public static final java.lang.String ANIMATOR_DURATION_SCALE = "animator_duration_scale";
field public static final java.lang.String APPEND_FOR_LAST_AUDIBLE = "_last_audible";
field public static final java.lang.String AUTO_TIME = "auto_time";
field public static final java.lang.String AUTO_TIME_ZONE = "auto_time_zone";
@@ -17560,6 +17626,7 @@
field public static final java.lang.String RADIO_NFC = "nfc";
field public static final java.lang.String RADIO_WIFI = "wifi";
field public static final java.lang.String RINGTONE = "ringtone";
+ field public static final java.lang.String SCREEN_AUTO_BRIGHTNESS_ADJ = "screen_auto_brightness_adj";
field public static final java.lang.String SCREEN_BRIGHTNESS = "screen_brightness";
field public static final java.lang.String SCREEN_BRIGHTNESS_MODE = "screen_brightness_mode";
field public static final int SCREEN_BRIGHTNESS_MODE_AUTOMATIC = 1; // 0x1
@@ -21387,6 +21454,7 @@
field public static final int DENSITY_MEDIUM = 160; // 0xa0
field public static final int DENSITY_TV = 213; // 0xd5
field public static final int DENSITY_XHIGH = 320; // 0x140
+ field public static final int DENSITY_XXHIGH = 480; // 0x1e0
field public float density;
field public int densityDpi;
field public int heightPixels;
@@ -23785,6 +23853,9 @@
method public android.view.ViewPropertyAnimator translationXBy(float);
method public android.view.ViewPropertyAnimator translationY(float);
method public android.view.ViewPropertyAnimator translationYBy(float);
+ method public android.view.ViewPropertyAnimator withEndAction(java.lang.Runnable);
+ method public android.view.ViewPropertyAnimator withLayer();
+ method public android.view.ViewPropertyAnimator withStartAction(java.lang.Runnable);
method public android.view.ViewPropertyAnimator x(float);
method public android.view.ViewPropertyAnimator xBy(float);
method public android.view.ViewPropertyAnimator y(float);
@@ -23817,8 +23888,9 @@
method public final void dispatchOnGlobalLayout();
method public final boolean dispatchOnPreDraw();
method public boolean isAlive();
- method public void removeGlobalOnLayoutListener(android.view.ViewTreeObserver.OnGlobalLayoutListener);
+ method public deprecated void removeGlobalOnLayoutListener(android.view.ViewTreeObserver.OnGlobalLayoutListener);
method public void removeOnGlobalFocusChangeListener(android.view.ViewTreeObserver.OnGlobalFocusChangeListener);
+ method public void removeOnGlobalLayoutListener(android.view.ViewTreeObserver.OnGlobalLayoutListener);
method public void removeOnPreDrawListener(android.view.ViewTreeObserver.OnPreDrawListener);
method public void removeOnScrollChangedListener(android.view.ViewTreeObserver.OnScrollChangedListener);
method public void removeOnTouchModeChangeListener(android.view.ViewTreeObserver.OnTouchModeChangeListener);
@@ -26671,6 +26743,7 @@
method public void setOnValueChangedListener(android.widget.NumberPicker.OnValueChangeListener);
method public void setValue(int);
method public void setWrapSelectorWheel(boolean);
+ field public static final int SELECTOR_WHEEL_ITEM_COUNT = 5; // 0x5
}
public static abstract interface NumberPicker.Formatter {
diff --git a/cmds/dumpstate/dumpstate.c b/cmds/dumpstate/dumpstate.c
index 83c881a..16dc517 100644
--- a/cmds/dumpstate/dumpstate.c
+++ b/cmds/dumpstate/dumpstate.c
@@ -122,7 +122,7 @@
dump_file("NETWORK DEV INFO", "/proc/net/dev");
dump_file("QTAGUID NETWORK INTERFACES INFO", "/proc/net/xt_qtaguid/iface_stat_all");
dump_file("QTAGUID CTRL INFO", "/proc/net/xt_qtaguid/ctrl");
- run_command("QTAGUID STATS INFO", 10, "su", "root", "cat", "/proc/net/xt_qtaguid/stats", NULL);
+ dump_file("QTAGUID STATS INFO", "/proc/net/xt_qtaguid/stats");
dump_file("NETWORK ROUTES", "/proc/net/route");
dump_file("NETWORK ROUTES IPV6", "/proc/net/ipv6_route");
@@ -334,7 +334,7 @@
}
/* switch to non-root user and group */
- gid_t groups[] = { AID_LOG, AID_SDCARD_RW, AID_MOUNT, AID_INET };
+ gid_t groups[] = { AID_LOG, AID_SDCARD_RW, AID_MOUNT, AID_INET, AID_NET_BW_STATS };
if (setgroups(sizeof(groups)/sizeof(groups[0]), groups) != 0) {
ALOGE("Unable to setgroups, aborting: %s\n", strerror(errno));
return -1;
diff --git a/cmds/servicemanager/Android.mk b/cmds/servicemanager/Android.mk
index ea80c7d..8840867 100644
--- a/cmds/servicemanager/Android.mk
+++ b/cmds/servicemanager/Android.mk
@@ -9,7 +9,4 @@
LOCAL_SHARED_LIBRARIES := liblog
LOCAL_SRC_FILES := service_manager.c binder.c
LOCAL_MODULE := servicemanager
-ifeq ($(BOARD_USE_LVMX),true)
- LOCAL_CFLAGS += -DLVMX
-endif
include $(BUILD_EXECUTABLE)
diff --git a/cmds/servicemanager/service_manager.c b/cmds/servicemanager/service_manager.c
index 42d8977..4ed2489 100644
--- a/cmds/servicemanager/service_manager.c
+++ b/cmds/servicemanager/service_manager.c
@@ -27,9 +27,6 @@
unsigned uid;
const char *name;
} allowed[] = {
-#ifdef LVMX
- { AID_MEDIA, "com.lifevibes.mx.ipc" },
-#endif
{ AID_MEDIA, "media.audio_flinger" },
{ AID_MEDIA, "media.player" },
{ AID_MEDIA, "media.camera" },
diff --git a/cmds/stagefright/record.cpp b/cmds/stagefright/record.cpp
index 613435d..7703058 100644
--- a/cmds/stagefright/record.cpp
+++ b/cmds/stagefright/record.cpp
@@ -38,7 +38,7 @@
static const int32_t kAudioBitRate = 12200;
static const int64_t kDurationUs = 10000000LL; // 10 seconds
-#if 1
+#if 0
class DummySource : public MediaSource {
public:
@@ -318,7 +318,7 @@
sp<MetaData> encMeta = new MetaData;
encMeta->setCString(kKeyMIMEType,
- 1 ? MEDIA_MIMETYPE_AUDIO_AMR_WB : MEDIA_MIMETYPE_AUDIO_AAC);
+ 0 ? MEDIA_MIMETYPE_AUDIO_AMR_WB : MEDIA_MIMETYPE_AUDIO_AAC);
encMeta->setInt32(kKeySampleRate, kSampleRate);
encMeta->setInt32(kKeyChannelCount, kNumChannels);
encMeta->setInt32(kKeyMaxInputSize, 8192);
diff --git a/core/java/android/accessibilityservice/AccessibilityService.java b/core/java/android/accessibilityservice/AccessibilityService.java
index 211be52..a463a62 100644
--- a/core/java/android/accessibilityservice/AccessibilityService.java
+++ b/core/java/android/accessibilityservice/AccessibilityService.java
@@ -17,8 +17,10 @@
package android.accessibilityservice;
import android.app.Service;
+import android.content.Context;
import android.content.Intent;
import android.os.IBinder;
+import android.os.Looper;
import android.os.Message;
import android.os.RemoteException;
import android.util.Log;
@@ -218,10 +220,17 @@
private static final String LOG_TAG = "AccessibilityService";
- private AccessibilityServiceInfo mInfo;
+ interface Callbacks {
+ public void onAccessibilityEvent(AccessibilityEvent event);
+ public void onInterrupt();
+ public void onServiceConnected();
+ public void onSetConnectionId(int connectionId);
+ }
private int mConnectionId;
+ private AccessibilityServiceInfo mInfo;
+
/**
* Callback for {@link android.view.accessibility.AccessibilityEvent}s.
*
@@ -282,27 +291,49 @@
*/
@Override
public final IBinder onBind(Intent intent) {
- return new IEventListenerWrapper(this);
+ return new IEventListenerWrapper(this, getMainLooper(), new Callbacks() {
+ @Override
+ public void onServiceConnected() {
+ AccessibilityService.this.onServiceConnected();
+ }
+
+ @Override
+ public void onInterrupt() {
+ AccessibilityService.this.onInterrupt();
+ }
+
+ @Override
+ public void onAccessibilityEvent(AccessibilityEvent event) {
+ AccessibilityService.this.onAccessibilityEvent(event);
+ }
+
+ @Override
+ public void onSetConnectionId( int connectionId) {
+ mConnectionId = connectionId;
+ }
+ });
}
/**
* Implements the internal {@link IEventListener} interface to convert
* incoming calls to it back to calls on an {@link AccessibilityService}.
*/
- class IEventListenerWrapper extends IEventListener.Stub
+ static class IEventListenerWrapper extends IEventListener.Stub
implements HandlerCaller.Callback {
+ static final int NO_ID = -1;
+
private static final int DO_SET_SET_CONNECTION = 10;
private static final int DO_ON_INTERRUPT = 20;
private static final int DO_ON_ACCESSIBILITY_EVENT = 30;
private final HandlerCaller mCaller;
- private final AccessibilityService mTarget;
+ private final Callbacks mCallback;
- public IEventListenerWrapper(AccessibilityService context) {
- mTarget = context;
- mCaller = new HandlerCaller(context, this);
+ public IEventListenerWrapper(Context context, Looper looper, Callbacks callback) {
+ mCallback = callback;
+ mCaller = new HandlerCaller(context, looper, this);
}
public void setConnection(IAccessibilityServiceConnection connection, int connectionId) {
@@ -326,12 +357,13 @@
case DO_ON_ACCESSIBILITY_EVENT :
AccessibilityEvent event = (AccessibilityEvent) message.obj;
if (event != null) {
- mTarget.onAccessibilityEvent(event);
+ AccessibilityInteractionClient.getInstance().onAccessibilityEvent(event);
+ mCallback.onAccessibilityEvent(event);
event.recycle();
}
return;
case DO_ON_INTERRUPT :
- mTarget.onInterrupt();
+ mCallback.onInterrupt();
return;
case DO_SET_SET_CONNECTION :
final int connectionId = message.arg1;
@@ -340,12 +372,11 @@
if (connection != null) {
AccessibilityInteractionClient.getInstance().addConnection(connectionId,
connection);
- mConnectionId = connectionId;
- mTarget.onServiceConnected();
+ mCallback.onSetConnectionId(connectionId);
+ mCallback.onServiceConnected();
} else {
AccessibilityInteractionClient.getInstance().removeConnection(connectionId);
- mConnectionId = AccessibilityInteractionClient.NO_ID;
- // TODO: Do we need a onServiceDisconnected callback?
+ mCallback.onSetConnectionId(AccessibilityInteractionClient.NO_ID);
}
return;
default :
diff --git a/core/java/android/accessibilityservice/IAccessibilityServiceConnection.aidl b/core/java/android/accessibilityservice/IAccessibilityServiceConnection.aidl
index e53b313..c9468eb 100644
--- a/core/java/android/accessibilityservice/IAccessibilityServiceConnection.aidl
+++ b/core/java/android/accessibilityservice/IAccessibilityServiceConnection.aidl
@@ -32,8 +32,13 @@
/**
* Finds an {@link AccessibilityNodeInfo} by accessibility id.
*
- * @param accessibilityWindowId A unique window id.
- * @param accessibilityNodeId A unique view id or virtual descendant id.
+ * @param accessibilityWindowId A unique window id. Use
+ * {@link com.android.server.accessibility.AccessibilityManagerService#ACTIVE_WINDOW_ID}
+ * to query the currently active window.
+ * @param accessibilityNodeId A unique view id or virtual descendant id from
+ * where to start the search. Use
+ * {@link com.android.server.accessibility.AccessibilityManagerService#ROOT_NODE_ID}
+ * to start from the root.
* @param interactionId The id of the interaction for matching with the callback result.
* @param callback Callback which to receive the result.
* @param threadId The id of the calling thread.
@@ -46,57 +51,58 @@
/**
* Finds {@link AccessibilityNodeInfo}s by View text. The match is case
* insensitive containment. The search is performed in the window whose
- * id is specified and starts from the View whose accessibility id is
+ * id is specified and starts from the node whose accessibility id is
* specified.
*
- * @param text The searched text.
- * @param accessibilityWindowId A unique window id.
+ * @param accessibilityWindowId A unique window id. Use
+ * {@link com.android.server.accessibility.AccessibilityManagerService#ACTIVE_WINDOW_ID}
+ * to query the currently active window.
* @param accessibilityNodeId A unique view id or virtual descendant id from
- * where to start the search. Use {@link android.view.View#NO_ID} to start from the root.
- * @param interactionId The id of the interaction for matching with the callback result.
- * @param callback Callback which to receive the result.
- * @param threadId The id of the calling thread.
- * @return The current window scale, where zero means a failure.
- */
- float findAccessibilityNodeInfosByText(String text, int accessibilityWindowId,
- long accessibilityNodeId, int interractionId,
- IAccessibilityInteractionConnectionCallback callback, long threadId);
-
- /**
- * Finds {@link AccessibilityNodeInfo}s by View text. The match is case
- * insensitive containment. The search is performed in the currently
- * active window and start from the root View in the window.
- *
+ * where to start the search. Use
+ * {@link com.android.server.accessibility.AccessibilityManagerService#ROOT_NODE_ID}
+ * to start from the root.
* @param text The searched text.
- * @param accessibilityId The id of the view from which to start searching.
- * Use {@link android.view.View#NO_ID} to start from the root.
* @param interactionId The id of the interaction for matching with the callback result.
* @param callback Callback which to receive the result.
* @param threadId The id of the calling thread.
* @return The current window scale, where zero means a failure.
*/
- float findAccessibilityNodeInfosByTextInActiveWindow(String text,
- int interactionId, IAccessibilityInteractionConnectionCallback callback,
+ float findAccessibilityNodeInfosByText(int accessibilityWindowId, long accessibilityNodeId,
+ String text, int interactionId, IAccessibilityInteractionConnectionCallback callback,
long threadId);
/**
- * Finds an {@link AccessibilityNodeInfo} by View id. The search is performed
- * in the currently active window and starts from the root View in the window.
+ * Finds an {@link AccessibilityNodeInfo} by View id. The search is performed in
+ * the window whose id is specified and starts from the node whose accessibility
+ * id is specified.
*
+ * @param accessibilityWindowId A unique window id. Use
+ * {@link com.android.server.accessibility.AccessibilityManagerService#ACTIVE_WINDOW_ID}
+ * to query the currently active window.
+ * @param accessibilityNodeId A unique view id or virtual descendant id from
+ * where to start the search. Use
+ * {@link com.android.server.accessibility.AccessibilityManagerService#ROOT_NODE_ID}
+ * to start from the root.
* @param id The id of the node.
* @param interactionId The id of the interaction for matching with the callback result.
* @param callback Callback which to receive the result.
* @param threadId The id of the calling thread.
* @return The current window scale, where zero means a failure.
*/
- float findAccessibilityNodeInfoByViewIdInActiveWindow(int viewId, int interactionId,
- IAccessibilityInteractionConnectionCallback callback, long threadId);
+ float findAccessibilityNodeInfoByViewId(int accessibilityWindowId, long accessibilityNodeId,
+ int viewId, int interactionId, IAccessibilityInteractionConnectionCallback callback,
+ long threadId);
/**
* Performs an accessibility action on an {@link AccessibilityNodeInfo}.
*
- * @param accessibilityWindowId The id of the window.
- * @param accessibilityNodeId A unique view id or virtual descendant id.
+ * @param accessibilityWindowId A unique window id. Use
+ * {@link com.android.server.accessibility.AccessibilityManagerService#ACTIVE_WINDOW_ID}
+ * to query the currently active window.
+ * @param accessibilityNodeId A unique view id or virtual descendant id from
+ * where to start the search. Use
+ * {@link com.android.server.accessibility.AccessibilityManagerService#ROOT_NODE_ID}
+ * to start from the root.
* @param action The action to perform.
* @param interactionId The id of the interaction for matching with the callback result.
* @param callback Callback which to receive the result.
diff --git a/core/java/android/accessibilityservice/UiTestAutomationBridge.java b/core/java/android/accessibilityservice/UiTestAutomationBridge.java
new file mode 100644
index 0000000..9d48efc
--- /dev/null
+++ b/core/java/android/accessibilityservice/UiTestAutomationBridge.java
@@ -0,0 +1,418 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.accessibilityservice;
+
+import android.accessibilityservice.AccessibilityService.Callbacks;
+import android.accessibilityservice.AccessibilityService.IEventListenerWrapper;
+import android.content.Context;
+import android.os.HandlerThread;
+import android.os.Looper;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.os.SystemClock;
+import android.util.Log;
+import android.view.accessibility.AccessibilityEvent;
+import android.view.accessibility.AccessibilityInteractionClient;
+import android.view.accessibility.AccessibilityNodeInfo;
+import android.view.accessibility.IAccessibilityManager;
+
+import com.android.internal.util.Predicate;
+
+import java.util.List;
+import java.util.concurrent.TimeoutException;
+
+/**
+ * This class represents a bridge that can be used for UI test
+ * automation. It is responsible for connecting to the system,
+ * keeping track of the last accessibility event, and exposing
+ * window content querying APIs. This class is designed to be
+ * used from both an Android application and a Java program
+ * run from the shell.
+ *
+ * @hide
+ */
+public class UiTestAutomationBridge {
+
+ private static final String LOG_TAG = UiTestAutomationBridge.class.getSimpleName();
+
+ public static final int ACTIVE_WINDOW_ID = -1;
+
+ public static final long ROOT_NODE_ID = -1;
+
+ private static final int TIMEOUT_REGISTER_SERVICE = 5000;
+
+ private final Object mLock = new Object();
+
+ private volatile int mConnectionId = AccessibilityInteractionClient.NO_ID;
+
+ private IEventListenerWrapper mListener;
+
+ private AccessibilityEvent mLastEvent;
+
+ private volatile boolean mWaitingForEventDelivery;
+
+ private volatile boolean mUnprocessedEventAvailable;
+
+ /**
+ * Gets the last received {@link AccessibilityEvent}.
+ *
+ * @return The event.
+ */
+ public AccessibilityEvent getLastAccessibilityEvent() {
+ return mLastEvent;
+ }
+
+ /**
+ * Callback for receiving an {@link AccessibilityEvent}.
+ *
+ * <strong>Note:</strong> This method is <strong>NOT</strong>
+ * executed on the application main thread. The client are
+ * responsible for proper synchronization.
+ *
+ * @param event The received event.
+ */
+ public void onAccessibilityEvent(AccessibilityEvent event) {
+ /* hook - do nothing */
+ }
+
+ /**
+ * Callback for requests to stop feedback.
+ *
+ * <strong>Note:</strong> This method is <strong>NOT</strong>
+ * executed on the application main thread. The client are
+ * responsible for proper synchronization.
+ */
+ public void onInterrupt() {
+ /* hook - do nothing */
+ }
+
+ /**
+ * Connects this service.
+ *
+ * @throws IllegalStateException If already connected.
+ */
+ public void connect() {
+ if (isConnected()) {
+ throw new IllegalStateException("Already connected.");
+ }
+
+ // Serialize binder calls to a handler on a dedicated thread
+ // different from the main since we expose APIs that block
+ // the main thread waiting for a result the deliver of which
+ // on the main thread will prevent that thread from waking up.
+ // The serialization is needed also to ensure that events are
+ // examined in delivery order. Otherwise, a fair locking
+ // is needed for making sure the binder calls are interleaved
+ // with check for the expected event and also to make sure the
+ // binder threads are allowed to proceed in the received order.
+ HandlerThread handlerThread = new HandlerThread("UiTestAutomationBridge");
+ handlerThread.start();
+ Looper looper = handlerThread.getLooper();
+
+ mListener = new IEventListenerWrapper(null, looper, new Callbacks() {
+ @Override
+ public void onServiceConnected() {
+ /* do nothing */
+ }
+
+ @Override
+ public void onInterrupt() {
+ UiTestAutomationBridge.this.onInterrupt();
+ }
+
+ @Override
+ public void onAccessibilityEvent(AccessibilityEvent event) {
+ synchronized (mLock) {
+ while (true) {
+ if (!mWaitingForEventDelivery) {
+ break;
+ }
+ if (!mUnprocessedEventAvailable) {
+ mUnprocessedEventAvailable = true;
+ mLastEvent = AccessibilityEvent.obtain(event);
+ mLock.notifyAll();
+ break;
+ }
+ try {
+ mLock.wait();
+ } catch (InterruptedException ie) {
+ /* ignore */
+ }
+ }
+ }
+ UiTestAutomationBridge.this.onAccessibilityEvent(event);
+ }
+
+ @Override
+ public void onSetConnectionId(int connectionId) {
+ synchronized (mLock) {
+ mConnectionId = connectionId;
+ mLock.notifyAll();
+ }
+ }
+ });
+
+ final IAccessibilityManager manager = IAccessibilityManager.Stub.asInterface(
+ ServiceManager.getService(Context.ACCESSIBILITY_SERVICE));
+
+ final AccessibilityServiceInfo info = new AccessibilityServiceInfo();
+ info.eventTypes = AccessibilityEvent.TYPES_ALL_MASK;
+ info.feedbackType = AccessibilityServiceInfo.FEEDBACK_GENERIC;
+
+ try {
+ manager.registerUiTestAutomationService(mListener, info);
+ } catch (RemoteException re) {
+ throw new IllegalStateException("Cound not register UiAutomationService.", re);
+ }
+
+ synchronized (mLock) {
+ final long startTimeMillis = SystemClock.uptimeMillis();
+ while (true) {
+ if (isConnected()) {
+ return;
+ }
+ final long elapsedTimeMillis = SystemClock.uptimeMillis() - startTimeMillis;
+ final long remainingTimeMillis = TIMEOUT_REGISTER_SERVICE - elapsedTimeMillis;
+ if (remainingTimeMillis <= 0) {
+ throw new IllegalStateException("Cound not register UiAutomationService.");
+ }
+ try {
+ mLock.wait(remainingTimeMillis);
+ } catch (InterruptedException ie) {
+ /* ignore */
+ }
+ }
+ }
+ }
+
+ /**
+ * Disconnects this service.
+ *
+ * @throws IllegalStateException If already disconnected.
+ */
+ public void disconnect() {
+ if (!isConnected()) {
+ throw new IllegalStateException("Already disconnected.");
+ }
+
+ IAccessibilityManager manager = IAccessibilityManager.Stub.asInterface(
+ ServiceManager.getService(Context.ACCESSIBILITY_SERVICE));
+
+ try {
+ manager.unregisterUiTestAutomationService(mListener);
+ } catch (RemoteException re) {
+ Log.e(LOG_TAG, "Error while unregistering UiTestAutomationService", re);
+ }
+ }
+
+ /**
+ * Gets whether this service is connected.
+ *
+ * @return True if connected.
+ */
+ public boolean isConnected() {
+ return (mConnectionId != AccessibilityInteractionClient.NO_ID);
+ }
+
+ /**
+ * Executes a command and waits for a specific accessibility event type up
+ * to a given timeout.
+ *
+ * @param command The command to execute before starting to wait for the event.
+ * @param predicate Predicate for recognizing the awaited event.
+ * @param timeoutMillis The max wait time in milliseconds.
+ */
+ public AccessibilityEvent executeCommandAndWaitForAccessibilityEvent(Runnable command,
+ Predicate<AccessibilityEvent> predicate, long timeoutMillis)
+ throws TimeoutException, Exception {
+ synchronized (mLock) {
+ // Prepare to wait for an event.
+ mWaitingForEventDelivery = true;
+ mUnprocessedEventAvailable = false;
+ if (mLastEvent != null) {
+ mLastEvent.recycle();
+ mLastEvent = null;
+ }
+ // Execute the command.
+ command.run();
+ // Wait for the event.
+ final long startTimeMillis = SystemClock.uptimeMillis();
+ while (true) {
+ // If the expected event is received, that's it.
+ if ((mUnprocessedEventAvailable && predicate.apply(mLastEvent))) {
+ mWaitingForEventDelivery = false;
+ mUnprocessedEventAvailable = false;
+ mLock.notifyAll();
+ return mLastEvent;
+ }
+ // Ask for another event.
+ mWaitingForEventDelivery = true;
+ mUnprocessedEventAvailable = false;
+ mLock.notifyAll();
+ // Check if timed out and if not wait.
+ final long elapsedTimeMillis = SystemClock.uptimeMillis() - startTimeMillis;
+ final long remainingTimeMillis = timeoutMillis - elapsedTimeMillis;
+ if (remainingTimeMillis <= 0) {
+ mWaitingForEventDelivery = false;
+ mUnprocessedEventAvailable = false;
+ mLock.notifyAll();
+ throw new TimeoutException("Expacted event not received within: "
+ + timeoutMillis + " ms.");
+ }
+ try {
+ mLock.wait(remainingTimeMillis);
+ } catch (InterruptedException ie) {
+ /* ignore */
+ }
+ }
+ }
+ }
+
+ /**
+ * Finds an {@link AccessibilityNodeInfo} by accessibility id in the active
+ * window. The search is performed from the root node.
+ *
+ * @param accessibilityNodeId A unique view id or virtual descendant id for
+ * which to search.
+ * @return The current window scale, where zero means a failure.
+ */
+ public AccessibilityNodeInfo findAccessibilityNodeInfoByAccessibilityIdInActiveWindow(
+ long accessibilityNodeId) {
+ return findAccessibilityNodeInfoByAccessibilityId(ACTIVE_WINDOW_ID, accessibilityNodeId);
+ }
+
+ /**
+ * Finds an {@link AccessibilityNodeInfo} by accessibility id.
+ *
+ * @param accessibilityWindowId A unique window id. Use {@link #ACTIVE_WINDOW_ID}
+ * to query the currently active window.
+ * @param accessibilityNodeId A unique view id or virtual descendant id for
+ * which to search.
+ * @return The current window scale, where zero means a failure.
+ */
+ public AccessibilityNodeInfo findAccessibilityNodeInfoByAccessibilityId(
+ int accessibilityWindowId, long accessibilityNodeId) {
+ // Cache the id to avoid locking
+ final int connectionId = mConnectionId;
+ ensureValidConnection(connectionId);
+ return AccessibilityInteractionClient.getInstance()
+ .findAccessibilityNodeInfoByAccessibilityId(mConnectionId,
+ accessibilityWindowId, accessibilityNodeId);
+ }
+
+ /**
+ * Finds an {@link AccessibilityNodeInfo} by View id in the active
+ * window. The search is performed from the root node.
+ *
+ * @return The current window scale, where zero means a failure.
+ */
+ public AccessibilityNodeInfo findAccessibilityNodeInfoByViewIdInActiveWindow(int viewId) {
+ return findAccessibilityNodeInfoByViewId(ACTIVE_WINDOW_ID, ROOT_NODE_ID, viewId);
+ }
+
+ /**
+ * Finds an {@link AccessibilityNodeInfo} by View id. The search is performed in
+ * the window whose id is specified and starts from the node whose accessibility
+ * id is specified.
+ *
+ * @param accessibilityWindowId A unique window id. Use {@link #ACTIVE_WINDOW_ID}
+ * to query the currently active window.
+ * @param accessibilityNodeId A unique view id or virtual descendant id from
+ * where to start the search. Use {@link #ROOT_NODE_ID} to start from the root.
+ * @return The current window scale, where zero means a failure.
+ */
+ public AccessibilityNodeInfo findAccessibilityNodeInfoByViewId(int accessibilityWindowId,
+ long accessibilityNodeId, int viewId) {
+ // Cache the id to avoid locking
+ final int connectionId = mConnectionId;
+ ensureValidConnection(connectionId);
+ return AccessibilityInteractionClient.getInstance()
+ .findAccessibilityNodeInfoByViewId(connectionId, accessibilityWindowId,
+ accessibilityNodeId, viewId);
+ }
+
+ /**
+ * Finds {@link AccessibilityNodeInfo}s by View text in the active
+ * window. The search is performed from the root node.
+ *
+ * @param text The searched text.
+ * @return The current window scale, where zero means a failure.
+ */
+ public List<AccessibilityNodeInfo> findAccessibilityNodeInfosByTextInActiveWindow(String text) {
+ return findAccessibilityNodeInfosByText(ACTIVE_WINDOW_ID, ROOT_NODE_ID, text);
+ }
+
+ /**
+ * Finds {@link AccessibilityNodeInfo}s by View text. The match is case
+ * insensitive containment. The search is performed in the window whose
+ * id is specified and starts from the node whose accessibility id is
+ * specified.
+ *
+ * @param accessibilityWindowId A unique window id. Use {@link #ACTIVE_WINDOW_ID}
+ * to query the currently active window.
+ * @param accessibilityNodeId A unique view id or virtual descendant id from
+ * where to start the search. Use {@link #ROOT_NODE_ID} to start from the root.
+ * @param text The searched text.
+ * @return The current window scale, where zero means a failure.
+ */
+ public List<AccessibilityNodeInfo> findAccessibilityNodeInfosByText(int accessibilityWindowId,
+ long accessibilityNodeId, String text) {
+ // Cache the id to avoid locking
+ final int connectionId = mConnectionId;
+ ensureValidConnection(connectionId);
+ return AccessibilityInteractionClient.getInstance()
+ .findAccessibilityNodeInfosByText(connectionId, accessibilityWindowId,
+ accessibilityNodeId, text);
+ }
+
+ /**
+ * Performs an accessibility action on an {@link AccessibilityNodeInfo}
+ * in the active window.
+ *
+ * @param accessibilityNodeId A unique node id (accessibility and virtual descendant id).
+ * @param action The action to perform.
+ * @return Whether the action was performed.
+ */
+ public boolean performAccessibilityActionInActiveWindow(long accessibilityNodeId, int action) {
+ return performAccessibilityAction(ACTIVE_WINDOW_ID, accessibilityNodeId, action);
+ }
+
+ /**
+ * Performs an accessibility action on an {@link AccessibilityNodeInfo}.
+ *
+ * @param accessibilityWindowId A unique window id. Use {@link #ACTIVE_WINDOW_ID}
+ * to query the currently active window.
+ * @param accessibilityNodeId A unique node id (accessibility and virtual descendant id).
+ * @param action The action to perform.
+ * @return Whether the action was performed.
+ */
+ public boolean performAccessibilityAction(int accessibilityWindowId, long accessibilityNodeId,
+ int action) {
+ // Cache the id to avoid locking
+ final int connectionId = mConnectionId;
+ ensureValidConnection(connectionId);
+ return AccessibilityInteractionClient.getInstance().performAccessibilityAction(connectionId,
+ accessibilityWindowId, accessibilityNodeId, action);
+ }
+
+ private void ensureValidConnection(int connectionId) {
+ if (connectionId == AccessibilityInteractionClient.NO_ID) {
+ throw new IllegalStateException("UiAutomationService not connected."
+ + " Did you call #register()?");
+ }
+ }
+}
diff --git a/core/java/android/accounts/AccountManagerService.java b/core/java/android/accounts/AccountManagerService.java
index 4f3405b..5fee4de 100644
--- a/core/java/android/accounts/AccountManagerService.java
+++ b/core/java/android/accounts/AccountManagerService.java
@@ -62,6 +62,7 @@
import java.util.Collection;
import java.util.HashMap;
import java.util.LinkedHashMap;
+import java.util.Map;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicReference;
@@ -275,7 +276,7 @@
accountNames.add(accountName);
}
}
- for (HashMap.Entry<String, ArrayList<String>> cur
+ for (Map.Entry<String, ArrayList<String>> cur
: accountNamesByType.entrySet()) {
final String accountType = cur.getKey();
final ArrayList<String> accountNames = cur.getValue();
diff --git a/core/java/android/animation/LayoutTransition.java b/core/java/android/animation/LayoutTransition.java
index 894f428..634e4d8 100644
--- a/core/java/android/animation/LayoutTransition.java
+++ b/core/java/android/animation/LayoutTransition.java
@@ -960,17 +960,17 @@
if (anim instanceof ObjectAnimator) {
((ObjectAnimator) anim).setCurrentPlayTime(0);
}
- if (mListeners != null) {
- anim.addListener(new AnimatorListenerAdapter() {
- @Override
- public void onAnimationEnd(Animator anim) {
- currentAppearingAnimations.remove(child);
+ anim.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator anim) {
+ currentAppearingAnimations.remove(child);
+ if (mListeners != null) {
for (TransitionListener listener : mListeners) {
listener.endTransition(LayoutTransition.this, parent, child, APPEARING);
}
}
- });
- }
+ }
+ });
currentAppearingAnimations.put(child, anim);
anim.start();
}
@@ -998,17 +998,19 @@
anim.setStartDelay(mDisappearingDelay);
anim.setDuration(mDisappearingDuration);
anim.setTarget(child);
- if (mListeners != null) {
- anim.addListener(new AnimatorListenerAdapter() {
- @Override
- public void onAnimationEnd(Animator anim) {
- currentDisappearingAnimations.remove(child);
+ final float preAnimAlpha = child.getAlpha();
+ anim.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator anim) {
+ currentDisappearingAnimations.remove(child);
+ child.setAlpha(preAnimAlpha);
+ if (mListeners != null) {
for (TransitionListener listener : mListeners) {
listener.endTransition(LayoutTransition.this, parent, child, DISAPPEARING);
}
}
- });
- }
+ }
+ });
if (anim instanceof ObjectAnimator) {
((ObjectAnimator) anim).setCurrentPlayTime(0);
}
@@ -1024,18 +1026,25 @@
*
* @param parent The ViewGroup to which the View is being added.
* @param child The View being added to the ViewGroup.
+ * @param changesLayout Whether the removal will cause changes in the layout of other views
+ * in the container. INVISIBLE views becoming VISIBLE will not cause changes and thus will not
+ * affect CHANGE_APPEARING or CHANGE_DISAPPEARING animations.
*/
- public void addChild(ViewGroup parent, View child) {
+ private void addChild(ViewGroup parent, View child, boolean changesLayout) {
// Want disappearing animations to finish up before proceeding
cancel(DISAPPEARING);
- // Also, cancel changing animations so that we start fresh ones from current locations
- cancel(CHANGE_APPEARING);
+ if (changesLayout) {
+ // Also, cancel changing animations so that we start fresh ones from current locations
+ cancel(CHANGE_APPEARING);
+ }
if (mListeners != null) {
for (TransitionListener listener : mListeners) {
listener.startTransition(this, parent, child, APPEARING);
}
}
- runChangeTransition(parent, child, APPEARING);
+ if (changesLayout) {
+ runChangeTransition(parent, child, APPEARING);
+ }
runAppearingTransition(parent, child);
}
@@ -1048,8 +1057,31 @@
* @param parent The ViewGroup to which the View is being added.
* @param child The View being added to the ViewGroup.
*/
+ public void addChild(ViewGroup parent, View child) {
+ addChild(parent, child, true);
+ }
+
+ /**
+ * @deprecated Use {@link #showChild(android.view.ViewGroup, android.view.View, int)}.
+ */
+ @Deprecated
public void showChild(ViewGroup parent, View child) {
- addChild(parent, child);
+ addChild(parent, child, true);
+ }
+
+ /**
+ * This method is called by ViewGroup when a child view is about to be made visible in the
+ * container. This callback starts the process of a transition; we grab the starting
+ * values, listen for changes to all of the children of the container, and start appropriate
+ * animations.
+ *
+ * @param parent The ViewGroup in which the View is being made visible.
+ * @param child The View being made visible.
+ * @param oldVisibility The previous visibility value of the child View, either
+ * {@link View#GONE} or {@link View#INVISIBLE}.
+ */
+ public void showChild(ViewGroup parent, View child, int oldVisibility) {
+ addChild(parent, child, oldVisibility == View.GONE);
}
/**
@@ -1060,18 +1092,25 @@
*
* @param parent The ViewGroup from which the View is being removed.
* @param child The View being removed from the ViewGroup.
+ * @param changesLayout Whether the removal will cause changes in the layout of other views
+ * in the container. Views becoming INVISIBLE will not cause changes and thus will not
+ * affect CHANGE_APPEARING or CHANGE_DISAPPEARING animations.
*/
- public void removeChild(ViewGroup parent, View child) {
+ private void removeChild(ViewGroup parent, View child, boolean changesLayout) {
// Want appearing animations to finish up before proceeding
cancel(APPEARING);
- // Also, cancel changing animations so that we start fresh ones from current locations
- cancel(CHANGE_DISAPPEARING);
+ if (changesLayout) {
+ // Also, cancel changing animations so that we start fresh ones from current locations
+ cancel(CHANGE_DISAPPEARING);
+ }
if (mListeners != null) {
for (TransitionListener listener : mListeners) {
listener.startTransition(this, parent, child, DISAPPEARING);
}
}
- runChangeTransition(parent, child, DISAPPEARING);
+ if (changesLayout) {
+ runChangeTransition(parent, child, DISAPPEARING);
+ }
runDisappearingTransition(parent, child);
}
@@ -1084,8 +1123,31 @@
* @param parent The ViewGroup from which the View is being removed.
* @param child The View being removed from the ViewGroup.
*/
+ public void removeChild(ViewGroup parent, View child) {
+ removeChild(parent, child, true);
+ }
+
+ /**
+ * @deprecated Use {@link #hideChild(android.view.ViewGroup, android.view.View, int)}.
+ */
+ @Deprecated
public void hideChild(ViewGroup parent, View child) {
- removeChild(parent, child);
+ removeChild(parent, child, true);
+ }
+
+ /**
+ * This method is called by ViewGroup when a child view is about to be hidden in
+ * container. This callback starts the process of a transition; we grab the starting
+ * values, listen for changes to all of the children of the container, and start appropriate
+ * animations.
+ *
+ * @param parent The parent ViewGroup of the View being hidden.
+ * @param child The View being hidden.
+ * @param newVisibility The new visibility value of the child View, either
+ * {@link View#GONE} or {@link View#INVISIBLE}.
+ */
+ public void hideChild(ViewGroup parent, View child, int newVisibility) {
+ removeChild(parent, child, newVisibility == View.GONE);
}
/**
diff --git a/core/java/android/animation/ValueAnimator.java b/core/java/android/animation/ValueAnimator.java
index c7a129e..cc1efb9 100755
--- a/core/java/android/animation/ValueAnimator.java
+++ b/core/java/android/animation/ValueAnimator.java
@@ -19,6 +19,7 @@
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
+import android.os.SystemProperties;
import android.util.AndroidRuntimeException;
import android.view.Choreographer;
import android.view.animation.AccelerateDecelerateInterpolator;
@@ -52,6 +53,7 @@
/**
* Internal constants
*/
+ private static float sDurationScale = 1.0f;
/**
* Messages sent to timing handler: START is sent when an animation first begins.
@@ -158,10 +160,12 @@
//
// How long the animation should last in ms
- private long mDuration = 300;
+ private long mDuration = (long)(300 * sDurationScale);
+ private long mUnscaledDuration = 300;
// The amount of time in ms to delay starting the animation after start() is called
private long mStartDelay = 0;
+ private long mUnscaledStartDelay = 0;
// The number of times the animation will repeat. The default is 0, which means the animation
// will play only once
@@ -217,6 +221,14 @@
*/
public static final int INFINITE = -1;
+
+ /**
+ * @hide
+ */
+ public static void setDurationScale(float durationScale) {
+ sDurationScale = durationScale;
+ }
+
/**
* Creates a new ValueAnimator object. This default constructor is primarily for
* use internally; the factory methods which take parameters are more generally
@@ -453,7 +465,8 @@
throw new IllegalArgumentException("Animators cannot have negative duration: " +
duration);
}
- mDuration = duration;
+ mUnscaledDuration = duration;
+ mDuration = (long)(duration * sDurationScale);
return this;
}
@@ -463,7 +476,7 @@
* @return The length of the animation, in milliseconds.
*/
public long getDuration() {
- return mDuration;
+ return mUnscaledDuration;
}
/**
@@ -658,7 +671,7 @@
* @return the number of milliseconds to delay running the animation
*/
public long getStartDelay() {
- return mStartDelay;
+ return mUnscaledStartDelay;
}
/**
@@ -668,7 +681,8 @@
* @param startDelay The amount of the delay, in milliseconds
*/
public void setStartDelay(long startDelay) {
- this.mStartDelay = startDelay;
+ this.mStartDelay = (long)(startDelay * sDurationScale);
+ mUnscaledStartDelay = startDelay;
}
/**
diff --git a/core/java/android/annotation/SuppressLint.java b/core/java/android/annotation/SuppressLint.java
new file mode 100644
index 0000000..2d3456b
--- /dev/null
+++ b/core/java/android/annotation/SuppressLint.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.annotation;
+
+import static java.lang.annotation.ElementType.CONSTRUCTOR;
+import static java.lang.annotation.ElementType.FIELD;
+import static java.lang.annotation.ElementType.LOCAL_VARIABLE;
+import static java.lang.annotation.ElementType.METHOD;
+import static java.lang.annotation.ElementType.PARAMETER;
+import static java.lang.annotation.ElementType.TYPE;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/** Indicates that Lint should ignore the specified warnings for the annotated element. */
+@Target({TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE})
+@Retention(RetentionPolicy.CLASS)
+public @interface SuppressLint {
+ /**
+ * The set of warnings (identified by the lint issue id) that should be
+ * ignored by lint. It is not an error to specify an unrecognized name.
+ */
+ String[] value();
+}
diff --git a/core/java/android/annotation/TargetApi.java b/core/java/android/annotation/TargetApi.java
new file mode 100644
index 0000000..ea17890
--- /dev/null
+++ b/core/java/android/annotation/TargetApi.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.annotation;
+
+import static java.lang.annotation.ElementType.CONSTRUCTOR;
+import static java.lang.annotation.ElementType.METHOD;
+import static java.lang.annotation.ElementType.TYPE;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/** Indicates that Lint should treat this type as targeting a given API level, no matter what the
+ project target is. */
+@Target({TYPE, METHOD, CONSTRUCTOR})
+@Retention(RetentionPolicy.CLASS)
+public @interface TargetApi {
+ /**
+ * This sets the target api level for the type..
+ */
+ int value();
+}
diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java
index 4fe9cef..9661b9e 100644
--- a/core/java/android/app/ActivityManager.java
+++ b/core/java/android/app/ActivityManager.java
@@ -1442,9 +1442,10 @@
public int getLauncherLargeIconDensity() {
final Resources res = mContext.getResources();
final int density = res.getDisplayMetrics().densityDpi;
+ final int sw = res.getConfiguration().smallestScreenWidthDp;
- if ((res.getConfiguration().screenLayout & Configuration.SCREENLAYOUT_SIZE_MASK)
- != Configuration.SCREENLAYOUT_SIZE_XLARGE) {
+ if (sw < 600) {
+ // Smaller than approx 7" tablets, use the regular icon size.
return density;
}
@@ -1456,9 +1457,13 @@
case DisplayMetrics.DENSITY_HIGH:
return DisplayMetrics.DENSITY_XHIGH;
case DisplayMetrics.DENSITY_XHIGH:
- return DisplayMetrics.DENSITY_MEDIUM * 2;
+ return DisplayMetrics.DENSITY_XXHIGH;
+ case DisplayMetrics.DENSITY_XXHIGH:
+ return DisplayMetrics.DENSITY_XHIGH * 2;
default:
- return density;
+ // The density is some abnormal value. Return some other
+ // abnormal value that is a reasonable scaling of it.
+ return (int)(density*1.5f);
}
}
@@ -1471,9 +1476,10 @@
public int getLauncherLargeIconSize() {
final Resources res = mContext.getResources();
final int size = res.getDimensionPixelSize(android.R.dimen.app_icon_size);
+ final int sw = res.getConfiguration().smallestScreenWidthDp;
- if ((res.getConfiguration().screenLayout & Configuration.SCREENLAYOUT_SIZE_MASK)
- != Configuration.SCREENLAYOUT_SIZE_XLARGE) {
+ if (sw < 600) {
+ // Smaller than approx 7" tablets, use the regular icon size.
return size;
}
@@ -1487,9 +1493,13 @@
case DisplayMetrics.DENSITY_HIGH:
return (size * DisplayMetrics.DENSITY_XHIGH) / DisplayMetrics.DENSITY_HIGH;
case DisplayMetrics.DENSITY_XHIGH:
- return (size * DisplayMetrics.DENSITY_MEDIUM * 2) / DisplayMetrics.DENSITY_XHIGH;
+ return (size * DisplayMetrics.DENSITY_XXHIGH) / DisplayMetrics.DENSITY_XHIGH;
+ case DisplayMetrics.DENSITY_XXHIGH:
+ return (size * DisplayMetrics.DENSITY_XHIGH*2) / DisplayMetrics.DENSITY_XXHIGH;
default:
- return size;
+ // The density is some abnormal value. Return some other
+ // abnormal value that is a reasonable scaling of it.
+ return (int)(size*1.5f);
}
}
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index 455d2f0..3c5f53a 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -3741,7 +3741,6 @@
}
final void handleTrimMemory(int level) {
- WindowManagerImpl.getDefault().trimMemory(level);
ArrayList<ComponentCallbacks2> callbacks;
synchronized (mPackages) {
@@ -3752,6 +3751,7 @@
for (int i=0; i<N; i++) {
callbacks.get(i).onTrimMemory(level);
}
+ WindowManagerImpl.getDefault().trimMemory(level);
}
private void setupGraphicsSupport(LoadedApk info) {
@@ -3804,7 +3804,7 @@
// implementation to use the pool executor. Normally, we use the
// serialized executor as the default. This has to happen in the
// main thread so the main looper is set right.
- if (data.appInfo.targetSdkVersion <= 12) {
+ if (data.appInfo.targetSdkVersion <= android.os.Build.VERSION_CODES.HONEYCOMB_MR1) {
AsyncTask.setDefaultExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
}
@@ -4413,7 +4413,7 @@
});
}
- public static final ActivityThread systemMain() {
+ public static ActivityThread systemMain() {
HardwareRenderer.disable(true);
ActivityThread thread = new ActivityThread();
thread.attach(true);
@@ -4454,6 +4454,8 @@
ActivityThread thread = new ActivityThread();
thread.attach(false);
+ AsyncTask.init();
+
if (false) {
Looper.myLooper().setMessageLogging(new
LogPrinter(Log.DEBUG, "ActivityThread"));
diff --git a/core/java/android/app/LoaderManager.java b/core/java/android/app/LoaderManager.java
index d83d2e6..ff71ee7 100644
--- a/core/java/android/app/LoaderManager.java
+++ b/core/java/android/app/LoaderManager.java
@@ -17,6 +17,7 @@
package android.app;
import android.content.Loader;
+import android.content.Loader.OnLoadCanceledListener;
import android.os.Bundle;
import android.util.DebugUtils;
import android.util.Log;
@@ -219,7 +220,8 @@
boolean mCreatingLoader;
- final class LoaderInfo implements Loader.OnLoadCompleteListener<Object> {
+ final class LoaderInfo implements Loader.OnLoadCompleteListener<Object>,
+ Loader.OnLoadCanceledListener<Object> {
final int mId;
final Bundle mArgs;
LoaderManager.LoaderCallbacks<Object> mCallbacks;
@@ -271,6 +273,7 @@
}
if (!mListenerRegistered) {
mLoader.registerListener(mId, this);
+ mLoader.registerOnLoadCanceledListener(this);
mListenerRegistered = true;
}
mLoader.startLoading();
@@ -329,11 +332,21 @@
// Let the loader know we're done with it
mListenerRegistered = false;
mLoader.unregisterListener(this);
+ mLoader.unregisterOnLoadCanceledListener(this);
mLoader.stopLoading();
}
}
}
-
+
+ void cancel() {
+ if (DEBUG) Log.v(TAG, " Canceling: " + this);
+ if (mStarted && mLoader != null && mListenerRegistered) {
+ if (!mLoader.cancelLoad()) {
+ onLoadCanceled(mLoader);
+ }
+ }
+ }
+
void destroy() {
if (DEBUG) Log.v(TAG, " Destroying: " + this);
mDestroyed = true;
@@ -361,6 +374,7 @@
if (mListenerRegistered) {
mListenerRegistered = false;
mLoader.unregisterListener(this);
+ mLoader.unregisterOnLoadCanceledListener(this);
}
mLoader.reset();
}
@@ -368,8 +382,38 @@
mPendingLoader.destroy();
}
}
-
- @Override public void onLoadComplete(Loader<Object> loader, Object data) {
+
+ @Override
+ public void onLoadCanceled(Loader<Object> loader) {
+ if (DEBUG) Log.v(TAG, "onLoadCanceled: " + this);
+
+ if (mDestroyed) {
+ if (DEBUG) Log.v(TAG, " Ignoring load canceled -- destroyed");
+ return;
+ }
+
+ if (mLoaders.get(mId) != this) {
+ // This cancellation message is not coming from the current active loader.
+ // We don't care about it.
+ if (DEBUG) Log.v(TAG, " Ignoring load canceled -- not active");
+ return;
+ }
+
+ LoaderInfo pending = mPendingLoader;
+ if (pending != null) {
+ // There is a new request pending and we were just
+ // waiting for the old one to cancel or complete before starting
+ // it. So now it is time, switch over to the new loader.
+ if (DEBUG) Log.v(TAG, " Switching to pending loader: " + pending);
+ mPendingLoader = null;
+ mLoaders.put(mId, null);
+ destroy();
+ installLoader(pending);
+ }
+ }
+
+ @Override
+ public void onLoadComplete(Loader<Object> loader, Object data) {
if (DEBUG) Log.v(TAG, "onLoadComplete: " + this);
if (mDestroyed) {
@@ -632,7 +676,9 @@
} else {
// Now we have three active loaders... we'll queue
// up this request to be processed once one of the other loaders
- // finishes.
+ // finishes or is canceled.
+ if (DEBUG) Log.v(TAG, " Current loader is running; attempting to cancel");
+ info.cancel();
if (info.mPendingLoader != null) {
if (DEBUG) Log.v(TAG, " Removing pending loader: " + info.mPendingLoader);
info.mPendingLoader.destroy();
diff --git a/core/java/android/app/SearchDialog.java b/core/java/android/app/SearchDialog.java
index 8fa95b4..d04e9db 100644
--- a/core/java/android/app/SearchDialog.java
+++ b/core/java/android/app/SearchDialog.java
@@ -551,7 +551,6 @@
try {
// If the intent was created from a suggestion, it will always have an explicit
// component here.
- Log.i(LOG_TAG, "Starting (as ourselves) " + intent.toUri(0));
getContext().startActivity(intent);
// If the search switches to a different activity,
// SearchDialogWrapper#performActivityResuming
diff --git a/core/java/android/content/AsyncTaskLoader.java b/core/java/android/content/AsyncTaskLoader.java
index 0b54396..da51952 100644
--- a/core/java/android/content/AsyncTaskLoader.java
+++ b/core/java/android/content/AsyncTaskLoader.java
@@ -53,19 +53,33 @@
static final boolean DEBUG = false;
final class LoadTask extends AsyncTask<Void, Void, D> implements Runnable {
+ private final CountDownLatch mDone = new CountDownLatch(1);
- D result;
+ // Set to true to indicate that the task has been posted to a handler for
+ // execution at a later time. Used to throttle updates.
boolean waiting;
- private CountDownLatch done = new CountDownLatch(1);
-
/* Runs on a worker thread */
@Override
protected D doInBackground(Void... params) {
if (DEBUG) Slog.v(TAG, this + " >>> doInBackground");
- result = AsyncTaskLoader.this.onLoadInBackground();
- if (DEBUG) Slog.v(TAG, this + " <<< doInBackground");
- return result;
+ try {
+ D data = AsyncTaskLoader.this.onLoadInBackground();
+ if (DEBUG) Slog.v(TAG, this + " <<< doInBackground");
+ return data;
+ } catch (OperationCanceledException ex) {
+ if (!isCancelled()) {
+ // onLoadInBackground threw a canceled exception spuriously.
+ // This is problematic because it means that the LoaderManager did not
+ // cancel the Loader itself and still expects to receive a result.
+ // Additionally, the Loader's own state will not have been updated to
+ // reflect the fact that the task was being canceled.
+ // So we treat this case as an unhandled exception.
+ throw ex;
+ }
+ if (DEBUG) Slog.v(TAG, this + " <<< doInBackground (was canceled)");
+ return null;
+ }
}
/* Runs on the UI thread */
@@ -75,25 +89,37 @@
try {
AsyncTaskLoader.this.dispatchOnLoadComplete(this, data);
} finally {
- done.countDown();
+ mDone.countDown();
}
}
+ /* Runs on the UI thread */
@Override
- protected void onCancelled() {
+ protected void onCancelled(D data) {
if (DEBUG) Slog.v(TAG, this + " onCancelled");
try {
- AsyncTaskLoader.this.dispatchOnCancelled(this, result);
+ AsyncTaskLoader.this.dispatchOnCancelled(this, data);
} finally {
- done.countDown();
+ mDone.countDown();
}
}
+ /* Runs on the UI thread, when the waiting task is posted to a handler.
+ * This method is only executed when task execution was deferred (waiting was true). */
@Override
public void run() {
waiting = false;
AsyncTaskLoader.this.executePendingTask();
}
+
+ /* Used for testing purposes to wait for the task to complete. */
+ public void waitForLoader() {
+ try {
+ mDone.await();
+ } catch (InterruptedException e) {
+ // Ignore
+ }
+ }
}
volatile LoadTask mTask;
@@ -109,7 +135,7 @@
/**
* Set amount to throttle updates by. This is the minimum time from
- * when the last {@link #onLoadInBackground()} call has completed until
+ * when the last {@link #loadInBackground()} call has completed until
* a new load is scheduled.
*
* @param delayMS Amount of delay, in milliseconds.
@@ -130,24 +156,9 @@
executePendingTask();
}
- /**
- * Attempt to cancel the current load task. See {@link AsyncTask#cancel(boolean)}
- * for more info. Must be called on the main thread of the process.
- *
- * <p>Cancelling is not an immediate operation, since the load is performed
- * in a background thread. If there is currently a load in progress, this
- * method requests that the load be cancelled, and notes this is the case;
- * once the background thread has completed its work its remaining state
- * will be cleared. If another load request comes in during this time,
- * it will be held until the cancelled load is complete.
- *
- * @return Returns <tt>false</tt> if the task could not be cancelled,
- * typically because it has already completed normally, or
- * because {@link #startLoading()} hasn't been called; returns
- * <tt>true</tt> otherwise.
- */
- public boolean cancelLoad() {
- if (DEBUG) Slog.v(TAG, "cancelLoad: mTask=" + mTask);
+ @Override
+ protected boolean onCancelLoad() {
+ if (DEBUG) Slog.v(TAG, "onCancelLoad: mTask=" + mTask);
if (mTask != null) {
if (mCancellingTask != null) {
// There was a pending task already waiting for a previous
@@ -173,6 +184,7 @@
if (DEBUG) Slog.v(TAG, "cancelLoad: cancelled=" + cancelled);
if (cancelled) {
mCancellingTask = mTask;
+ cancelLoadInBackground();
}
mTask = null;
return cancelled;
@@ -183,7 +195,10 @@
/**
* Called if the task was canceled before it was completed. Gives the class a chance
- * to properly dispose of the result.
+ * to clean up post-cancellation and to properly dispose of the result.
+ *
+ * @param data The value that was returned by {@link #loadInBackground}, or null
+ * if the task threw {@link OperationCanceledException}.
*/
public void onCanceled(D data) {
}
@@ -217,6 +232,8 @@
if (DEBUG) Slog.v(TAG, "Cancelled task is now canceled!");
mLastLoadCompleteTime = SystemClock.uptimeMillis();
mCancellingTask = null;
+ if (DEBUG) Slog.v(TAG, "Delivering cancellation");
+ deliverCancellation();
executePendingTask();
}
}
@@ -239,23 +256,76 @@
}
/**
+ * Called on a worker thread to perform the actual load and to return
+ * the result of the load operation.
+ *
+ * Implementations should not deliver the result directly, but should return them
+ * from this method, which will eventually end up calling {@link #deliverResult} on
+ * the UI thread. If implementations need to process the results on the UI thread
+ * they may override {@link #deliverResult} and do so there.
+ *
+ * To support cancellation, this method should periodically check the value of
+ * {@link #isLoadInBackgroundCanceled} and terminate when it returns true.
+ * Subclasses may also override {@link #cancelLoadInBackground} to interrupt the load
+ * directly instead of polling {@link #isLoadInBackgroundCanceled}.
+ *
+ * When the load is canceled, this method may either return normally or throw
+ * {@link OperationCanceledException}. In either case, the {@link Loader} will
+ * call {@link #onCanceled} to perform post-cancellation cleanup and to dispose of the
+ * result object, if any.
+ *
+ * @return The result of the load operation.
+ *
+ * @throws OperationCanceledException if the load is canceled during execution.
+ *
+ * @see #isLoadInBackgroundCanceled
+ * @see #cancelLoadInBackground
+ * @see #onCanceled
*/
public abstract D loadInBackground();
/**
- * Called on a worker thread to perform the actual load. Implementations should not deliver the
- * result directly, but should return them from this method, which will eventually end up
- * calling {@link #deliverResult} on the UI thread. If implementations need to process
- * the results on the UI thread they may override {@link #deliverResult} and do so
- * there.
+ * Calls {@link #loadInBackground()}.
*
- * @return Implementations must return the result of their load operation.
+ * This method is reserved for use by the loader framework.
+ * Subclasses should override {@link #loadInBackground} instead of this method.
+ *
+ * @return The result of the load operation.
+ *
+ * @throws OperationCanceledException if the load is canceled during execution.
+ *
+ * @see #loadInBackground
*/
protected D onLoadInBackground() {
return loadInBackground();
}
/**
+ * Called on the main thread to abort a load in progress.
+ *
+ * Override this method to abort the current invocation of {@link #loadInBackground}
+ * that is running in the background on a worker thread.
+ *
+ * This method should do nothing if {@link #loadInBackground} has not started
+ * running or if it has already finished.
+ *
+ * @see #loadInBackground
+ */
+ public void cancelLoadInBackground() {
+ }
+
+ /**
+ * Returns true if the current invocation of {@link #loadInBackground} is being canceled.
+ *
+ * @return True if the current invocation of {@link #loadInBackground} is being canceled.
+ *
+ * @see #loadInBackground
+ */
+ public boolean isLoadInBackgroundCanceled() {
+ return mCancellingTask != null;
+ }
+
+ /**
* Locks the current thread until the loader completes the current load
* operation. Returns immediately if there is no load operation running.
* Should not be called from the UI thread: calling it from the UI
@@ -268,11 +338,7 @@
public void waitForLoader() {
LoadTask task = mTask;
if (task != null) {
- try {
- task.done.await();
- } catch (InterruptedException e) {
- // Ignore
- }
+ task.waitForLoader();
}
}
diff --git a/core/java/android/content/CancellationSignal.java b/core/java/android/content/CancellationSignal.java
new file mode 100644
index 0000000..2dbbe54
--- /dev/null
+++ b/core/java/android/content/CancellationSignal.java
@@ -0,0 +1,170 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.content;
+
+import android.os.RemoteException;
+
+/**
+ * Provides the ability to cancel an operation in progress.
+ */
+public final class CancellationSignal {
+ private boolean mIsCanceled;
+ private OnCancelListener mOnCancelListener;
+ private ICancellationSignal mRemote;
+
+ /**
+ * Creates a cancellation signal, initially not canceled.
+ */
+ public CancellationSignal() {
+ }
+
+ /**
+ * Returns true if the operation has been canceled.
+ *
+ * @return True if the operation has been canceled.
+ */
+ public boolean isCanceled() {
+ synchronized (this) {
+ return mIsCanceled;
+ }
+ }
+
+ /**
+ * Throws {@link OperationCanceledException} if the operation has been canceled.
+ *
+ * @throws OperationCanceledException if the operation has been canceled.
+ */
+ public void throwIfCanceled() {
+ if (isCanceled()) {
+ throw new OperationCanceledException();
+ }
+ }
+
+ /**
+ * Cancels the operation and signals the cancellation listener.
+ * If the operation has not yet started, then it will be canceled as soon as it does.
+ */
+ public void cancel() {
+ synchronized (this) {
+ if (!mIsCanceled) {
+ mIsCanceled = true;
+ if (mOnCancelListener != null) {
+ mOnCancelListener.onCancel();
+ }
+ if (mRemote != null) {
+ try {
+ mRemote.cancel();
+ } catch (RemoteException ex) {
+ }
+ }
+ }
+ }
+ }
+
+ /**
+ * Sets the cancellation listener to be called when canceled.
+ *
+ * This method is intended to be used by the recipient of a cancellation signal
+ * such as a database or a content provider to handle cancellation requests
+ * while performing a long-running operation. This method is not intended to be
+ * used by applications themselves.
+ *
+ * If {@link CancellationSignal#cancel} has already been called, then the provided
+ * listener is invoked immediately.
+ *
+ * The listener is called while holding the cancellation signal's lock which is
+ * also held while registering or unregistering the listener. Because of the lock,
+ * it is not possible for the listener to run after it has been unregistered.
+ * This design choice makes it easier for clients of {@link CancellationSignal} to
+ * prevent race conditions related to listener registration and unregistration.
+ *
+ * @param listener The cancellation listener, or null to remove the current listener.
+ */
+ public void setOnCancelListener(OnCancelListener listener) {
+ synchronized (this) {
+ mOnCancelListener = listener;
+ if (mIsCanceled && listener != null) {
+ listener.onCancel();
+ }
+ }
+ }
+
+ /**
+ * Sets the remote transport.
+ *
+ * @param remote The remote transport, or null to remove.
+ *
+ * @hide
+ */
+ public void setRemote(ICancellationSignal remote) {
+ synchronized (this) {
+ mRemote = remote;
+ if (mIsCanceled && remote != null) {
+ try {
+ remote.cancel();
+ } catch (RemoteException ex) {
+ }
+ }
+ }
+ }
+
+ /**
+ * Creates a transport that can be returned back to the caller of
+ * a Binder function and subsequently used to dispatch a cancellation signal.
+ *
+ * @return The new cancellation signal transport.
+ *
+ * @hide
+ */
+ public static ICancellationSignal createTransport() {
+ return new Transport();
+ }
+
+ /**
+ * Given a locally created transport, returns its associated cancellation signal.
+ *
+ * @param transport The locally created transport, or null if none.
+ * @return The associated cancellation signal, or null if none.
+ *
+ * @hide
+ */
+ public static CancellationSignal fromTransport(ICancellationSignal transport) {
+ if (transport instanceof Transport) {
+ return ((Transport)transport).mCancellationSignal;
+ }
+ return null;
+ }
+
+ /**
+ * Listens for cancellation.
+ */
+ public interface OnCancelListener {
+ /**
+ * Called when {@link CancellationSignal#cancel} is invoked.
+ */
+ void onCancel();
+ }
+
+ private static final class Transport extends ICancellationSignal.Stub {
+ final CancellationSignal mCancellationSignal = new CancellationSignal();
+
+ @Override
+ public void cancel() throws RemoteException {
+ mCancellationSignal.cancel();
+ }
+ }
+}
diff --git a/core/java/android/content/ContentProvider.java b/core/java/android/content/ContentProvider.java
index 116ca48..12e3ccf 100644
--- a/core/java/android/content/ContentProvider.java
+++ b/core/java/android/content/ContentProvider.java
@@ -29,6 +29,7 @@
import android.os.Bundle;
import android.os.ParcelFileDescriptor;
import android.os.Process;
+import android.os.RemoteException;
import android.util.Log;
import java.io.File;
@@ -174,28 +175,33 @@
return getContentProvider().getClass().getName();
}
+ @Override
public Cursor query(Uri uri, String[] projection,
- String selection, String[] selectionArgs, String sortOrder) {
+ String selection, String[] selectionArgs, String sortOrder,
+ ICancellationSignal cancellationSignal) {
enforceReadPermission(uri);
- return ContentProvider.this.query(uri, projection, selection,
- selectionArgs, sortOrder);
+ return ContentProvider.this.query(uri, projection, selection, selectionArgs, sortOrder,
+ CancellationSignal.fromTransport(cancellationSignal));
}
+ @Override
public String getType(Uri uri) {
return ContentProvider.this.getType(uri);
}
-
+ @Override
public Uri insert(Uri uri, ContentValues initialValues) {
enforceWritePermission(uri);
return ContentProvider.this.insert(uri, initialValues);
}
+ @Override
public int bulkInsert(Uri uri, ContentValues[] initialValues) {
enforceWritePermission(uri);
return ContentProvider.this.bulkInsert(uri, initialValues);
}
+ @Override
public ContentProviderResult[] applyBatch(ArrayList<ContentProviderOperation> operations)
throws OperationApplicationException {
for (ContentProviderOperation operation : operations) {
@@ -210,17 +216,20 @@
return ContentProvider.this.applyBatch(operations);
}
+ @Override
public int delete(Uri uri, String selection, String[] selectionArgs) {
enforceWritePermission(uri);
return ContentProvider.this.delete(uri, selection, selectionArgs);
}
+ @Override
public int update(Uri uri, ContentValues values, String selection,
String[] selectionArgs) {
enforceWritePermission(uri);
return ContentProvider.this.update(uri, values, selection, selectionArgs);
}
+ @Override
public ParcelFileDescriptor openFile(Uri uri, String mode)
throws FileNotFoundException {
if (mode != null && mode.startsWith("rw")) enforceWritePermission(uri);
@@ -228,6 +237,7 @@
return ContentProvider.this.openFile(uri, mode);
}
+ @Override
public AssetFileDescriptor openAssetFile(Uri uri, String mode)
throws FileNotFoundException {
if (mode != null && mode.startsWith("rw")) enforceWritePermission(uri);
@@ -235,6 +245,7 @@
return ContentProvider.this.openAssetFile(uri, mode);
}
+ @Override
public Bundle call(String method, String arg, Bundle extras) {
return ContentProvider.this.call(method, arg, extras);
}
@@ -251,6 +262,11 @@
return ContentProvider.this.openTypedAssetFile(uri, mimeType, opts);
}
+ @Override
+ public ICancellationSignal createCancellationSignal() throws RemoteException {
+ return CancellationSignal.createTransport();
+ }
+
private void enforceReadPermission(Uri uri) {
final int uid = Binder.getCallingUid();
if (uid == mMyUid) {
@@ -541,6 +557,75 @@
String selection, String[] selectionArgs, String sortOrder);
/**
+ * Implement this to handle query requests from clients with support for cancellation.
+ * This method can be called from multiple threads, as described in
+ * <a href="{@docRoot}guide/topics/fundamentals/processes-and-threads.html#Threads">Processes
+ * and Threads</a>.
+ * <p>
+ * Example client call:<p>
+ * <pre>// Request a specific record.
+ * Cursor managedCursor = managedQuery(
+ ContentUris.withAppendedId(Contacts.People.CONTENT_URI, 2),
+ projection, // Which columns to return.
+ null, // WHERE clause.
+ null, // WHERE clause value substitution
+ People.NAME + " ASC"); // Sort order.</pre>
+ * Example implementation:<p>
+ * <pre>// SQLiteQueryBuilder is a helper class that creates the
+ // proper SQL syntax for us.
+ SQLiteQueryBuilder qBuilder = new SQLiteQueryBuilder();
+
+ // Set the table we're querying.
+ qBuilder.setTables(DATABASE_TABLE_NAME);
+
+ // If the query ends in a specific record number, we're
+ // being asked for a specific record, so set the
+ // WHERE clause in our query.
+ if((URI_MATCHER.match(uri)) == SPECIFIC_MESSAGE){
+ qBuilder.appendWhere("_id=" + uri.getPathLeafId());
+ }
+
+ // Make the query.
+ Cursor c = qBuilder.query(mDb,
+ projection,
+ selection,
+ selectionArgs,
+ groupBy,
+ having,
+ sortOrder);
+ c.setNotificationUri(getContext().getContentResolver(), uri);
+ return c;</pre>
+ * <p>
+ * If you implement this method then you must also implement the version of
+ * {@link #query(Uri, String[], String, String[], String)} that does not take a cancellation
+ * signal to ensure correct operation on older versions of the Android Framework in
+ * which the cancellation signal overload was not available.
+ *
+ * @param uri The URI to query. This will be the full URI sent by the client;
+ * if the client is requesting a specific record, the URI will end in a record number
+ * that the implementation should parse and add to a WHERE or HAVING clause, specifying
+ * that _id value.
+ * @param projection The list of columns to put into the cursor. If
+ * null all columns are included.
+ * @param selection A selection criteria to apply when filtering rows.
+ * If null then all rows are included.
+ * @param selectionArgs You may include ?s in selection, which will be replaced by
+ * the values from selectionArgs, in order that they appear in the selection.
+ * The values will be bound as Strings.
+ * @param sortOrder How the rows in the cursor should be sorted.
+ * If null then the provider is free to define the sort order.
+ * @param cancellationSignal A signal to cancel the operation in progress, or null if none.
+ * If the operation is canceled, then {@link OperationCanceledException} will be thrown
+ * when the query is executed.
+ * @return a Cursor or null.
+ */
+ public Cursor query(Uri uri, String[] projection,
+ String selection, String[] selectionArgs, String sortOrder,
+ CancellationSignal cancellationSignal) {
+ return query(uri, projection, selection, selectionArgs, sortOrder);
+ }
+
+ /**
* Implement this to handle requests for the MIME type of the data at the
* given URI. The returned MIME type should start with
* <code>vnd.android.cursor.item</code> for a single record,
diff --git a/core/java/android/content/ContentProviderClient.java b/core/java/android/content/ContentProviderClient.java
index 0540109..3ac5e07 100644
--- a/core/java/android/content/ContentProviderClient.java
+++ b/core/java/android/content/ContentProviderClient.java
@@ -47,7 +47,20 @@
/** See {@link ContentProvider#query ContentProvider.query} */
public Cursor query(Uri url, String[] projection, String selection,
String[] selectionArgs, String sortOrder) throws RemoteException {
- return mContentProvider.query(url, projection, selection, selectionArgs, sortOrder);
+ return query(url, projection, selection, selectionArgs, sortOrder, null);
+ }
+
+ /** See {@link ContentProvider#query ContentProvider.query} */
+ public Cursor query(Uri url, String[] projection, String selection,
+ String[] selectionArgs, String sortOrder, CancellationSignal cancellationSignal)
+ throws RemoteException {
+ ICancellationSignal remoteCancellationSignal = null;
+ if (cancellationSignal != null) {
+ remoteCancellationSignal = mContentProvider.createCancellationSignal();
+ cancellationSignal.setRemote(remoteCancellationSignal);
+ }
+ return mContentProvider.query(url, projection, selection, selectionArgs, sortOrder,
+ remoteCancellationSignal);
}
/** See {@link ContentProvider#getType ContentProvider.getType} */
diff --git a/core/java/android/content/ContentProviderNative.java b/core/java/android/content/ContentProviderNative.java
index b089bf2..eb83dbc 100644
--- a/core/java/android/content/ContentProviderNative.java
+++ b/core/java/android/content/ContentProviderNative.java
@@ -21,7 +21,6 @@
import android.database.BulkCursorToCursorAdaptor;
import android.database.Cursor;
import android.database.CursorToBulkCursorAdaptor;
-import android.database.CursorWindow;
import android.database.DatabaseUtils;
import android.database.IBulkCursor;
import android.database.IContentObserver;
@@ -41,8 +40,6 @@
* {@hide}
*/
abstract public class ContentProviderNative extends Binder implements IContentProvider {
- private static final String TAG = "ContentProvider";
-
public ContentProviderNative()
{
attachInterface(this, descriptor);
@@ -108,8 +105,11 @@
String sortOrder = data.readString();
IContentObserver observer = IContentObserver.Stub.asInterface(
data.readStrongBinder());
+ ICancellationSignal cancellationSignal = ICancellationSignal.Stub.asInterface(
+ data.readStrongBinder());
- Cursor cursor = query(url, projection, selection, selectionArgs, sortOrder);
+ Cursor cursor = query(url, projection, selection, selectionArgs, sortOrder,
+ cancellationSignal);
if (cursor != null) {
CursorToBulkCursorAdaptor adaptor = new CursorToBulkCursorAdaptor(
cursor, observer, getProviderName());
@@ -295,6 +295,16 @@
}
return true;
}
+
+ case CREATE_CANCELATION_SIGNAL_TRANSACTION:
+ {
+ data.enforceInterface(IContentProvider.descriptor);
+
+ ICancellationSignal cancellationSignal = createCancellationSignal();
+ reply.writeNoException();
+ reply.writeStrongBinder(cancellationSignal.asBinder());
+ return true;
+ }
}
} catch (Exception e) {
DatabaseUtils.writeExceptionToParcel(reply, e);
@@ -324,7 +334,8 @@
}
public Cursor query(Uri url, String[] projection, String selection,
- String[] selectionArgs, String sortOrder) throws RemoteException {
+ String[] selectionArgs, String sortOrder, ICancellationSignal cancellationSignal)
+ throws RemoteException {
BulkCursorToCursorAdaptor adaptor = new BulkCursorToCursorAdaptor();
Parcel data = Parcel.obtain();
Parcel reply = Parcel.obtain();
@@ -352,6 +363,7 @@
}
data.writeString(sortOrder);
data.writeStrongBinder(adaptor.getObserver().asBinder());
+ data.writeStrongBinder(cancellationSignal != null ? cancellationSignal.asBinder() : null);
mRemote.transact(IContentProvider.QUERY_TRANSACTION, data, reply, 0);
@@ -620,5 +632,24 @@
}
}
+ public ICancellationSignal createCancellationSignal() throws RemoteException {
+ Parcel data = Parcel.obtain();
+ Parcel reply = Parcel.obtain();
+ try {
+ data.writeInterfaceToken(IContentProvider.descriptor);
+
+ mRemote.transact(IContentProvider.CREATE_CANCELATION_SIGNAL_TRANSACTION,
+ data, reply, 0);
+
+ DatabaseUtils.readExceptionFromParcel(reply);
+ ICancellationSignal cancellationSignal = ICancellationSignal.Stub.asInterface(
+ reply.readStrongBinder());
+ return cancellationSignal;
+ } finally {
+ data.recycle();
+ reply.recycle();
+ }
+ }
+
private IBinder mRemote;
}
diff --git a/core/java/android/content/ContentResolver.java b/core/java/android/content/ContentResolver.java
index cc3219b..96a65da 100644
--- a/core/java/android/content/ContentResolver.java
+++ b/core/java/android/content/ContentResolver.java
@@ -22,6 +22,7 @@
import android.app.ActivityManagerNative;
import android.app.ActivityThread;
import android.app.AppGlobals;
+import android.content.ContentProvider.Transport;
import android.content.pm.PackageManager.NameNotFoundException;
import android.content.res.AssetFileDescriptor;
import android.content.res.Resources;
@@ -302,13 +303,62 @@
*/
public final Cursor query(Uri uri, String[] projection,
String selection, String[] selectionArgs, String sortOrder) {
+ return query(uri, projection, selection, selectionArgs, sortOrder, null);
+ }
+
+ /**
+ * <p>
+ * Query the given URI, returning a {@link Cursor} over the result set.
+ * </p>
+ * <p>
+ * For best performance, the caller should follow these guidelines:
+ * <ul>
+ * <li>Provide an explicit projection, to prevent
+ * reading data from storage that aren't going to be used.</li>
+ * <li>Use question mark parameter markers such as 'phone=?' instead of
+ * explicit values in the {@code selection} parameter, so that queries
+ * that differ only by those values will be recognized as the same
+ * for caching purposes.</li>
+ * </ul>
+ * </p>
+ *
+ * @param uri The URI, using the content:// scheme, for the content to
+ * retrieve.
+ * @param projection A list of which columns to return. Passing null will
+ * return all columns, which is inefficient.
+ * @param selection A filter declaring which rows to return, formatted as an
+ * SQL WHERE clause (excluding the WHERE itself). Passing null will
+ * return all rows for the given URI.
+ * @param selectionArgs You may include ?s in selection, which will be
+ * replaced by the values from selectionArgs, in the order that they
+ * appear in the selection. The values will be bound as Strings.
+ * @param sortOrder How to order the rows, formatted as an SQL ORDER BY
+ * clause (excluding the ORDER BY itself). Passing null will use the
+ * default sort order, which may be unordered.
+ * @param cancellationSignal A signal to cancel the operation in progress, or null if none.
+ * If the operation is canceled, then {@link OperationCanceledException} will be thrown
+ * when the query is executed.
+ * @return A Cursor object, which is positioned before the first entry, or null
+ * @see Cursor
+ */
+ public final Cursor query(final Uri uri, String[] projection,
+ String selection, String[] selectionArgs, String sortOrder,
+ CancellationSignal cancellationSignal) {
IContentProvider provider = acquireProvider(uri);
if (provider == null) {
return null;
}
try {
long startTime = SystemClock.uptimeMillis();
- Cursor qCursor = provider.query(uri, projection, selection, selectionArgs, sortOrder);
+
+ ICancellationSignal remoteCancellationSignal = null;
+ if (cancellationSignal != null) {
+ cancellationSignal.throwIfCanceled();
+ remoteCancellationSignal = provider.createCancellationSignal();
+ cancellationSignal.setRemote(remoteCancellationSignal);
+ }
+ Cursor qCursor = provider.query(uri, projection,
+ selection, selectionArgs, sortOrder, remoteCancellationSignal);
if (qCursor == null) {
releaseProvider(provider);
return null;
@@ -1034,8 +1084,11 @@
* To register, call {@link #registerContentObserver(android.net.Uri , boolean, android.database.ContentObserver) registerContentObserver()}.
* By default, CursorAdapter objects will get this notification.
*
- * @param uri
- * @param observer The observer that originated the change, may be <code>null</null>
+ * @param uri The uri of the content that was changed.
+ * @param observer The observer that originated the change, may be <code>null</null>.
+ * The observer that originated the change will only receive the notification if it
+ * has requested to receive self-change notifications by implementing
+ * {@link ContentObserver#deliverSelfNotifications()} to return true.
*/
public void notifyChange(Uri uri, ContentObserver observer) {
notifyChange(uri, observer, true /* sync to network */);
@@ -1046,8 +1099,11 @@
* To register, call {@link #registerContentObserver(android.net.Uri , boolean, android.database.ContentObserver) registerContentObserver()}.
* By default, CursorAdapter objects will get this notification.
*
- * @param uri
- * @param observer The observer that originated the change, may be <code>null</null>
+ * @param uri The uri of the content that was changed.
+ * @param observer The observer that originated the change, may be <code>null</null>.
+ * The observer that originated the change will only receive the notification if it
+ * has requested to receive self-change notifications by implementing
+ * {@link ContentObserver#deliverSelfNotifications()} to return true.
* @param syncToNetwork If true, attempt to sync the change to the network.
*/
public void notifyChange(Uri uri, ContentObserver observer, boolean syncToNetwork) {
diff --git a/core/java/android/content/ContentService.java b/core/java/android/content/ContentService.java
index 0e83dc0..fc4c262 100644
--- a/core/java/android/content/ContentService.java
+++ b/core/java/android/content/ContentService.java
@@ -176,7 +176,7 @@
for (int i=0; i<numCalls; i++) {
ObserverCall oc = calls.get(i);
try {
- oc.mObserver.onChange(oc.mSelfNotify);
+ oc.mObserver.onChange(oc.mSelfChange, uri);
if (Log.isLoggable(TAG, Log.VERBOSE)) {
Log.v(TAG, "Notified " + oc.mObserver + " of " + "update at " + uri);
}
@@ -218,13 +218,12 @@
public static final class ObserverCall {
final ObserverNode mNode;
final IContentObserver mObserver;
- final boolean mSelfNotify;
+ final boolean mSelfChange;
- ObserverCall(ObserverNode node, IContentObserver observer,
- boolean selfNotify) {
+ ObserverCall(ObserverNode node, IContentObserver observer, boolean selfChange) {
mNode = node;
mObserver = observer;
- mSelfNotify = selfNotify;
+ mSelfChange = selfChange;
}
}
@@ -668,7 +667,7 @@
}
private void collectMyObserversLocked(boolean leaf, IContentObserver observer,
- boolean selfNotify, ArrayList<ObserverCall> calls) {
+ boolean observerWantsSelfNotifications, ArrayList<ObserverCall> calls) {
int N = mObservers.size();
IBinder observerBinder = observer == null ? null : observer.asBinder();
for (int i = 0; i < N; i++) {
@@ -676,28 +675,29 @@
// Don't notify the observer if it sent the notification and isn't interesed
// in self notifications
- if (entry.observer.asBinder() == observerBinder && !selfNotify) {
+ boolean selfChange = (entry.observer.asBinder() == observerBinder);
+ if (selfChange && !observerWantsSelfNotifications) {
continue;
}
// Make sure the observer is interested in the notification
if (leaf || (!leaf && entry.notifyForDescendents)) {
- calls.add(new ObserverCall(this, entry.observer, selfNotify));
+ calls.add(new ObserverCall(this, entry.observer, selfChange));
}
}
}
public void collectObserversLocked(Uri uri, int index, IContentObserver observer,
- boolean selfNotify, ArrayList<ObserverCall> calls) {
+ boolean observerWantsSelfNotifications, ArrayList<ObserverCall> calls) {
String segment = null;
int segmentCount = countUriSegments(uri);
if (index >= segmentCount) {
// This is the leaf node, notify all observers
- collectMyObserversLocked(true, observer, selfNotify, calls);
+ collectMyObserversLocked(true, observer, observerWantsSelfNotifications, calls);
} else if (index < segmentCount){
segment = getUriSegment(uri, index);
// Notify any observers at this level who are interested in descendents
- collectMyObserversLocked(false, observer, selfNotify, calls);
+ collectMyObserversLocked(false, observer, observerWantsSelfNotifications, calls);
}
int N = mChildren.size();
@@ -705,7 +705,8 @@
ObserverNode node = mChildren.get(i);
if (segment == null || node.mName.equals(segment)) {
// We found the child,
- node.collectObserversLocked(uri, index + 1, observer, selfNotify, calls);
+ node.collectObserversLocked(uri, index + 1,
+ observer, observerWantsSelfNotifications, calls);
if (segment != null) {
break;
}
diff --git a/core/java/android/content/CursorLoader.java b/core/java/android/content/CursorLoader.java
index 7af535b..aed3728 100644
--- a/core/java/android/content/CursorLoader.java
+++ b/core/java/android/content/CursorLoader.java
@@ -19,7 +19,6 @@
import android.database.ContentObserver;
import android.database.Cursor;
import android.net.Uri;
-import android.os.AsyncTask;
import java.io.FileDescriptor;
import java.io.PrintWriter;
@@ -49,18 +48,42 @@
String mSortOrder;
Cursor mCursor;
+ CancellationSignal mCancellationSignal;
/* Runs on a worker thread */
@Override
public Cursor loadInBackground() {
- Cursor cursor = getContext().getContentResolver().query(mUri, mProjection, mSelection,
- mSelectionArgs, mSortOrder);
- if (cursor != null) {
- // Ensure the cursor window is filled
- cursor.getCount();
- registerContentObserver(cursor, mObserver);
+ synchronized (this) {
+ if (isLoadInBackgroundCanceled()) {
+ throw new OperationCanceledException();
+ }
+ mCancellationSignal = new CancellationSignal();
}
- return cursor;
+ try {
+ Cursor cursor = getContext().getContentResolver().query(mUri, mProjection, mSelection,
+ mSelectionArgs, mSortOrder, mCancellationSignal);
+ if (cursor != null) {
+ // Ensure the cursor window is filled
+ cursor.getCount();
+ registerContentObserver(cursor, mObserver);
+ }
+ return cursor;
+ } finally {
+ synchronized (this) {
+ mCancellationSignal = null;
+ }
+ }
+ }
+
+ @Override
+ public void cancelLoadInBackground() {
+ super.cancelLoadInBackground();
+
+ synchronized (this) {
+ if (mCancellationSignal != null) {
+ mCancellationSignal.cancel();
+ }
+ }
}
/**
diff --git a/core/java/android/content/ICancellationSignal.aidl b/core/java/android/content/ICancellationSignal.aidl
new file mode 100644
index 0000000..cf1c5d3
--- /dev/null
+++ b/core/java/android/content/ICancellationSignal.aidl
@@ -0,0 +1,24 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.content;
+
+/**
+ * @hide
+ */
+interface ICancellationSignal {
+ oneway void cancel();
+}
diff --git a/core/java/android/content/IContentProvider.java b/core/java/android/content/IContentProvider.java
index 2a67ff8..16478b7 100644
--- a/core/java/android/content/IContentProvider.java
+++ b/core/java/android/content/IContentProvider.java
@@ -34,7 +34,8 @@
*/
public interface IContentProvider extends IInterface {
public Cursor query(Uri url, String[] projection, String selection,
- String[] selectionArgs, String sortOrder) throws RemoteException;
+ String[] selectionArgs, String sortOrder, ICancellationSignal cancellationSignal)
+ throws RemoteException;
public String getType(Uri url) throws RemoteException;
public Uri insert(Uri url, ContentValues initialValues)
throws RemoteException;
@@ -50,6 +51,7 @@
public ContentProviderResult[] applyBatch(ArrayList<ContentProviderOperation> operations)
throws RemoteException, OperationApplicationException;
public Bundle call(String method, String arg, Bundle extras) throws RemoteException;
+ public ICancellationSignal createCancellationSignal() throws RemoteException;
// Data interchange.
public String[] getStreamTypes(Uri url, String mimeTypeFilter) throws RemoteException;
@@ -71,4 +73,5 @@
static final int CALL_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 20;
static final int GET_STREAM_TYPES_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 21;
static final int OPEN_TYPED_ASSET_FILE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 22;
+ static final int CREATE_CANCELATION_SIGNAL_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 23;
}
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index e3b1f54..ab62c44 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -43,6 +43,7 @@
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Iterator;
+import java.util.Locale;
import java.util.Set;
/**
@@ -2956,6 +2957,13 @@
*/
public static final int FLAG_RECEIVER_REPLACE_PENDING = 0x20000000;
/**
+ * If set, when sending a broadcast the recipient is allowed to run at
+ * foreground priority, with a shorter timeout interval. During normal
+ * broadcasts the receivers are not automatically hoisted out of the
+ * background priority class.
+ */
+ public static final int FLAG_RECEIVER_FOREGROUND = 0x10000000;
+ /**
* If set, when sending a broadcast <i>before boot has completed</i> only
* registered receivers will be called -- no BroadcastReceiver components
* will be launched. Sticky intent state will be recorded properly even
@@ -2968,14 +2976,14 @@
*
* @hide
*/
- public static final int FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT = 0x10000000;
+ public static final int FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT = 0x08000000;
/**
* Set when this broadcast is for a boot upgrade, a special mode that
* allows the broadcast to be sent before the system is ready and launches
* the app process with no providers running in it.
* @hide
*/
- public static final int FLAG_RECEIVER_BOOT_UPGRADE = 0x08000000;
+ public static final int FLAG_RECEIVER_BOOT_UPGRADE = 0x04000000;
/**
* @hide Flags that can't be changed with PendingIntent.
@@ -4420,22 +4428,24 @@
/**
* Set the data this intent is operating on. This method automatically
- * clears any type that was previously set by {@link #setType}.
+ * clears any type that was previously set by {@link #setType} or
+ * {@link #setTypeAndNormalize}.
*
- * <p><em>Note: scheme and host name matching in the Android framework is
- * case-sensitive, unlike the formal RFC. As a result,
- * you should always ensure that you write your Uri with these elements
- * using lower case letters, and normalize any Uris you receive from
- * outside of Android to ensure the scheme and host is lower case.</em></p>
+ * <p><em>Note: scheme matching in the Android framework is
+ * case-sensitive, unlike the formal RFC. As a result,
+ * you should always write your Uri with a lower case scheme,
+ * or use {@link Uri#normalize} or
+ * {@link #setDataAndNormalize}
+ * to ensure that the scheme is converted to lower case.</em>
*
- * @param data The URI of the data this intent is now targeting.
+ * @param data The Uri of the data this intent is now targeting.
*
* @return Returns the same Intent object, for chaining multiple calls
* into a single statement.
*
* @see #getData
- * @see #setType
- * @see #setDataAndType
+ * @see #setDataAndNormalize
+ * @see android.net.Intent#normalize
*/
public Intent setData(Uri data) {
mData = data;
@@ -4444,16 +4454,45 @@
}
/**
- * Set an explicit MIME data type. This is used to create intents that
- * only specify a type and not data, for example to indicate the type of
- * data to return. This method automatically clears any data that was
- * previously set by {@link #setData}.
+ * Normalize and set the data this intent is operating on.
+ *
+ * <p>This method automatically clears any type that was
+ * previously set (for example, by {@link #setType}).
+ *
+ * <p>The data Uri is normalized using
+ * {@link android.net.Uri#normalize} before it is set,
+ * so really this is just a convenience method for
+ * <pre>
+ * setData(data.normalize())
+ * </pre>
+ *
+ * @param data The Uri of the data this intent is now targeting.
+ *
+ * @return Returns the same Intent object, for chaining multiple calls
+ * into a single statement.
+ *
+ * @see #getData
+ * @see #setType
+ * @see android.net.Uri#normalize
+ */
+ public Intent setDataAndNormalize(Uri data) {
+ return setData(data.normalize());
+ }
+
+ /**
+ * Set an explicit MIME data type.
+ *
+ * <p>This is used to create intents that only specify a type and not data,
+ * for example to indicate the type of data to return.
+ *
+ * <p>This method automatically clears any data that was
+ * previously set (for example by {@link #setData}).
*
* <p><em>Note: MIME type matching in the Android framework is
* case-sensitive, unlike formal RFC MIME types. As a result,
* you should always write your MIME types with lower case letters,
- * and any MIME types you receive from outside of Android should be
- * converted to lower case before supplying them here.</em></p>
+ * or use {@link #normalizeMimeType} or {@link #setTypeAndNormalize}
+ * to ensure that it is converted to lower case.</em>
*
* @param type The MIME type of the data being handled by this intent.
*
@@ -4461,8 +4500,9 @@
* into a single statement.
*
* @see #getType
- * @see #setData
+ * @see #setTypeAndNormalize
* @see #setDataAndType
+ * @see #normalizeMimeType
*/
public Intent setType(String type) {
mData = null;
@@ -4471,26 +4511,58 @@
}
/**
- * (Usually optional) Set the data for the intent along with an explicit
- * MIME data type. This method should very rarely be used -- it allows you
- * to override the MIME type that would ordinarily be inferred from the
- * data with your own type given here.
+ * Normalize and set an explicit MIME data type.
*
- * <p><em>Note: MIME type, Uri scheme, and host name matching in the
- * Android framework is case-sensitive, unlike the formal RFC definitions.
- * As a result, you should always write these elements with lower case letters,
- * and normalize any MIME types or Uris you receive from
- * outside of Android to ensure these elements are lower case before
- * supplying them here.</em></p>
+ * <p>This is used to create intents that only specify a type and not data,
+ * for example to indicate the type of data to return.
*
- * @param data The URI of the data this intent is now targeting.
+ * <p>This method automatically clears any data that was
+ * previously set (for example by {@link #setData}).
+ *
+ * <p>The MIME type is normalized using
+ * {@link #normalizeMimeType} before it is set,
+ * so really this is just a convenience method for
+ * <pre>
+ * setType(Intent.normalizeMimeType(type))
+ * </pre>
+ *
* @param type The MIME type of the data being handled by this intent.
*
* @return Returns the same Intent object, for chaining multiple calls
* into a single statement.
*
+ * @see #getType
* @see #setData
+ * @see #normalizeMimeType
+ */
+ public Intent setTypeAndNormalize(String type) {
+ return setType(normalizeMimeType(type));
+ }
+
+ /**
+ * (Usually optional) Set the data for the intent along with an explicit
+ * MIME data type. This method should very rarely be used -- it allows you
+ * to override the MIME type that would ordinarily be inferred from the
+ * data with your own type given here.
+ *
+ * <p><em>Note: MIME type and Uri scheme matching in the
+ * Android framework is case-sensitive, unlike the formal RFC definitions.
+ * As a result, you should always write these elements with lower case letters,
+ * or use {@link #normalizeMimeType} or {@link android.net.Uri#normalize} or
+ * {@link #setDataAndTypeAndNormalize}
+ * to ensure that they are converted to lower case.</em>
+ *
+ * @param data The Uri of the data this intent is now targeting.
+ * @param type The MIME type of the data being handled by this intent.
+ *
+ * @return Returns the same Intent object, for chaining multiple calls
+ * into a single statement.
+ *
* @see #setType
+ * @see #setData
+ * @see #normalizeMimeType
+ * @see android.net.Uri#normalize
+ * @see #setDataAndTypeAndNormalize
*/
public Intent setDataAndType(Uri data, String type) {
mData = data;
@@ -4499,6 +4571,35 @@
}
/**
+ * (Usually optional) Normalize and set both the data Uri and an explicit
+ * MIME data type. This method should very rarely be used -- it allows you
+ * to override the MIME type that would ordinarily be inferred from the
+ * data with your own type given here.
+ *
+ * <p>The data Uri and the MIME type are normalize using
+ * {@link android.net.Uri#normalize} and {@link #normalizeMimeType}
+ * before they are set, so really this is just a convenience method for
+ * <pre>
+ * setDataAndType(data.normalize(), Intent.normalizeMimeType(type))
+ * </pre>
+ *
+ * @param data The Uri of the data this intent is now targeting.
+ * @param type The MIME type of the data being handled by this intent.
+ *
+ * @return Returns the same Intent object, for chaining multiple calls
+ * into a single statement.
+ *
+ * @see #setType
+ * @see #setData
+ * @see #setDataAndType
+ * @see #normalizeMimeType
+ * @see android.net.Uri#normalize
+ */
+ public Intent setDataAndTypeAndNormalize(Uri data, String type) {
+ return setDataAndType(data.normalize(), normalizeMimeType(type));
+ }
+
+ /**
* Add a new category to the intent. Categories provide additional detail
* about the action the intent is perform. When resolving an intent, only
* activities that provide <em>all</em> of the requested categories will be
@@ -5566,7 +5667,7 @@
*
* <ul>
* <li> action, as set by {@link #setAction}.
- * <li> data URI and MIME type, as set by {@link #setData(Uri)},
+ * <li> data Uri and MIME type, as set by {@link #setData(Uri)},
* {@link #setType(String)}, or {@link #setDataAndType(Uri, String)}.
* <li> categories, as set by {@link #addCategory}.
* <li> package, as set by {@link #setPackage}.
@@ -6229,4 +6330,38 @@
return intent;
}
+
+ /**
+ * Normalize a MIME data type.
+ *
+ * <p>A normalized MIME type has white-space trimmed,
+ * content-type parameters removed, and is lower-case.
+ * This aligns the type with Android best practices for
+ * intent filtering.
+ *
+ * <p>For example, "text/plain; charset=utf-8" becomes "text/plain".
+ * "text/x-vCard" becomes "text/x-vcard".
+ *
+ * <p>All MIME types received from outside Android (such as user input,
+ * or external sources like Bluetooth, NFC, or the Internet) should
+ * be normalized before they are used to create an Intent.
+ *
+ * @param type MIME data type to normalize
+ * @return normalized MIME data type, or null if the input was null
+ * @see {@link #setType}
+ * @see {@link #setTypeAndNormalize}
+ */
+ public static String normalizeMimeType(String type) {
+ if (type == null) {
+ return null;
+ }
+
+ type = type.trim().toLowerCase(Locale.US);
+
+ final int semicolonIndex = type.indexOf(';');
+ if (semicolonIndex != -1) {
+ type = type.substring(0, semicolonIndex);
+ }
+ return type;
+ }
}
diff --git a/core/java/android/content/Loader.java b/core/java/android/content/Loader.java
index ac05682..3052414 100644
--- a/core/java/android/content/Loader.java
+++ b/core/java/android/content/Loader.java
@@ -52,6 +52,7 @@
public class Loader<D> {
int mId;
OnLoadCompleteListener<D> mListener;
+ OnLoadCanceledListener<D> mOnLoadCanceledListener;
Context mContext;
boolean mStarted = false;
boolean mAbandoned = false;
@@ -100,6 +101,23 @@
}
/**
+ * Interface that is implemented to discover when a Loader has been canceled
+ * before it finished loading its data. You do not normally need to implement
+ * this yourself; it is used in the implementation of {@link android.app.LoaderManager}
+ * to find out when a Loader it is managing has been canceled so that it
+ * can schedule the next Loader. This interface should only be used if a
+ * Loader is not being used in conjunction with LoaderManager.
+ */
+ public interface OnLoadCanceledListener<D> {
+ /**
+ * Called on the thread that created the Loader when the load is canceled.
+ *
+ * @param loader the loader that canceled the load
+ */
+ public void onLoadCanceled(Loader<D> loader);
+ }
+
+ /**
* Stores away the application context associated with context.
* Since Loaders can be used across multiple activities it's dangerous to
* store the context directly; always use {@link #getContext()} to retrieve
@@ -127,6 +145,18 @@
}
/**
+ * Informs the registered {@link OnLoadCanceledListener} that the load has been canceled.
+ * Should only be called by subclasses.
+ *
+ * Must be called from the process's main thread.
+ */
+ public void deliverCancellation() {
+ if (mOnLoadCanceledListener != null) {
+ mOnLoadCanceledListener.onLoadCanceled(this);
+ }
+ }
+
+ /**
* @return an application context retrieved from the Context passed to the constructor.
*/
public Context getContext() {
@@ -171,6 +201,40 @@
}
/**
+ * Registers a listener that will receive callbacks when a load is canceled.
+ * The callback will be called on the process's main thread so it's safe to
+ * pass the results to widgets.
+ *
+ * Must be called from the process's main thread.
+ *
+ * @param listener The listener to register.
+ */
+ public void registerOnLoadCanceledListener(OnLoadCanceledListener<D> listener) {
+ if (mOnLoadCanceledListener != null) {
+ throw new IllegalStateException("There is already a listener registered");
+ }
+ mOnLoadCanceledListener = listener;
+ }
+
+ /**
+ * Unregisters a listener that was previously added with
+ * {@link #registerOnLoadCanceledListener}.
+ *
+ * Must be called from the process's main thread.
+ *
+ * @param listener The listener to unregister.
+ */
+ public void unregisterOnLoadCanceledListener(OnLoadCanceledListener<D> listener) {
+ if (mOnLoadCanceledListener == null) {
+ throw new IllegalStateException("No listener register");
+ }
+ if (mOnLoadCanceledListener != listener) {
+ throw new IllegalArgumentException("Attempting to unregister the wrong listener");
+ }
+ mOnLoadCanceledListener = null;
+ }
+
+ /**
* Return whether this load has been started. That is, its {@link #startLoading()}
* has been called and no calls to {@link #stopLoading()} or
* {@link #reset()} have yet been made.
@@ -234,6 +298,43 @@
}
/**
+ * Attempt to cancel the current load task.
+ * Must be called on the main thread of the process.
+ *
+ * <p>Cancellation is not an immediate operation, since the load is performed
+ * in a background thread. If there is currently a load in progress, this
+ * method requests that the load be canceled, and notes this is the case;
+ * once the background thread has completed its work its remaining state
+ * will be cleared. If another load request comes in during this time,
+ * it will be held until the canceled load is complete.
+ *
+ * @return Returns <tt>false</tt> if the task could not be canceled,
+ * typically because it has already completed normally, or
+ * because {@link #startLoading()} hasn't been called; returns
+ * <tt>true</tt> otherwise. When <tt>true</tt> is returned, the task
+ * is still running and the {@link OnLoadCanceledListener} will be called
+ * when the task completes.
+ */
+ public boolean cancelLoad() {
+ return onCancelLoad();
+ }
+
+ /**
+ * Subclasses must implement this to take care of requests to {@link #cancelLoad()}.
+ * This will always be called from the process's main thread.
+ *
+ * @return Returns <tt>false</tt> if the task could not be canceled,
+ * typically because it has already completed normally, or
+ * because {@link #startLoading()} hasn't been called; returns
+ * <tt>true</tt> otherwise. When <tt>true</tt> is returned, the task
+ * is still running and the {@link OnLoadCanceledListener} will be called
+ * when the task completes.
+ */
+ protected boolean onCancelLoad() {
+ return false;
+ }
+
+ /**
* Force an asynchronous load. Unlike {@link #startLoading()} this will ignore a previously
* loaded data set and load a new one. This simply calls through to the
* implementation's {@link #onForceLoad()}. You generally should only call this
diff --git a/core/java/android/content/OperationCanceledException.java b/core/java/android/content/OperationCanceledException.java
new file mode 100644
index 0000000..d783a07
--- /dev/null
+++ b/core/java/android/content/OperationCanceledException.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.content;
+
+/**
+ * An exception type that is thrown when an operation in progress is canceled.
+ *
+ * @see CancellationSignal
+ */
+public class OperationCanceledException extends RuntimeException {
+ public OperationCanceledException() {
+ this(null);
+ }
+
+ public OperationCanceledException(String message) {
+ super(message != null ? message : "The operation has been canceled.");
+ }
+}
diff --git a/core/java/android/content/res/Configuration.java b/core/java/android/content/res/Configuration.java
index 6015668..e04b2f7 100644
--- a/core/java/android/content/res/Configuration.java
+++ b/core/java/android/content/res/Configuration.java
@@ -347,6 +347,7 @@
sb.append(" (no locale)");
}
switch (textLayoutDirection) {
+ case LocaleUtil.TEXT_LAYOUT_DIRECTION_LTR_DO_NOT_USE: /* ltr not interesting */ break;
case LocaleUtil.TEXT_LAYOUT_DIRECTION_RTL_DO_NOT_USE: sb.append(" rtl"); break;
default: sb.append(" layoutdir="); sb.append(textLayoutDirection); break;
}
diff --git a/core/java/android/database/AbstractCursor.java b/core/java/android/database/AbstractCursor.java
index 74fef29..b28ed8d 100644
--- a/core/java/android/database/AbstractCursor.java
+++ b/core/java/android/database/AbstractCursor.java
@@ -284,23 +284,6 @@
}
}
- /**
- * This is hidden until the data set change model has been re-evaluated.
- * @hide
- */
- protected void notifyDataSetChange() {
- mDataSetObservable.notifyChanged();
- }
-
- /**
- * This is hidden until the data set change model has been re-evaluated.
- * @hide
- */
- protected DataSetObservable getDataSetObservable() {
- return mDataSetObservable;
-
- }
-
public void registerDataSetObserver(DataSetObserver observer) {
mDataSetObservable.registerObserver(observer);
}
@@ -317,7 +300,7 @@
*/
protected void onChange(boolean selfChange) {
synchronized (mSelfObserverLock) {
- mContentObservable.dispatchChange(selfChange);
+ mContentObservable.dispatchChange(selfChange, null);
if (mNotifyUri != null && selfChange) {
mContentResolver.notifyChange(mNotifyUri, mSelfObserver);
}
diff --git a/core/java/android/database/ContentObservable.java b/core/java/android/database/ContentObservable.java
index 8d7b7c5..7692bb3 100644
--- a/core/java/android/database/ContentObservable.java
+++ b/core/java/android/database/ContentObservable.java
@@ -16,40 +16,75 @@
package android.database;
+import android.net.Uri;
+
/**
- * A specialization of Observable for ContentObserver that provides methods for
- * invoking the various callback methods of ContentObserver.
+ * A specialization of {@link Observable} for {@link ContentObserver}
+ * that provides methods for sending notifications to a list of
+ * {@link ContentObserver} objects.
*/
public class ContentObservable extends Observable<ContentObserver> {
-
+ // Even though the generic method defined in Observable would be perfectly
+ // fine on its own, we can't delete this overridden method because it would
+ // potentially break binary compatibility with existing applications.
@Override
public void registerObserver(ContentObserver observer) {
super.registerObserver(observer);
}
/**
- * invokes dispatchUpdate on each observer, unless the observer doesn't want
- * self-notifications and the update is from a self-notification
- * @param selfChange
+ * Invokes {@link ContentObserver#dispatchChange(boolean)} on each observer.
+ * <p>
+ * If <code>selfChange</code> is true, only delivers the notification
+ * to the observer if it has indicated that it wants to receive self-change
+ * notifications by implementing {@link ContentObserver#deliverSelfNotifications}
+ * to return true.
+ * </p>
+ *
+ * @param selfChange True if this is a self-change notification.
+ *
+ * @deprecated Use {@link #dispatchChange(boolean, Uri)} instead.
*/
+ @Deprecated
public void dispatchChange(boolean selfChange) {
+ dispatchChange(selfChange, null);
+ }
+
+ /**
+ * Invokes {@link ContentObserver#dispatchChange(boolean, Uri)} on each observer.
+ * Includes the changed content Uri when available.
+ * <p>
+ * If <code>selfChange</code> is true, only delivers the notification
+ * to the observer if it has indicated that it wants to receive self-change
+ * notifications by implementing {@link ContentObserver#deliverSelfNotifications}
+ * to return true.
+ * </p>
+ *
+ * @param selfChange True if this is a self-change notification.
+ * @param uri The Uri of the changed content, or null if unknown.
+ */
+ public void dispatchChange(boolean selfChange, Uri uri) {
synchronized(mObservers) {
for (ContentObserver observer : mObservers) {
if (!selfChange || observer.deliverSelfNotifications()) {
- observer.dispatchChange(selfChange);
+ observer.dispatchChange(selfChange, uri);
}
}
}
}
/**
- * invokes onChange on each observer
- * @param selfChange
+ * Invokes {@link ContentObserver#onChange} on each observer.
+ *
+ * @param selfChange True if this is a self-change notification.
+ *
+ * @deprecated Use {@link #dispatchChange} instead.
*/
+ @Deprecated
public void notifyChange(boolean selfChange) {
synchronized(mObservers) {
for (ContentObserver observer : mObservers) {
- observer.onChange(selfChange);
+ observer.onChange(selfChange, null);
}
}
}
diff --git a/core/java/android/database/ContentObserver.java b/core/java/android/database/ContentObserver.java
index 3b829a3..e4fbc28 100644
--- a/core/java/android/database/ContentObserver.java
+++ b/core/java/android/database/ContentObserver.java
@@ -16,65 +16,23 @@
package android.database;
+import android.net.Uri;
import android.os.Handler;
/**
- * Receives call backs for changes to content. Must be implemented by objects which are added
- * to a {@link ContentObservable}.
+ * Receives call backs for changes to content.
+ * Must be implemented by objects which are added to a {@link ContentObservable}.
*/
public abstract class ContentObserver {
+ private final Object mLock = new Object();
+ private Transport mTransport; // guarded by mLock
- private Transport mTransport;
-
- // Protects mTransport
- private Object lock = new Object();
-
- /* package */ Handler mHandler;
-
- private final class NotificationRunnable implements Runnable {
-
- private boolean mSelf;
-
- public NotificationRunnable(boolean self) {
- mSelf = self;
- }
-
- public void run() {
- ContentObserver.this.onChange(mSelf);
- }
- }
-
- private static final class Transport extends IContentObserver.Stub {
- ContentObserver mContentObserver;
-
- public Transport(ContentObserver contentObserver) {
- mContentObserver = contentObserver;
- }
-
- public boolean deliverSelfNotifications() {
- ContentObserver contentObserver = mContentObserver;
- if (contentObserver != null) {
- return contentObserver.deliverSelfNotifications();
- }
- return false;
- }
-
- public void onChange(boolean selfChange) {
- ContentObserver contentObserver = mContentObserver;
- if (contentObserver != null) {
- contentObserver.dispatchChange(selfChange);
- }
- }
-
- public void releaseContentObserver() {
- mContentObserver = null;
- }
- }
+ Handler mHandler;
/**
- * onChange() will happen on the provider Handler.
+ * Creates a content observer.
*
- * @param handler The handler to run {@link #onChange} on.
+ * @param handler The handler to run {@link #onChange} on, or null if none.
*/
public ContentObserver(Handler handler) {
mHandler = handler;
@@ -86,7 +44,7 @@
* {@hide}
*/
public IContentObserver getContentObserver() {
- synchronized(lock) {
+ synchronized (mLock) {
if (mTransport == null) {
mTransport = new Transport(this);
}
@@ -101,8 +59,8 @@
* {@hide}
*/
public IContentObserver releaseContentObserver() {
- synchronized(lock) {
- Transport oldTransport = mTransport;
+ synchronized (mLock) {
+ final Transport oldTransport = mTransport;
if (oldTransport != null) {
oldTransport.releaseContentObserver();
mTransport = null;
@@ -112,27 +70,134 @@
}
/**
- * Returns true if this observer is interested in notifications for changes
- * made through the cursor the observer is registered with.
+ * Returns true if this observer is interested receiving self-change notifications.
+ *
+ * Subclasses should override this method to indicate whether the observer
+ * is interested in receiving notifications for changes that it made to the
+ * content itself.
+ *
+ * @return True if self-change notifications should be delivered to the observer.
*/
public boolean deliverSelfNotifications() {
return false;
}
/**
- * This method is called when a change occurs to the cursor that
- * is being observed.
- *
- * @param selfChange true if the update was caused by a call to <code>commit</code> on the
- * cursor that is being observed.
+ * This method is called when a content change occurs.
+ * <p>
+ * Subclasses should override this method to handle content changes.
+ * </p>
+ *
+ * @param selfChange True if this is a self-change notification.
*/
- public void onChange(boolean selfChange) {}
+ public void onChange(boolean selfChange) {
+ // Do nothing. Subclass should override.
+ }
+ /**
+ * This method is called when a content change occurs.
+ * Includes the changed content Uri when available.
+ * <p>
+ * Subclasses should override this method to handle content changes.
+ * To ensure correct operation on older versions of the framework that
+ * did not provide a Uri argument, applications should also implement
+ * the {@link #onChange(boolean)} overload of this method whenever they
+ * implement the {@link #onChange(boolean, Uri)} overload.
+ * </p><p>
+ * Example implementation:
+ * <pre><code>
+ * // Implement the onChange(boolean) method to delegate the change notification to
+ * // the onChange(boolean, Uri) method to ensure correct operation on older versions
+ * // of the framework that did not have the onChange(boolean, Uri) method.
+ * {@literal @Override}
+ * public void onChange(boolean selfChange) {
+ * onChange(selfChange, null);
+ * }
+ *
+ * // Implement the onChange(boolean, Uri) method to take advantage of the new Uri argument.
+ * {@literal @Override}
+ * public void onChange(boolean selfChange, Uri uri) {
+ * // Handle change.
+ * }
+ * </code></pre>
+ * </p>
+ *
+ * @param selfChange True if this is a self-change notification.
+ * @param uri The Uri of the changed content, or null if unknown.
+ */
+ public void onChange(boolean selfChange, Uri uri) {
+ onChange(selfChange);
+ }
+
+ /**
+ * Dispatches a change notification to the observer.
+ * <p>
+ * If a {@link Handler} was supplied to the {@link ContentObserver} constructor,
+ * then a call to the {@link #onChange} method is posted to the handler's message queue.
+ * Otherwise, the {@link #onChange} method is invoked immediately on this thread.
+ * </p>
+ *
+ * @param selfChange True if this is a self-change notification.
+ *
+ * @deprecated Use {@link #dispatchChange(boolean, Uri)} instead.
+ */
+ @Deprecated
public final void dispatchChange(boolean selfChange) {
+ dispatchChange(selfChange, null);
+ }
+
+ /**
+ * Dispatches a change notification to the observer.
+ * Includes the changed content Uri when available.
+ * <p>
+ * If a {@link Handler} was supplied to the {@link ContentObserver} constructor,
+ * then a call to the {@link #onChange} method is posted to the handler's message queue.
+ * Otherwise, the {@link #onChange} method is invoked immediately on this thread.
+ * </p>
+ *
+ * @param selfChange True if this is a self-change notification.
+ * @param uri The Uri of the changed content, or null if unknown.
+ */
+ public final void dispatchChange(boolean selfChange, Uri uri) {
if (mHandler == null) {
- onChange(selfChange);
+ onChange(selfChange, uri);
} else {
- mHandler.post(new NotificationRunnable(selfChange));
+ mHandler.post(new NotificationRunnable(selfChange, uri));
+ }
+ }
+
+ private final class NotificationRunnable implements Runnable {
+ private final boolean mSelfChange;
+ private final Uri mUri;
+
+ public NotificationRunnable(boolean selfChange, Uri uri) {
+ mSelfChange = selfChange;
+ mUri = uri;
+ }
+
+ @Override
+ public void run() {
+ ContentObserver.this.onChange(mSelfChange, mUri);
+ }
+ }
+
+ private static final class Transport extends IContentObserver.Stub {
+ private ContentObserver mContentObserver;
+
+ public Transport(ContentObserver contentObserver) {
+ mContentObserver = contentObserver;
+ }
+
+ @Override
+ public void onChange(boolean selfChange, Uri uri) {
+ ContentObserver contentObserver = mContentObserver;
+ if (contentObserver != null) {
+ contentObserver.dispatchChange(selfChange, uri);
+ }
+ }
+
+ public void releaseContentObserver() {
+ mContentObserver = null;
}
}
}
diff --git a/core/java/android/database/Cursor.java b/core/java/android/database/Cursor.java
index a9a71cf..59ec89d 100644
--- a/core/java/android/database/Cursor.java
+++ b/core/java/android/database/Cursor.java
@@ -341,6 +341,7 @@
* Deactivates the Cursor, making all calls on it fail until {@link #requery} is called.
* Inactive Cursors use fewer resources than active Cursors.
* Calling {@link #requery} will make the cursor active again.
+ * @deprecated Since {@link #requery()} is deprecated, so too is this.
*/
void deactivate();
diff --git a/core/java/android/database/CursorToBulkCursorAdaptor.java b/core/java/android/database/CursorToBulkCursorAdaptor.java
index aa0f61e37..167278a 100644
--- a/core/java/android/database/CursorToBulkCursorAdaptor.java
+++ b/core/java/android/database/CursorToBulkCursorAdaptor.java
@@ -16,6 +16,7 @@
package android.database;
+import android.net.Uri;
import android.os.Bundle;
import android.os.IBinder;
import android.os.RemoteException;
@@ -78,9 +79,9 @@
}
@Override
- public void onChange(boolean selfChange) {
+ public void onChange(boolean selfChange, Uri uri) {
try {
- mRemote.onChange(selfChange);
+ mRemote.onChange(selfChange, uri);
} catch (RemoteException ex) {
// Do nothing, the far side is dead
}
diff --git a/core/java/android/database/DataSetObservable.java b/core/java/android/database/DataSetObservable.java
index 51c72c1..ca77a13 100644
--- a/core/java/android/database/DataSetObservable.java
+++ b/core/java/android/database/DataSetObservable.java
@@ -17,13 +17,15 @@
package android.database;
/**
- * A specialization of Observable for DataSetObserver that provides methods for
- * invoking the various callback methods of DataSetObserver.
+ * A specialization of {@link Observable} for {@link DataSetObserver}
+ * that provides methods for sending notifications to a list of
+ * {@link DataSetObserver} objects.
*/
public class DataSetObservable extends Observable<DataSetObserver> {
/**
- * Invokes onChanged on each observer. Called when the data set being observed has
- * changed, and which when read contains the new state of the data.
+ * Invokes {@link DataSetObserver#onChanged} on each observer.
+ * Called when the contents of the data set have changed. The recipient
+ * will obtain the new contents the next time it queries the data set.
*/
public void notifyChanged() {
synchronized(mObservers) {
@@ -38,8 +40,9 @@
}
/**
- * Invokes onInvalidated on each observer. Called when the data set being monitored
- * has changed such that it is no longer valid.
+ * Invokes {@link DataSetObserver#onInvalidated} on each observer.
+ * Called when the data set is no longer valid and cannot be queried again,
+ * such as when the data set has been closed.
*/
public void notifyInvalidated() {
synchronized (mObservers) {
diff --git a/core/java/android/database/DatabaseUtils.java b/core/java/android/database/DatabaseUtils.java
index b69d9bf..0022118 100644
--- a/core/java/android/database/DatabaseUtils.java
+++ b/core/java/android/database/DatabaseUtils.java
@@ -21,6 +21,7 @@
import android.content.ContentValues;
import android.content.Context;
import android.content.OperationApplicationException;
+import android.content.OperationCanceledException;
import android.database.sqlite.SQLiteAbortException;
import android.database.sqlite.SQLiteConstraintException;
import android.database.sqlite.SQLiteDatabase;
@@ -107,6 +108,9 @@
code = 9;
} else if (e instanceof OperationApplicationException) {
code = 10;
+ } else if (e instanceof OperationCanceledException) {
+ code = 11;
+ logException = false;
} else {
reply.writeException(e);
Log.e(TAG, "Writing exception to parcel", e);
@@ -178,6 +182,8 @@
throw new SQLiteDiskIOException(msg);
case 9:
throw new SQLiteException(msg);
+ case 11:
+ throw new OperationCanceledException(msg);
default:
reply.readException(code, msg);
}
diff --git a/core/java/android/database/IContentObserver.aidl b/core/java/android/database/IContentObserver.aidl
index ac2f975..13aff05 100755
--- a/core/java/android/database/IContentObserver.aidl
+++ b/core/java/android/database/IContentObserver.aidl
@@ -17,6 +17,8 @@
package android.database;
+import android.net.Uri;
+
/**
* @hide
*/
@@ -27,5 +29,5 @@
* observed. selfUpdate is true if the update was caused by a call to
* commit on the cursor that is being observed.
*/
- oneway void onChange(boolean selfUpdate);
+ oneway void onChange(boolean selfUpdate, in Uri uri);
}
diff --git a/core/java/android/database/Observable.java b/core/java/android/database/Observable.java
index b6fecab..aff32db 100644
--- a/core/java/android/database/Observable.java
+++ b/core/java/android/database/Observable.java
@@ -19,7 +19,12 @@
import java.util.ArrayList;
/**
- * Provides methods for (un)registering arbitrary observers in an ArrayList.
+ * Provides methods for registering or unregistering arbitrary observers in an {@link ArrayList}.
+ *
+ * This abstract class is intended to be subclassed and specialized to maintain
+ * a registry of observers of specific types and dispatch notifications to them.
+ *
+ * @param T The observer type.
*/
public abstract class Observable<T> {
/**
@@ -66,13 +71,13 @@
mObservers.remove(index);
}
}
-
+
/**
- * Remove all registered observer
+ * Remove all registered observers.
*/
public void unregisterAll() {
synchronized(mObservers) {
mObservers.clear();
- }
+ }
}
}
diff --git a/core/java/android/database/sqlite/SQLiteConnection.java b/core/java/android/database/sqlite/SQLiteConnection.java
index 72f62fd..b5cef81 100644
--- a/core/java/android/database/sqlite/SQLiteConnection.java
+++ b/core/java/android/database/sqlite/SQLiteConnection.java
@@ -19,6 +19,8 @@
import dalvik.system.BlockGuard;
import dalvik.system.CloseGuard;
+import android.content.CancellationSignal;
+import android.content.OperationCanceledException;
import android.database.Cursor;
import android.database.CursorWindow;
import android.database.DatabaseUtils;
@@ -82,7 +84,7 @@
*
* @hide
*/
-public final class SQLiteConnection {
+public final class SQLiteConnection implements CancellationSignal.OnCancelListener {
private static final String TAG = "SQLiteConnection";
private static final boolean DEBUG = false;
@@ -108,6 +110,12 @@
private boolean mOnlyAllowReadOnlyOperations;
+ // The number of times attachCancellationSignal has been called.
+ // Because SQLite statement execution can be re-entrant, we keep track of how many
+ // times we have attempted to attach a cancellation signal to the connection so that
+ // we can ensure that we detach the signal at the right time.
+ private int mCancellationSignalAttachCount;
+
private static native int nativeOpen(String path, int openFlags, String label,
boolean enableTrace, boolean enableProfile);
private static native void nativeClose(int connectionPtr);
@@ -145,6 +153,8 @@
int connectionPtr, int statementPtr, int windowPtr,
int startPos, int requiredPos, boolean countAllRows);
private static native int nativeGetDbLookaside(int connectionPtr);
+ private static native void nativeCancel(int connectionPtr);
+ private static native void nativeResetCancel(int connectionPtr, boolean cancelable);
private SQLiteConnection(SQLiteConnectionPool pool,
SQLiteDatabaseConfiguration configuration,
@@ -345,11 +355,14 @@
*
* @param sql The SQL statement to execute.
* @param bindArgs The arguments to bind, or null if none.
+ * @param cancellationSignal A signal to cancel the operation in progress, or null if none.
*
* @throws SQLiteException if an error occurs, such as a syntax error
* or invalid number of bind arguments.
+ * @throws OperationCanceledException if the operation was canceled.
*/
- public void execute(String sql, Object[] bindArgs) {
+ public void execute(String sql, Object[] bindArgs,
+ CancellationSignal cancellationSignal) {
if (sql == null) {
throw new IllegalArgumentException("sql must not be null.");
}
@@ -361,7 +374,12 @@
throwIfStatementForbidden(statement);
bindArguments(statement, bindArgs);
applyBlockGuardPolicy(statement);
- nativeExecute(mConnectionPtr, statement.mStatementPtr);
+ attachCancellationSignal(cancellationSignal);
+ try {
+ nativeExecute(mConnectionPtr, statement.mStatementPtr);
+ } finally {
+ detachCancellationSignal(cancellationSignal);
+ }
} finally {
releasePreparedStatement(statement);
}
@@ -378,13 +396,16 @@
*
* @param sql The SQL statement to execute.
* @param bindArgs The arguments to bind, or null if none.
+ * @param cancellationSignal A signal to cancel the operation in progress, or null if none.
* @return The value of the first column in the first row of the result set
* as a <code>long</code>, or zero if none.
*
* @throws SQLiteException if an error occurs, such as a syntax error
* or invalid number of bind arguments.
+ * @throws OperationCanceledException if the operation was canceled.
*/
- public long executeForLong(String sql, Object[] bindArgs) {
+ public long executeForLong(String sql, Object[] bindArgs,
+ CancellationSignal cancellationSignal) {
if (sql == null) {
throw new IllegalArgumentException("sql must not be null.");
}
@@ -396,7 +417,12 @@
throwIfStatementForbidden(statement);
bindArguments(statement, bindArgs);
applyBlockGuardPolicy(statement);
- return nativeExecuteForLong(mConnectionPtr, statement.mStatementPtr);
+ attachCancellationSignal(cancellationSignal);
+ try {
+ return nativeExecuteForLong(mConnectionPtr, statement.mStatementPtr);
+ } finally {
+ detachCancellationSignal(cancellationSignal);
+ }
} finally {
releasePreparedStatement(statement);
}
@@ -413,13 +439,16 @@
*
* @param sql The SQL statement to execute.
* @param bindArgs The arguments to bind, or null if none.
+ * @param cancellationSignal A signal to cancel the operation in progress, or null if none.
* @return The value of the first column in the first row of the result set
* as a <code>String</code>, or null if none.
*
* @throws SQLiteException if an error occurs, such as a syntax error
* or invalid number of bind arguments.
+ * @throws OperationCanceledException if the operation was canceled.
*/
- public String executeForString(String sql, Object[] bindArgs) {
+ public String executeForString(String sql, Object[] bindArgs,
+ CancellationSignal cancellationSignal) {
if (sql == null) {
throw new IllegalArgumentException("sql must not be null.");
}
@@ -431,7 +460,12 @@
throwIfStatementForbidden(statement);
bindArguments(statement, bindArgs);
applyBlockGuardPolicy(statement);
- return nativeExecuteForString(mConnectionPtr, statement.mStatementPtr);
+ attachCancellationSignal(cancellationSignal);
+ try {
+ return nativeExecuteForString(mConnectionPtr, statement.mStatementPtr);
+ } finally {
+ detachCancellationSignal(cancellationSignal);
+ }
} finally {
releasePreparedStatement(statement);
}
@@ -449,14 +483,17 @@
*
* @param sql The SQL statement to execute.
* @param bindArgs The arguments to bind, or null if none.
+ * @param cancellationSignal A signal to cancel the operation in progress, or null if none.
* @return The file descriptor for a shared memory region that contains
* the value of the first column in the first row of the result set as a BLOB,
* or null if none.
*
* @throws SQLiteException if an error occurs, such as a syntax error
* or invalid number of bind arguments.
+ * @throws OperationCanceledException if the operation was canceled.
*/
- public ParcelFileDescriptor executeForBlobFileDescriptor(String sql, Object[] bindArgs) {
+ public ParcelFileDescriptor executeForBlobFileDescriptor(String sql, Object[] bindArgs,
+ CancellationSignal cancellationSignal) {
if (sql == null) {
throw new IllegalArgumentException("sql must not be null.");
}
@@ -469,9 +506,14 @@
throwIfStatementForbidden(statement);
bindArguments(statement, bindArgs);
applyBlockGuardPolicy(statement);
- int fd = nativeExecuteForBlobFileDescriptor(
- mConnectionPtr, statement.mStatementPtr);
- return fd >= 0 ? ParcelFileDescriptor.adoptFd(fd) : null;
+ attachCancellationSignal(cancellationSignal);
+ try {
+ int fd = nativeExecuteForBlobFileDescriptor(
+ mConnectionPtr, statement.mStatementPtr);
+ return fd >= 0 ? ParcelFileDescriptor.adoptFd(fd) : null;
+ } finally {
+ detachCancellationSignal(cancellationSignal);
+ }
} finally {
releasePreparedStatement(statement);
}
@@ -489,12 +531,15 @@
*
* @param sql The SQL statement to execute.
* @param bindArgs The arguments to bind, or null if none.
+ * @param cancellationSignal A signal to cancel the operation in progress, or null if none.
* @return The number of rows that were changed.
*
* @throws SQLiteException if an error occurs, such as a syntax error
* or invalid number of bind arguments.
+ * @throws OperationCanceledException if the operation was canceled.
*/
- public int executeForChangedRowCount(String sql, Object[] bindArgs) {
+ public int executeForChangedRowCount(String sql, Object[] bindArgs,
+ CancellationSignal cancellationSignal) {
if (sql == null) {
throw new IllegalArgumentException("sql must not be null.");
}
@@ -507,8 +552,13 @@
throwIfStatementForbidden(statement);
bindArguments(statement, bindArgs);
applyBlockGuardPolicy(statement);
- return nativeExecuteForChangedRowCount(
- mConnectionPtr, statement.mStatementPtr);
+ attachCancellationSignal(cancellationSignal);
+ try {
+ return nativeExecuteForChangedRowCount(
+ mConnectionPtr, statement.mStatementPtr);
+ } finally {
+ detachCancellationSignal(cancellationSignal);
+ }
} finally {
releasePreparedStatement(statement);
}
@@ -526,12 +576,15 @@
*
* @param sql The SQL statement to execute.
* @param bindArgs The arguments to bind, or null if none.
+ * @param cancellationSignal A signal to cancel the operation in progress, or null if none.
* @return The row id of the last row that was inserted, or 0 if none.
*
* @throws SQLiteException if an error occurs, such as a syntax error
* or invalid number of bind arguments.
+ * @throws OperationCanceledException if the operation was canceled.
*/
- public long executeForLastInsertedRowId(String sql, Object[] bindArgs) {
+ public long executeForLastInsertedRowId(String sql, Object[] bindArgs,
+ CancellationSignal cancellationSignal) {
if (sql == null) {
throw new IllegalArgumentException("sql must not be null.");
}
@@ -544,8 +597,13 @@
throwIfStatementForbidden(statement);
bindArguments(statement, bindArgs);
applyBlockGuardPolicy(statement);
- return nativeExecuteForLastInsertedRowId(
- mConnectionPtr, statement.mStatementPtr);
+ attachCancellationSignal(cancellationSignal);
+ try {
+ return nativeExecuteForLastInsertedRowId(
+ mConnectionPtr, statement.mStatementPtr);
+ } finally {
+ detachCancellationSignal(cancellationSignal);
+ }
} finally {
releasePreparedStatement(statement);
}
@@ -571,14 +629,17 @@
* so that it does. Must be greater than or equal to <code>startPos</code>.
* @param countAllRows True to count all rows that the query would return
* regagless of whether they fit in the window.
+ * @param cancellationSignal A signal to cancel the operation in progress, or null if none.
* @return The number of rows that were counted during query execution. Might
* not be all rows in the result set unless <code>countAllRows</code> is true.
*
* @throws SQLiteException if an error occurs, such as a syntax error
* or invalid number of bind arguments.
+ * @throws OperationCanceledException if the operation was canceled.
*/
public int executeForCursorWindow(String sql, Object[] bindArgs,
- CursorWindow window, int startPos, int requiredPos, boolean countAllRows) {
+ CursorWindow window, int startPos, int requiredPos, boolean countAllRows,
+ CancellationSignal cancellationSignal) {
if (sql == null) {
throw new IllegalArgumentException("sql must not be null.");
}
@@ -597,14 +658,19 @@
throwIfStatementForbidden(statement);
bindArguments(statement, bindArgs);
applyBlockGuardPolicy(statement);
- final long result = nativeExecuteForCursorWindow(
- mConnectionPtr, statement.mStatementPtr, window.mWindowPtr,
- startPos, requiredPos, countAllRows);
- actualPos = (int)(result >> 32);
- countedRows = (int)result;
- filledRows = window.getNumRows();
- window.setStartPosition(actualPos);
- return countedRows;
+ attachCancellationSignal(cancellationSignal);
+ try {
+ final long result = nativeExecuteForCursorWindow(
+ mConnectionPtr, statement.mStatementPtr, window.mWindowPtr,
+ startPos, requiredPos, countAllRows);
+ actualPos = (int)(result >> 32);
+ countedRows = (int)result;
+ filledRows = window.getNumRows();
+ window.setStartPosition(actualPos);
+ return countedRows;
+ } finally {
+ detachCancellationSignal(cancellationSignal);
+ }
} finally {
releasePreparedStatement(statement);
}
@@ -685,6 +751,46 @@
recyclePreparedStatement(statement);
}
+ private void attachCancellationSignal(CancellationSignal cancellationSignal) {
+ if (cancellationSignal != null) {
+ cancellationSignal.throwIfCanceled();
+
+ mCancellationSignalAttachCount += 1;
+ if (mCancellationSignalAttachCount == 1) {
+ // Reset cancellation flag before executing the statement.
+ nativeResetCancel(mConnectionPtr, true /*cancelable*/);
+
+ // After this point, onCancel() may be called concurrently.
+ cancellationSignal.setOnCancelListener(this);
+ }
+ }
+ }
+
+ private void detachCancellationSignal(CancellationSignal cancellationSignal) {
+ if (cancellationSignal != null) {
+ assert mCancellationSignalAttachCount > 0;
+
+ mCancellationSignalAttachCount -= 1;
+ if (mCancellationSignalAttachCount == 0) {
+ // After this point, onCancel() cannot be called concurrently.
+ cancellationSignal.setOnCancelListener(null);
+
+ // Reset cancellation flag after executing the statement.
+ nativeResetCancel(mConnectionPtr, false /*cancelable*/);
+ }
+ }
+ }
+
+ // CancellationSignal.OnCancelListener callback.
+ // This method may be called on a different thread than the executing statement.
+ // However, it will only be called between calls to attachCancellationSignal and
+ // detachCancellationSignal, while a statement is executing. We can safely assume
+ // that the SQLite connection is still alive.
+ @Override
+ public void onCancel() {
+ nativeCancel(mConnectionPtr);
+ }
+
private void bindArguments(PreparedStatement statement, Object[] bindArgs) {
final int count = bindArgs != null ? bindArgs.length : 0;
if (count != statement.mNumParameters) {
@@ -822,8 +928,8 @@
long pageCount = 0;
long pageSize = 0;
try {
- pageCount = executeForLong("PRAGMA page_count;", null);
- pageSize = executeForLong("PRAGMA page_size;", null);
+ pageCount = executeForLong("PRAGMA page_count;", null, null);
+ pageSize = executeForLong("PRAGMA page_size;", null, null);
} catch (SQLiteException ex) {
// Ignore.
}
@@ -834,15 +940,15 @@
// the main database which we have already described.
CursorWindow window = new CursorWindow("collectDbStats");
try {
- executeForCursorWindow("PRAGMA database_list;", null, window, 0, 0, false);
+ executeForCursorWindow("PRAGMA database_list;", null, window, 0, 0, false, null);
for (int i = 1; i < window.getNumRows(); i++) {
String name = window.getString(i, 1);
String path = window.getString(i, 2);
pageCount = 0;
pageSize = 0;
try {
- pageCount = executeForLong("PRAGMA " + name + ".page_count;", null);
- pageSize = executeForLong("PRAGMA " + name + ".page_size;", null);
+ pageCount = executeForLong("PRAGMA " + name + ".page_count;", null, null);
+ pageSize = executeForLong("PRAGMA " + name + ".page_size;", null, null);
} catch (SQLiteException ex) {
// Ignore.
}
diff --git a/core/java/android/database/sqlite/SQLiteConnectionPool.java b/core/java/android/database/sqlite/SQLiteConnectionPool.java
index 5469213..236948e 100644
--- a/core/java/android/database/sqlite/SQLiteConnectionPool.java
+++ b/core/java/android/database/sqlite/SQLiteConnectionPool.java
@@ -18,6 +18,8 @@
import dalvik.system.CloseGuard;
+import android.content.CancellationSignal;
+import android.content.OperationCanceledException;
import android.database.sqlite.SQLiteDebug.DbStats;
import android.os.SystemClock;
import android.util.Log;
@@ -282,13 +284,16 @@
* @param sql If not null, try to find a connection that already has
* the specified SQL statement in its prepared statement cache.
* @param connectionFlags The connection request flags.
+ * @param cancellationSignal A signal to cancel the operation in progress, or null if none.
* @return The connection that was acquired, never null.
*
* @throws IllegalStateException if the pool has been closed.
* @throws SQLiteException if a database error occurs.
+ * @throws OperationCanceledException if the operation was canceled.
*/
- public SQLiteConnection acquireConnection(String sql, int connectionFlags) {
- return waitForConnection(sql, connectionFlags);
+ public SQLiteConnection acquireConnection(String sql, int connectionFlags,
+ CancellationSignal cancellationSignal) {
+ return waitForConnection(sql, connectionFlags, cancellationSignal);
}
/**
@@ -497,7 +502,8 @@
}
// Might throw.
- private SQLiteConnection waitForConnection(String sql, int connectionFlags) {
+ private SQLiteConnection waitForConnection(String sql, int connectionFlags,
+ CancellationSignal cancellationSignal) {
final boolean wantPrimaryConnection =
(connectionFlags & CONNECTION_FLAG_PRIMARY_CONNECTION_AFFINITY) != 0;
@@ -505,6 +511,11 @@
synchronized (mLock) {
throwIfClosedLocked();
+ // Abort if canceled.
+ if (cancellationSignal != null) {
+ cancellationSignal.throwIfCanceled();
+ }
+
// Try to acquire a connection.
SQLiteConnection connection = null;
if (!wantPrimaryConnection) {
@@ -538,6 +549,18 @@
} else {
mConnectionWaiterQueue = waiter;
}
+
+ if (cancellationSignal != null) {
+ final int nonce = waiter.mNonce;
+ cancellationSignal.setOnCancelListener(new CancellationSignal.OnCancelListener() {
+ @Override
+ public void onCancel() {
+ synchronized (mLock) {
+ cancelConnectionWaiterLocked(waiter, nonce);
+ }
+ }
+ });
+ }
}
// Park the thread until a connection is assigned or the pool is closed.
@@ -547,7 +570,9 @@
for (;;) {
// Detect and recover from connection leaks.
if (mConnectionLeaked.compareAndSet(true, false)) {
- wakeConnectionWaitersLocked();
+ synchronized (mLock) {
+ wakeConnectionWaitersLocked();
+ }
}
// Wait to be unparked (may already have happened), a timeout, or interruption.
@@ -560,15 +585,16 @@
synchronized (mLock) {
throwIfClosedLocked();
- SQLiteConnection connection = waiter.mAssignedConnection;
- if (connection != null) {
+ final SQLiteConnection connection = waiter.mAssignedConnection;
+ final RuntimeException ex = waiter.mException;
+ if (connection != null || ex != null) {
+ if (cancellationSignal != null) {
+ cancellationSignal.setOnCancelListener(null);
+ }
recycleConnectionWaiterLocked(waiter);
- return connection;
- }
-
- RuntimeException ex = waiter.mException;
- if (ex != null) {
- recycleConnectionWaiterLocked(waiter);
+ if (connection != null) {
+ return connection;
+ }
throw ex; // rethrow!
}
@@ -585,6 +611,40 @@
}
// Can't throw.
+ private void cancelConnectionWaiterLocked(ConnectionWaiter waiter, int nonce) {
+ if (waiter.mNonce != nonce) {
+ // Waiter already removed and recycled.
+ return;
+ }
+
+ if (waiter.mAssignedConnection != null || waiter.mException != null) {
+ // Waiter is done waiting but has not woken up yet.
+ return;
+ }
+
+ // Waiter must still be waiting. Dequeue it.
+ ConnectionWaiter predecessor = null;
+ ConnectionWaiter current = mConnectionWaiterQueue;
+ while (current != waiter) {
+ assert current != null;
+ predecessor = current;
+ current = current.mNext;
+ }
+ if (predecessor != null) {
+ predecessor.mNext = waiter.mNext;
+ } else {
+ mConnectionWaiterQueue = waiter.mNext;
+ }
+
+ // Send the waiter an exception and unpark it.
+ waiter.mException = new OperationCanceledException();
+ LockSupport.unpark(waiter.mThread);
+
+ // Check whether removing this waiter will enable other waiters to make progress.
+ wakeConnectionWaitersLocked();
+ }
+
+ // Can't throw.
private void logConnectionPoolBusyLocked(long waitMillis, int connectionFlags) {
final Thread thread = Thread.currentThread();
StringBuilder msg = new StringBuilder();
@@ -826,6 +886,7 @@
waiter.mSql = null;
waiter.mAssignedConnection = null;
waiter.mException = null;
+ waiter.mNonce += 1;
mConnectionWaiterPool = waiter;
}
@@ -904,5 +965,6 @@
public int mConnectionFlags;
public SQLiteConnection mAssignedConnection;
public RuntimeException mException;
+ public int mNonce;
}
}
diff --git a/core/java/android/database/sqlite/SQLiteCursor.java b/core/java/android/database/sqlite/SQLiteCursor.java
index 946300f..82bb23e 100644
--- a/core/java/android/database/sqlite/SQLiteCursor.java
+++ b/core/java/android/database/sqlite/SQLiteCursor.java
@@ -65,8 +65,7 @@
* interface. For a query such as: {@code SELECT name, birth, phone FROM
* myTable WHERE ... LIMIT 1,20 ORDER BY...} the column names (name, birth,
* phone) would be in the projection argument and everything from
- * {@code FROM} onward would be in the params argument. This constructor
- * has package scope.
+ * {@code FROM} onward would be in the params argument.
*
* @param db a reference to a Database object that is already constructed
* and opened. This param is not used any longer
@@ -86,8 +85,7 @@
* interface. For a query such as: {@code SELECT name, birth, phone FROM
* myTable WHERE ... LIMIT 1,20 ORDER BY...} the column names (name, birth,
* phone) would be in the projection argument and everything from
- * {@code FROM} onward would be in the params argument. This constructor
- * has package scope.
+ * {@code FROM} onward would be in the params argument.
*
* @param editTable the name of the table used for this query
* @param query the {@link SQLiteQuery} object associated with this cursor object.
diff --git a/core/java/android/database/sqlite/SQLiteDatabase.java b/core/java/android/database/sqlite/SQLiteDatabase.java
index 9cb6480..505f83e 100644
--- a/core/java/android/database/sqlite/SQLiteDatabase.java
+++ b/core/java/android/database/sqlite/SQLiteDatabase.java
@@ -16,7 +16,9 @@
package android.database.sqlite;
+import android.content.CancellationSignal;
import android.content.ContentValues;
+import android.content.OperationCanceledException;
import android.content.res.Resources;
import android.database.Cursor;
import android.database.DatabaseErrorHandler;
@@ -492,7 +494,7 @@
boolean exclusive) {
getThreadSession().beginTransaction(exclusive ? SQLiteSession.TRANSACTION_MODE_EXCLUSIVE :
SQLiteSession.TRANSACTION_MODE_IMMEDIATE, transactionListener,
- getThreadDefaultConnectionFlags(false /*readOnly*/));
+ getThreadDefaultConnectionFlags(false /*readOnly*/), null);
}
/**
@@ -500,7 +502,7 @@
* are committed and rolled back.
*/
public void endTransaction() {
- getThreadSession().endTransaction();
+ getThreadSession().endTransaction(null);
}
/**
@@ -597,7 +599,7 @@
}
private boolean yieldIfContendedHelper(boolean throwIfUnsafe, long sleepAfterYieldDelay) {
- return getThreadSession().yieldTransaction(sleepAfterYieldDelay, throwIfUnsafe);
+ return getThreadSession().yieldTransaction(sleepAfterYieldDelay, throwIfUnsafe, null);
}
/**
@@ -935,7 +937,48 @@
String selection, String[] selectionArgs, String groupBy,
String having, String orderBy, String limit) {
return queryWithFactory(null, distinct, table, columns, selection, selectionArgs,
- groupBy, having, orderBy, limit);
+ groupBy, having, orderBy, limit, null);
+ }
+
+ /**
+ * Query the given URL, returning a {@link Cursor} over the result set.
+ *
+ * @param distinct true if you want each row to be unique, false otherwise.
+ * @param table The table name to compile the query against.
+ * @param columns A list of which columns to return. Passing null will
+ * return all columns, which is discouraged to prevent reading
+ * data from storage that isn't going to be used.
+ * @param selection A filter declaring which rows to return, formatted as an
+ * SQL WHERE clause (excluding the WHERE itself). Passing null
+ * will return all rows for the given table.
+ * @param selectionArgs You may include ?s in selection, which will be
+ * replaced by the values from selectionArgs, in order that they
+ * appear in the selection. The values will be bound as Strings.
+ * @param groupBy A filter declaring how to group rows, formatted as an SQL
+ * GROUP BY clause (excluding the GROUP BY itself). Passing null
+ * will cause the rows to not be grouped.
+ * @param having A filter declare which row groups to include in the cursor,
+ * if row grouping is being used, formatted as an SQL HAVING
+ * clause (excluding the HAVING itself). Passing null will cause
+ * all row groups to be included, and is required when row
+ * grouping is not being used.
+ * @param orderBy How to order the rows, formatted as an SQL ORDER BY clause
+ * (excluding the ORDER BY itself). Passing null will use the
+ * default sort order, which may be unordered.
+ * @param limit Limits the number of rows returned by the query,
+ * formatted as LIMIT clause. Passing null denotes no LIMIT clause.
+ * @param cancellationSignal A signal to cancel the operation in progress, or null if none.
+ * If the operation is canceled, then {@link OperationCanceledException} will be thrown
+ * when the query is executed.
+ * @return A {@link Cursor} object, which is positioned before the first entry. Note that
+ * {@link Cursor}s are not synchronized, see the documentation for more details.
+ * @see Cursor
+ */
+ public Cursor query(boolean distinct, String table, String[] columns,
+ String selection, String[] selectionArgs, String groupBy,
+ String having, String orderBy, String limit, CancellationSignal cancellationSignal) {
+ return queryWithFactory(null, distinct, table, columns, selection, selectionArgs,
+ groupBy, having, orderBy, limit, cancellationSignal);
}
/**
@@ -974,12 +1017,55 @@
boolean distinct, String table, String[] columns,
String selection, String[] selectionArgs, String groupBy,
String having, String orderBy, String limit) {
+ return queryWithFactory(cursorFactory, distinct, table, columns, selection,
+ selectionArgs, groupBy, having, orderBy, limit, null);
+ }
+
+ /**
+ * Query the given URL, returning a {@link Cursor} over the result set.
+ *
+ * @param cursorFactory the cursor factory to use, or null for the default factory
+ * @param distinct true if you want each row to be unique, false otherwise.
+ * @param table The table name to compile the query against.
+ * @param columns A list of which columns to return. Passing null will
+ * return all columns, which is discouraged to prevent reading
+ * data from storage that isn't going to be used.
+ * @param selection A filter declaring which rows to return, formatted as an
+ * SQL WHERE clause (excluding the WHERE itself). Passing null
+ * will return all rows for the given table.
+ * @param selectionArgs You may include ?s in selection, which will be
+ * replaced by the values from selectionArgs, in order that they
+ * appear in the selection. The values will be bound as Strings.
+ * @param groupBy A filter declaring how to group rows, formatted as an SQL
+ * GROUP BY clause (excluding the GROUP BY itself). Passing null
+ * will cause the rows to not be grouped.
+ * @param having A filter declare which row groups to include in the cursor,
+ * if row grouping is being used, formatted as an SQL HAVING
+ * clause (excluding the HAVING itself). Passing null will cause
+ * all row groups to be included, and is required when row
+ * grouping is not being used.
+ * @param orderBy How to order the rows, formatted as an SQL ORDER BY clause
+ * (excluding the ORDER BY itself). Passing null will use the
+ * default sort order, which may be unordered.
+ * @param limit Limits the number of rows returned by the query,
+ * formatted as LIMIT clause. Passing null denotes no LIMIT clause.
+ * @param cancellationSignal A signal to cancel the operation in progress, or null if none.
+ * If the operation is canceled, then {@link OperationCanceledException} will be thrown
+ * when the query is executed.
+ * @return A {@link Cursor} object, which is positioned before the first entry. Note that
+ * {@link Cursor}s are not synchronized, see the documentation for more details.
+ * @see Cursor
+ */
+ public Cursor queryWithFactory(CursorFactory cursorFactory,
+ boolean distinct, String table, String[] columns,
+ String selection, String[] selectionArgs, String groupBy,
+ String having, String orderBy, String limit, CancellationSignal cancellationSignal) {
throwIfNotOpen(); // fail fast
String sql = SQLiteQueryBuilder.buildQueryString(
distinct, table, columns, selection, groupBy, having, orderBy, limit);
- return rawQueryWithFactory(
- cursorFactory, sql, selectionArgs, findEditTable(table));
+ return rawQueryWithFactory(cursorFactory, sql, selectionArgs,
+ findEditTable(table), cancellationSignal);
}
/**
@@ -1067,7 +1153,25 @@
* {@link Cursor}s are not synchronized, see the documentation for more details.
*/
public Cursor rawQuery(String sql, String[] selectionArgs) {
- return rawQueryWithFactory(null, sql, selectionArgs, null);
+ return rawQueryWithFactory(null, sql, selectionArgs, null, null);
+ }
+
+ /**
+ * Runs the provided SQL and returns a {@link Cursor} over the result set.
+ *
+ * @param sql the SQL query. The SQL string must not be ; terminated
+ * @param selectionArgs You may include ?s in where clause in the query,
+ * which will be replaced by the values from selectionArgs. The
+ * values will be bound as Strings.
+ * @param cancellationSignal A signal to cancel the operation in progress, or null if none.
+ * If the operation is canceled, then {@link OperationCanceledException} will be thrown
+ * when the query is executed.
+ * @return A {@link Cursor} object, which is positioned before the first entry. Note that
+ * {@link Cursor}s are not synchronized, see the documentation for more details.
+ */
+ public Cursor rawQuery(String sql, String[] selectionArgs,
+ CancellationSignal cancellationSignal) {
+ return rawQueryWithFactory(null, sql, selectionArgs, null, cancellationSignal);
}
/**
@@ -1085,9 +1189,31 @@
public Cursor rawQueryWithFactory(
CursorFactory cursorFactory, String sql, String[] selectionArgs,
String editTable) {
+ return rawQueryWithFactory(cursorFactory, sql, selectionArgs, editTable, null);
+ }
+
+ /**
+ * Runs the provided SQL and returns a cursor over the result set.
+ *
+ * @param cursorFactory the cursor factory to use, or null for the default factory
+ * @param sql the SQL query. The SQL string must not be ; terminated
+ * @param selectionArgs You may include ?s in where clause in the query,
+ * which will be replaced by the values from selectionArgs. The
+ * values will be bound as Strings.
+ * @param editTable the name of the first table, which is editable
+ * @param cancellationSignal A signal to cancel the operation in progress, or null if none.
+ * If the operation is canceled, then {@link OperationCanceledException} will be thrown
+ * when the query is executed.
+ * @return A {@link Cursor} object, which is positioned before the first entry. Note that
+ * {@link Cursor}s are not synchronized, see the documentation for more details.
+ */
+ public Cursor rawQueryWithFactory(
+ CursorFactory cursorFactory, String sql, String[] selectionArgs,
+ String editTable, CancellationSignal cancellationSignal) {
throwIfNotOpen(); // fail fast
- SQLiteCursorDriver driver = new SQLiteDirectCursorDriver(this, sql, editTable);
+ SQLiteCursorDriver driver = new SQLiteDirectCursorDriver(this, sql, editTable,
+ cancellationSignal);
return driver.query(cursorFactory != null ? cursorFactory : mCursorFactory,
selectionArgs);
}
@@ -1786,7 +1912,7 @@
*/
void lockPrimaryConnection() {
getThreadSession().beginTransaction(SQLiteSession.TRANSACTION_MODE_DEFERRED,
- null, SQLiteConnectionPool.CONNECTION_FLAG_PRIMARY_CONNECTION_AFFINITY);
+ null, SQLiteConnectionPool.CONNECTION_FLAG_PRIMARY_CONNECTION_AFFINITY, null);
}
/**
@@ -1795,7 +1921,7 @@
* @see #lockPrimaryConnection()
*/
void unlockPrimaryConnection() {
- getThreadSession().endTransaction();
+ getThreadSession().endTransaction(null);
}
@Override
diff --git a/core/java/android/database/sqlite/SQLiteDirectCursorDriver.java b/core/java/android/database/sqlite/SQLiteDirectCursorDriver.java
index 52fd1d2..3375e74 100644
--- a/core/java/android/database/sqlite/SQLiteDirectCursorDriver.java
+++ b/core/java/android/database/sqlite/SQLiteDirectCursorDriver.java
@@ -16,6 +16,7 @@
package android.database.sqlite;
+import android.content.CancellationSignal;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase.CursorFactory;
@@ -28,16 +29,19 @@
private final SQLiteDatabase mDatabase;
private final String mEditTable;
private final String mSql;
+ private final CancellationSignal mCancellationSignal;
private SQLiteQuery mQuery;
- public SQLiteDirectCursorDriver(SQLiteDatabase db, String sql, String editTable) {
+ public SQLiteDirectCursorDriver(SQLiteDatabase db, String sql, String editTable,
+ CancellationSignal cancellationSignal) {
mDatabase = db;
mEditTable = editTable;
mSql = sql;
+ mCancellationSignal = cancellationSignal;
}
public Cursor query(CursorFactory factory, String[] selectionArgs) {
- final SQLiteQuery query = new SQLiteQuery(mDatabase, mSql);
+ final SQLiteQuery query = new SQLiteQuery(mDatabase, mSql, mCancellationSignal);
final Cursor cursor;
try {
query.bindAllArgsAsStrings(selectionArgs);
diff --git a/core/java/android/database/sqlite/SQLiteProgram.java b/core/java/android/database/sqlite/SQLiteProgram.java
index 8194458..9f0edfb 100644
--- a/core/java/android/database/sqlite/SQLiteProgram.java
+++ b/core/java/android/database/sqlite/SQLiteProgram.java
@@ -16,6 +16,7 @@
package android.database.sqlite;
+import android.content.CancellationSignal;
import android.database.DatabaseUtils;
import java.util.Arrays;
@@ -36,7 +37,8 @@
private final int mNumParameters;
private final Object[] mBindArgs;
- SQLiteProgram(SQLiteDatabase db, String sql, Object[] bindArgs) {
+ SQLiteProgram(SQLiteDatabase db, String sql, Object[] bindArgs,
+ CancellationSignal cancellationSignalForPrepare) {
mDatabase = db;
mSql = sql.trim();
@@ -54,7 +56,8 @@
boolean assumeReadOnly = (n == DatabaseUtils.STATEMENT_SELECT);
SQLiteStatementInfo info = new SQLiteStatementInfo();
db.getThreadSession().prepare(mSql,
- db.getThreadDefaultConnectionFlags(assumeReadOnly), info);
+ db.getThreadDefaultConnectionFlags(assumeReadOnly),
+ cancellationSignalForPrepare, info);
mReadOnly = info.readOnly;
mColumnNames = info.columnNames;
mNumParameters = info.numParameters;
diff --git a/core/java/android/database/sqlite/SQLiteQuery.java b/core/java/android/database/sqlite/SQLiteQuery.java
index 17aa886..30e77b5 100644
--- a/core/java/android/database/sqlite/SQLiteQuery.java
+++ b/core/java/android/database/sqlite/SQLiteQuery.java
@@ -16,6 +16,8 @@
package android.database.sqlite;
+import android.content.CancellationSignal;
+import android.content.OperationCanceledException;
import android.database.CursorWindow;
import android.util.Log;
@@ -29,8 +31,12 @@
public final class SQLiteQuery extends SQLiteProgram {
private static final String TAG = "SQLiteQuery";
- SQLiteQuery(SQLiteDatabase db, String query) {
- super(db, query, null);
+ private final CancellationSignal mCancellationSignal;
+
+ SQLiteQuery(SQLiteDatabase db, String query, CancellationSignal cancellationSignal) {
+ super(db, query, null, cancellationSignal);
+
+ mCancellationSignal = cancellationSignal;
}
/**
@@ -44,6 +50,9 @@
* return regardless of whether they fit in the window.
* @return Number of rows that were enumerated. Might not be all rows
* unless countAllRows is true.
+ *
+ * @throws SQLiteException if an error occurs.
+ * @throws OperationCanceledException if the operation was canceled.
*/
int fillWindow(CursorWindow window, int startPos, int requiredPos, boolean countAllRows) {
acquireReference();
@@ -51,7 +60,8 @@
window.acquireReference();
try {
int numRows = getSession().executeForCursorWindow(getSql(), getBindArgs(),
- window, startPos, requiredPos, countAllRows, getConnectionFlags());
+ window, startPos, requiredPos, countAllRows, getConnectionFlags(),
+ mCancellationSignal);
return numRows;
} catch (SQLiteDatabaseCorruptException ex) {
onCorruption();
diff --git a/core/java/android/database/sqlite/SQLiteQueryBuilder.java b/core/java/android/database/sqlite/SQLiteQueryBuilder.java
index 1b7b398..6f84b5e 100644
--- a/core/java/android/database/sqlite/SQLiteQueryBuilder.java
+++ b/core/java/android/database/sqlite/SQLiteQueryBuilder.java
@@ -16,6 +16,8 @@
package android.database.sqlite;
+import android.content.CancellationSignal;
+import android.content.OperationCanceledException;
import android.database.Cursor;
import android.database.DatabaseUtils;
import android.provider.BaseColumns;
@@ -137,8 +139,9 @@
/**
* Sets the cursor factory to be used for the query. You can use
* one factory for all queries on a database but it is normally
- * easier to specify the factory when doing this query. @param
- * factory the factor to use
+ * easier to specify the factory when doing this query.
+ *
+ * @param factory the factory to use.
*/
public void setCursorFactory(SQLiteDatabase.CursorFactory factory) {
mFactory = factory;
@@ -289,7 +292,7 @@
String selection, String[] selectionArgs, String groupBy,
String having, String sortOrder) {
return query(db, projectionIn, selection, selectionArgs, groupBy, having, sortOrder,
- null /* limit */);
+ null /* limit */, null /* cancellationSignal */);
}
/**
@@ -327,6 +330,48 @@
public Cursor query(SQLiteDatabase db, String[] projectionIn,
String selection, String[] selectionArgs, String groupBy,
String having, String sortOrder, String limit) {
+ return query(db, projectionIn, selection, selectionArgs,
+ groupBy, having, sortOrder, limit, null);
+ }
+
+ /**
+ * Perform a query by combining all current settings and the
+ * information passed into this method.
+ *
+ * @param db the database to query on
+ * @param projectionIn A list of which columns to return. Passing
+ * null will return all columns, which is discouraged to prevent
+ * reading data from storage that isn't going to be used.
+ * @param selection A filter declaring which rows to return,
+ * formatted as an SQL WHERE clause (excluding the WHERE
+ * itself). Passing null will return all rows for the given URL.
+ * @param selectionArgs You may include ?s in selection, which
+ * will be replaced by the values from selectionArgs, in order
+ * that they appear in the selection. The values will be bound
+ * as Strings.
+ * @param groupBy A filter declaring how to group rows, formatted
+ * as an SQL GROUP BY clause (excluding the GROUP BY
+ * itself). Passing null will cause the rows to not be grouped.
+ * @param having A filter declare which row groups to include in
+ * the cursor, if row grouping is being used, formatted as an
+ * SQL HAVING clause (excluding the HAVING itself). Passing
+ * null will cause all row groups to be included, and is
+ * required when row grouping is not being used.
+ * @param sortOrder How to order the rows, formatted as an SQL
+ * ORDER BY clause (excluding the ORDER BY itself). Passing null
+ * will use the default sort order, which may be unordered.
+ * @param limit Limits the number of rows returned by the query,
+ * formatted as LIMIT clause. Passing null denotes no LIMIT clause.
+ * @param cancellationSignal A signal to cancel the operation in progress, or null if none.
+ * If the operation is canceled, then {@link OperationCanceledException} will be thrown
+ * when the query is executed.
+ * @return a cursor over the result set
+ * @see android.content.ContentResolver#query(android.net.Uri, String[],
+ * String, String[], String)
+ */
+ public Cursor query(SQLiteDatabase db, String[] projectionIn,
+ String selection, String[] selectionArgs, String groupBy,
+ String having, String sortOrder, String limit, CancellationSignal cancellationSignal) {
if (mTables == null) {
return null;
}
@@ -341,7 +386,8 @@
// in both the wrapped and original forms.
String sqlForValidation = buildQuery(projectionIn, "(" + selection + ")", groupBy,
having, sortOrder, limit);
- validateQuerySql(db, sqlForValidation); // will throw if query is invalid
+ validateQuerySql(db, sqlForValidation,
+ cancellationSignal); // will throw if query is invalid
}
String sql = buildQuery(
@@ -353,16 +399,18 @@
}
return db.rawQueryWithFactory(
mFactory, sql, selectionArgs,
- SQLiteDatabase.findEditTable(mTables)); // will throw if query is invalid
+ SQLiteDatabase.findEditTable(mTables),
+ cancellationSignal); // will throw if query is invalid
}
/**
* Verifies that a SQL SELECT statement is valid by compiling it.
* If the SQL statement is not valid, this method will throw a {@link SQLiteException}.
*/
- private void validateQuerySql(SQLiteDatabase db, String sql) {
+ private void validateQuerySql(SQLiteDatabase db, String sql,
+ CancellationSignal cancellationSignal) {
db.getThreadSession().prepare(sql,
- db.getThreadDefaultConnectionFlags(true /*readOnly*/), null);
+ db.getThreadDefaultConnectionFlags(true /*readOnly*/), cancellationSignal, null);
}
/**
diff --git a/core/java/android/database/sqlite/SQLiteSession.java b/core/java/android/database/sqlite/SQLiteSession.java
index a933051..43efb03 100644
--- a/core/java/android/database/sqlite/SQLiteSession.java
+++ b/core/java/android/database/sqlite/SQLiteSession.java
@@ -16,6 +16,8 @@
package android.database.sqlite;
+import android.content.CancellationSignal;
+import android.content.OperationCanceledException;
import android.database.CursorWindow;
import android.database.DatabaseUtils;
import android.os.ParcelFileDescriptor;
@@ -156,8 +158,6 @@
* triggers may call custom SQLite functions that perform additional queries.
* </p>
*
- * TODO: Support timeouts on all possibly blocking operations.
- *
* @hide
*/
public final class SQLiteSession {
@@ -280,24 +280,34 @@
* @param transactionListener The transaction listener, or null if none.
* @param connectionFlags The connection flags to use if a connection must be
* acquired by this operation. Refer to {@link SQLiteConnectionPool}.
+ * @param cancellationSignal A signal to cancel the operation in progress, or null if none.
*
* @throws IllegalStateException if {@link #setTransactionSuccessful} has already been
* called for the current transaction.
+ * @throws SQLiteException if an error occurs.
+ * @throws OperationCanceledException if the operation was canceled.
*
* @see #setTransactionSuccessful
* @see #yieldTransaction
* @see #endTransaction
*/
public void beginTransaction(int transactionMode,
- SQLiteTransactionListener transactionListener, int connectionFlags) {
+ SQLiteTransactionListener transactionListener, int connectionFlags,
+ CancellationSignal cancellationSignal) {
throwIfTransactionMarkedSuccessful();
- beginTransactionUnchecked(transactionMode, transactionListener, connectionFlags);
+ beginTransactionUnchecked(transactionMode, transactionListener, connectionFlags,
+ cancellationSignal);
}
private void beginTransactionUnchecked(int transactionMode,
- SQLiteTransactionListener transactionListener, int connectionFlags) {
+ SQLiteTransactionListener transactionListener, int connectionFlags,
+ CancellationSignal cancellationSignal) {
+ if (cancellationSignal != null) {
+ cancellationSignal.throwIfCanceled();
+ }
+
if (mTransactionStack == null) {
- acquireConnection(null, connectionFlags); // might throw
+ acquireConnection(null, connectionFlags, cancellationSignal); // might throw
}
try {
// Set up the transaction such that we can back out safely
@@ -306,13 +316,15 @@
// Execute SQL might throw a runtime exception.
switch (transactionMode) {
case TRANSACTION_MODE_IMMEDIATE:
- mConnection.execute("BEGIN IMMEDIATE;", null); // might throw
+ mConnection.execute("BEGIN IMMEDIATE;", null,
+ cancellationSignal); // might throw
break;
case TRANSACTION_MODE_EXCLUSIVE:
- mConnection.execute("BEGIN EXCLUSIVE;", null); // might throw
+ mConnection.execute("BEGIN EXCLUSIVE;", null,
+ cancellationSignal); // might throw
break;
default:
- mConnection.execute("BEGIN;", null); // might throw
+ mConnection.execute("BEGIN;", null, cancellationSignal); // might throw
break;
}
}
@@ -323,7 +335,7 @@
transactionListener.onBegin(); // might throw
} catch (RuntimeException ex) {
if (mTransactionStack == null) {
- mConnection.execute("ROLLBACK;", null); // might throw
+ mConnection.execute("ROLLBACK;", null, cancellationSignal); // might throw
}
throw ex;
}
@@ -372,20 +384,28 @@
* This method must be called exactly once for each call to {@link #beginTransaction}.
* </p>
*
+ * @param cancellationSignal A signal to cancel the operation in progress, or null if none.
+ *
* @throws IllegalStateException if there is no current transaction.
+ * @throws SQLiteException if an error occurs.
+ * @throws OperationCanceledException if the operation was canceled.
*
* @see #beginTransaction
* @see #setTransactionSuccessful
* @see #yieldTransaction
*/
- public void endTransaction() {
+ public void endTransaction(CancellationSignal cancellationSignal) {
throwIfNoTransaction();
assert mConnection != null;
- endTransactionUnchecked();
+ endTransactionUnchecked(cancellationSignal);
}
- private void endTransactionUnchecked() {
+ private void endTransactionUnchecked(CancellationSignal cancellationSignal) {
+ if (cancellationSignal != null) {
+ cancellationSignal.throwIfCanceled();
+ }
+
final Transaction top = mTransactionStack;
boolean successful = top.mMarkedSuccessful && !top.mChildFailed;
@@ -414,9 +434,9 @@
} else {
try {
if (successful) {
- mConnection.execute("COMMIT;", null); // might throw
+ mConnection.execute("COMMIT;", null, cancellationSignal); // might throw
} else {
- mConnection.execute("ROLLBACK;", null); // might throw
+ mConnection.execute("ROLLBACK;", null, cancellationSignal); // might throw
}
} finally {
releaseConnection(); // might throw
@@ -467,16 +487,20 @@
* @param throwIfUnsafe If true, then instead of returning false when no
* transaction is in progress, a nested transaction is in progress, or when
* the transaction has already been marked successful, throws {@link IllegalStateException}.
+ * @param cancellationSignal A signal to cancel the operation in progress, or null if none.
* @return True if the transaction was actually yielded.
*
* @throws IllegalStateException if <code>throwIfNested</code> is true and
* there is no current transaction, there is a nested transaction in progress or
* if {@link #setTransactionSuccessful} has already been called for the current transaction.
+ * @throws SQLiteException if an error occurs.
+ * @throws OperationCanceledException if the operation was canceled.
*
* @see #beginTransaction
* @see #endTransaction
*/
- public boolean yieldTransaction(long sleepAfterYieldDelayMillis, boolean throwIfUnsafe) {
+ public boolean yieldTransaction(long sleepAfterYieldDelayMillis, boolean throwIfUnsafe,
+ CancellationSignal cancellationSignal) {
if (throwIfUnsafe) {
throwIfNoTransaction();
throwIfTransactionMarkedSuccessful();
@@ -493,10 +517,16 @@
return false;
}
- return yieldTransactionUnchecked(sleepAfterYieldDelayMillis); // might throw
+ return yieldTransactionUnchecked(sleepAfterYieldDelayMillis,
+ cancellationSignal); // might throw
}
- private boolean yieldTransactionUnchecked(long sleepAfterYieldDelayMillis) {
+ private boolean yieldTransactionUnchecked(long sleepAfterYieldDelayMillis,
+ CancellationSignal cancellationSignal) {
+ if (cancellationSignal != null) {
+ cancellationSignal.throwIfCanceled();
+ }
+
if (!mConnectionPool.shouldYieldConnection(mConnection, mConnectionFlags)) {
return false;
}
@@ -504,7 +534,7 @@
final int transactionMode = mTransactionStack.mMode;
final SQLiteTransactionListener listener = mTransactionStack.mListener;
final int connectionFlags = mConnectionFlags;
- endTransactionUnchecked(); // might throw
+ endTransactionUnchecked(cancellationSignal); // might throw
if (sleepAfterYieldDelayMillis > 0) {
try {
@@ -514,7 +544,8 @@
}
}
- beginTransactionUnchecked(transactionMode, listener, connectionFlags); // might throw
+ beginTransactionUnchecked(transactionMode, listener, connectionFlags,
+ cancellationSignal); // might throw
return true;
}
@@ -535,17 +566,24 @@
* @param sql The SQL statement to prepare.
* @param connectionFlags The connection flags to use if a connection must be
* acquired by this operation. Refer to {@link SQLiteConnectionPool}.
+ * @param cancellationSignal A signal to cancel the operation in progress, or null if none.
* @param outStatementInfo The {@link SQLiteStatementInfo} object to populate
* with information about the statement, or null if none.
*
* @throws SQLiteException if an error occurs, such as a syntax error.
+ * @throws OperationCanceledException if the operation was canceled.
*/
- public void prepare(String sql, int connectionFlags, SQLiteStatementInfo outStatementInfo) {
+ public void prepare(String sql, int connectionFlags, CancellationSignal cancellationSignal,
+ SQLiteStatementInfo outStatementInfo) {
if (sql == null) {
throw new IllegalArgumentException("sql must not be null.");
}
- acquireConnection(sql, connectionFlags); // might throw
+ if (cancellationSignal != null) {
+ cancellationSignal.throwIfCanceled();
+ }
+
+ acquireConnection(sql, connectionFlags, cancellationSignal); // might throw
try {
mConnection.prepare(sql, outStatementInfo); // might throw
} finally {
@@ -560,22 +598,25 @@
* @param bindArgs The arguments to bind, or null if none.
* @param connectionFlags The connection flags to use if a connection must be
* acquired by this operation. Refer to {@link SQLiteConnectionPool}.
+ * @param cancellationSignal A signal to cancel the operation in progress, or null if none.
*
* @throws SQLiteException if an error occurs, such as a syntax error
* or invalid number of bind arguments.
+ * @throws OperationCanceledException if the operation was canceled.
*/
- public void execute(String sql, Object[] bindArgs, int connectionFlags) {
+ public void execute(String sql, Object[] bindArgs, int connectionFlags,
+ CancellationSignal cancellationSignal) {
if (sql == null) {
throw new IllegalArgumentException("sql must not be null.");
}
- if (executeSpecial(sql, bindArgs, connectionFlags)) {
+ if (executeSpecial(sql, bindArgs, connectionFlags, cancellationSignal)) {
return;
}
- acquireConnection(sql, connectionFlags); // might throw
+ acquireConnection(sql, connectionFlags, cancellationSignal); // might throw
try {
- mConnection.execute(sql, bindArgs); // might throw
+ mConnection.execute(sql, bindArgs, cancellationSignal); // might throw
} finally {
releaseConnection(); // might throw
}
@@ -588,24 +629,27 @@
* @param bindArgs The arguments to bind, or null if none.
* @param connectionFlags The connection flags to use if a connection must be
* acquired by this operation. Refer to {@link SQLiteConnectionPool}.
+ * @param cancellationSignal A signal to cancel the operation in progress, or null if none.
* @return The value of the first column in the first row of the result set
* as a <code>long</code>, or zero if none.
*
* @throws SQLiteException if an error occurs, such as a syntax error
* or invalid number of bind arguments.
+ * @throws OperationCanceledException if the operation was canceled.
*/
- public long executeForLong(String sql, Object[] bindArgs, int connectionFlags) {
+ public long executeForLong(String sql, Object[] bindArgs, int connectionFlags,
+ CancellationSignal cancellationSignal) {
if (sql == null) {
throw new IllegalArgumentException("sql must not be null.");
}
- if (executeSpecial(sql, bindArgs, connectionFlags)) {
+ if (executeSpecial(sql, bindArgs, connectionFlags, cancellationSignal)) {
return 0;
}
- acquireConnection(sql, connectionFlags); // might throw
+ acquireConnection(sql, connectionFlags, cancellationSignal); // might throw
try {
- return mConnection.executeForLong(sql, bindArgs); // might throw
+ return mConnection.executeForLong(sql, bindArgs, cancellationSignal); // might throw
} finally {
releaseConnection(); // might throw
}
@@ -618,24 +662,27 @@
* @param bindArgs The arguments to bind, or null if none.
* @param connectionFlags The connection flags to use if a connection must be
* acquired by this operation. Refer to {@link SQLiteConnectionPool}.
+ * @param cancellationSignal A signal to cancel the operation in progress, or null if none.
* @return The value of the first column in the first row of the result set
* as a <code>String</code>, or null if none.
*
* @throws SQLiteException if an error occurs, such as a syntax error
* or invalid number of bind arguments.
+ * @throws OperationCanceledException if the operation was canceled.
*/
- public String executeForString(String sql, Object[] bindArgs, int connectionFlags) {
+ public String executeForString(String sql, Object[] bindArgs, int connectionFlags,
+ CancellationSignal cancellationSignal) {
if (sql == null) {
throw new IllegalArgumentException("sql must not be null.");
}
- if (executeSpecial(sql, bindArgs, connectionFlags)) {
+ if (executeSpecial(sql, bindArgs, connectionFlags, cancellationSignal)) {
return null;
}
- acquireConnection(sql, connectionFlags); // might throw
+ acquireConnection(sql, connectionFlags, cancellationSignal); // might throw
try {
- return mConnection.executeForString(sql, bindArgs); // might throw
+ return mConnection.executeForString(sql, bindArgs, cancellationSignal); // might throw
} finally {
releaseConnection(); // might throw
}
@@ -649,26 +696,29 @@
* @param bindArgs The arguments to bind, or null if none.
* @param connectionFlags The connection flags to use if a connection must be
* acquired by this operation. Refer to {@link SQLiteConnectionPool}.
+ * @param cancellationSignal A signal to cancel the operation in progress, or null if none.
* @return The file descriptor for a shared memory region that contains
* the value of the first column in the first row of the result set as a BLOB,
* or null if none.
*
* @throws SQLiteException if an error occurs, such as a syntax error
* or invalid number of bind arguments.
+ * @throws OperationCanceledException if the operation was canceled.
*/
public ParcelFileDescriptor executeForBlobFileDescriptor(String sql, Object[] bindArgs,
- int connectionFlags) {
+ int connectionFlags, CancellationSignal cancellationSignal) {
if (sql == null) {
throw new IllegalArgumentException("sql must not be null.");
}
- if (executeSpecial(sql, bindArgs, connectionFlags)) {
+ if (executeSpecial(sql, bindArgs, connectionFlags, cancellationSignal)) {
return null;
}
- acquireConnection(sql, connectionFlags); // might throw
+ acquireConnection(sql, connectionFlags, cancellationSignal); // might throw
try {
- return mConnection.executeForBlobFileDescriptor(sql, bindArgs); // might throw
+ return mConnection.executeForBlobFileDescriptor(sql, bindArgs,
+ cancellationSignal); // might throw
} finally {
releaseConnection(); // might throw
}
@@ -682,23 +732,27 @@
* @param bindArgs The arguments to bind, or null if none.
* @param connectionFlags The connection flags to use if a connection must be
* acquired by this operation. Refer to {@link SQLiteConnectionPool}.
+ * @param cancellationSignal A signal to cancel the operation in progress, or null if none.
* @return The number of rows that were changed.
*
* @throws SQLiteException if an error occurs, such as a syntax error
* or invalid number of bind arguments.
+ * @throws OperationCanceledException if the operation was canceled.
*/
- public int executeForChangedRowCount(String sql, Object[] bindArgs, int connectionFlags) {
+ public int executeForChangedRowCount(String sql, Object[] bindArgs, int connectionFlags,
+ CancellationSignal cancellationSignal) {
if (sql == null) {
throw new IllegalArgumentException("sql must not be null.");
}
- if (executeSpecial(sql, bindArgs, connectionFlags)) {
+ if (executeSpecial(sql, bindArgs, connectionFlags, cancellationSignal)) {
return 0;
}
- acquireConnection(sql, connectionFlags); // might throw
+ acquireConnection(sql, connectionFlags, cancellationSignal); // might throw
try {
- return mConnection.executeForChangedRowCount(sql, bindArgs); // might throw
+ return mConnection.executeForChangedRowCount(sql, bindArgs,
+ cancellationSignal); // might throw
} finally {
releaseConnection(); // might throw
}
@@ -712,23 +766,27 @@
* @param bindArgs The arguments to bind, or null if none.
* @param connectionFlags The connection flags to use if a connection must be
* acquired by this operation. Refer to {@link SQLiteConnectionPool}.
+ * @param cancellationSignal A signal to cancel the operation in progress, or null if none.
* @return The row id of the last row that was inserted, or 0 if none.
*
* @throws SQLiteException if an error occurs, such as a syntax error
* or invalid number of bind arguments.
+ * @throws OperationCanceledException if the operation was canceled.
*/
- public long executeForLastInsertedRowId(String sql, Object[] bindArgs, int connectionFlags) {
+ public long executeForLastInsertedRowId(String sql, Object[] bindArgs, int connectionFlags,
+ CancellationSignal cancellationSignal) {
if (sql == null) {
throw new IllegalArgumentException("sql must not be null.");
}
- if (executeSpecial(sql, bindArgs, connectionFlags)) {
+ if (executeSpecial(sql, bindArgs, connectionFlags, cancellationSignal)) {
return 0;
}
- acquireConnection(sql, connectionFlags); // might throw
+ acquireConnection(sql, connectionFlags, cancellationSignal); // might throw
try {
- return mConnection.executeForLastInsertedRowId(sql, bindArgs); // might throw
+ return mConnection.executeForLastInsertedRowId(sql, bindArgs,
+ cancellationSignal); // might throw
} finally {
releaseConnection(); // might throw
}
@@ -750,15 +808,17 @@
* regagless of whether they fit in the window.
* @param connectionFlags The connection flags to use if a connection must be
* acquired by this operation. Refer to {@link SQLiteConnectionPool}.
+ * @param cancellationSignal A signal to cancel the operation in progress, or null if none.
* @return The number of rows that were counted during query execution. Might
* not be all rows in the result set unless <code>countAllRows</code> is true.
*
* @throws SQLiteException if an error occurs, such as a syntax error
* or invalid number of bind arguments.
+ * @throws OperationCanceledException if the operation was canceled.
*/
public int executeForCursorWindow(String sql, Object[] bindArgs,
CursorWindow window, int startPos, int requiredPos, boolean countAllRows,
- int connectionFlags) {
+ int connectionFlags, CancellationSignal cancellationSignal) {
if (sql == null) {
throw new IllegalArgumentException("sql must not be null.");
}
@@ -766,15 +826,16 @@
throw new IllegalArgumentException("window must not be null.");
}
- if (executeSpecial(sql, bindArgs, connectionFlags)) {
+ if (executeSpecial(sql, bindArgs, connectionFlags, cancellationSignal)) {
window.clear();
return 0;
}
- acquireConnection(sql, connectionFlags); // might throw
+ acquireConnection(sql, connectionFlags, cancellationSignal); // might throw
try {
return mConnection.executeForCursorWindow(sql, bindArgs,
- window, startPos, requiredPos, countAllRows); // might throw
+ window, startPos, requiredPos, countAllRows,
+ cancellationSignal); // might throw
} finally {
releaseConnection(); // might throw
}
@@ -793,35 +854,45 @@
* @param bindArgs The arguments to bind, or null if none.
* @param connectionFlags The connection flags to use if a connection must be
* acquired by this operation. Refer to {@link SQLiteConnectionPool}.
+ * @param cancellationSignal A signal to cancel the operation in progress, or null if none.
* @return True if the statement was of a special form that was handled here,
* false otherwise.
*
* @throws SQLiteException if an error occurs, such as a syntax error
* or invalid number of bind arguments.
+ * @throws OperationCanceledException if the operation was canceled.
*/
- private boolean executeSpecial(String sql, Object[] bindArgs, int connectionFlags) {
+ private boolean executeSpecial(String sql, Object[] bindArgs, int connectionFlags,
+ CancellationSignal cancellationSignal) {
+ if (cancellationSignal != null) {
+ cancellationSignal.throwIfCanceled();
+ }
+
final int type = DatabaseUtils.getSqlStatementType(sql);
switch (type) {
case DatabaseUtils.STATEMENT_BEGIN:
- beginTransaction(TRANSACTION_MODE_EXCLUSIVE, null, connectionFlags);
+ beginTransaction(TRANSACTION_MODE_EXCLUSIVE, null, connectionFlags,
+ cancellationSignal);
return true;
case DatabaseUtils.STATEMENT_COMMIT:
setTransactionSuccessful();
- endTransaction();
+ endTransaction(cancellationSignal);
return true;
case DatabaseUtils.STATEMENT_ABORT:
- endTransaction();
+ endTransaction(cancellationSignal);
return true;
}
return false;
}
- private void acquireConnection(String sql, int connectionFlags) {
+ private void acquireConnection(String sql, int connectionFlags,
+ CancellationSignal cancellationSignal) {
if (mConnection == null) {
assert mConnectionUseCount == 0;
- mConnection = mConnectionPool.acquireConnection(sql, connectionFlags); // might throw
+ mConnection = mConnectionPool.acquireConnection(sql, connectionFlags,
+ cancellationSignal); // might throw
mConnectionFlags = connectionFlags;
}
mConnectionUseCount += 1;
diff --git a/core/java/android/database/sqlite/SQLiteStatement.java b/core/java/android/database/sqlite/SQLiteStatement.java
index 4e20da0..b1092d76 100644
--- a/core/java/android/database/sqlite/SQLiteStatement.java
+++ b/core/java/android/database/sqlite/SQLiteStatement.java
@@ -28,7 +28,7 @@
*/
public final class SQLiteStatement extends SQLiteProgram {
SQLiteStatement(SQLiteDatabase db, String sql, Object[] bindArgs) {
- super(db, sql, bindArgs);
+ super(db, sql, bindArgs, null);
}
/**
@@ -41,7 +41,7 @@
public void execute() {
acquireReference();
try {
- getSession().execute(getSql(), getBindArgs(), getConnectionFlags());
+ getSession().execute(getSql(), getBindArgs(), getConnectionFlags(), null);
} catch (SQLiteDatabaseCorruptException ex) {
onCorruption();
throw ex;
@@ -62,7 +62,7 @@
acquireReference();
try {
return getSession().executeForChangedRowCount(
- getSql(), getBindArgs(), getConnectionFlags());
+ getSql(), getBindArgs(), getConnectionFlags(), null);
} catch (SQLiteDatabaseCorruptException ex) {
onCorruption();
throw ex;
@@ -84,7 +84,7 @@
acquireReference();
try {
return getSession().executeForLastInsertedRowId(
- getSql(), getBindArgs(), getConnectionFlags());
+ getSql(), getBindArgs(), getConnectionFlags(), null);
} catch (SQLiteDatabaseCorruptException ex) {
onCorruption();
throw ex;
@@ -105,7 +105,7 @@
acquireReference();
try {
return getSession().executeForLong(
- getSql(), getBindArgs(), getConnectionFlags());
+ getSql(), getBindArgs(), getConnectionFlags(), null);
} catch (SQLiteDatabaseCorruptException ex) {
onCorruption();
throw ex;
@@ -126,7 +126,7 @@
acquireReference();
try {
return getSession().executeForString(
- getSql(), getBindArgs(), getConnectionFlags());
+ getSql(), getBindArgs(), getConnectionFlags(), null);
} catch (SQLiteDatabaseCorruptException ex) {
onCorruption();
throw ex;
@@ -147,7 +147,7 @@
acquireReference();
try {
return getSession().executeForBlobFileDescriptor(
- getSql(), getBindArgs(), getConnectionFlags());
+ getSql(), getBindArgs(), getConnectionFlags(), null);
} catch (SQLiteDatabaseCorruptException ex) {
onCorruption();
throw ex;
diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java
index a569317..2eef8f4 100644
--- a/core/java/android/net/ConnectivityManager.java
+++ b/core/java/android/net/ConnectivityManager.java
@@ -142,8 +142,19 @@
* If an application uses the network in the background, it should listen
* for this broadcast and stop using the background data if the value is
* {@code false}.
+ * <p>
+ *
+ * @deprecated As of {@link VERSION_CODES#ICE_CREAM_SANDWICH}, availability
+ * of background data depends on several combined factors, and
+ * this broadcast is no longer sent. Instead, when background
+ * data is unavailable, {@link #getActiveNetworkInfo()} will now
+ * appear disconnected. During first boot after a platform
+ * upgrade, this broadcast will be sent once if
+ * {@link #getBackgroundDataSetting()} was {@code false} before
+ * the upgrade.
*/
@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+ @Deprecated
public static final String ACTION_BACKGROUND_DATA_SETTING_CHANGED =
"android.net.conn.BACKGROUND_DATA_SETTING_CHANGED";
diff --git a/core/java/android/net/INetworkPolicyManager.aidl b/core/java/android/net/INetworkPolicyManager.aidl
index 633c38e0..442535a 100644
--- a/core/java/android/net/INetworkPolicyManager.aidl
+++ b/core/java/android/net/INetworkPolicyManager.aidl
@@ -43,7 +43,7 @@
NetworkPolicy[] getNetworkPolicies();
/** Snooze limit on policy matching given template. */
- void snoozePolicy(in NetworkTemplate template);
+ void snoozeLimit(in NetworkTemplate template);
/** Control if background data is restricted system-wide. */
void setRestrictBackground(boolean restrictBackground);
diff --git a/core/java/android/net/NetworkPolicy.java b/core/java/android/net/NetworkPolicy.java
index d9ea700..04cf1a3 100644
--- a/core/java/android/net/NetworkPolicy.java
+++ b/core/java/android/net/NetworkPolicy.java
@@ -38,18 +38,25 @@
public int cycleDay;
public long warningBytes;
public long limitBytes;
- public long lastSnooze;
+ public long lastWarningSnooze;
+ public long lastLimitSnooze;
public boolean metered;
private static final long DEFAULT_MTU = 1500;
- public NetworkPolicy(NetworkTemplate template, int cycleDay, long warningBytes, long limitBytes,
- long lastSnooze, boolean metered) {
+ public NetworkPolicy(NetworkTemplate template, int cycleDay, long warningBytes,
+ long limitBytes, boolean metered) {
+ this(template, cycleDay, warningBytes, limitBytes, SNOOZE_NEVER, SNOOZE_NEVER, metered);
+ }
+
+ public NetworkPolicy(NetworkTemplate template, int cycleDay, long warningBytes,
+ long limitBytes, long lastWarningSnooze, long lastLimitSnooze, boolean metered) {
this.template = checkNotNull(template, "missing NetworkTemplate");
this.cycleDay = cycleDay;
this.warningBytes = warningBytes;
this.limitBytes = limitBytes;
- this.lastSnooze = lastSnooze;
+ this.lastWarningSnooze = lastWarningSnooze;
+ this.lastLimitSnooze = lastLimitSnooze;
this.metered = metered;
}
@@ -58,7 +65,8 @@
cycleDay = in.readInt();
warningBytes = in.readLong();
limitBytes = in.readLong();
- lastSnooze = in.readLong();
+ lastWarningSnooze = in.readLong();
+ lastLimitSnooze = in.readLong();
metered = in.readInt() != 0;
}
@@ -68,7 +76,8 @@
dest.writeInt(cycleDay);
dest.writeLong(warningBytes);
dest.writeLong(limitBytes);
- dest.writeLong(lastSnooze);
+ dest.writeLong(lastWarningSnooze);
+ dest.writeLong(lastLimitSnooze);
dest.writeInt(metered ? 1 : 0);
}
@@ -78,6 +87,13 @@
}
/**
+ * Test if given measurement is over {@link #warningBytes}.
+ */
+ public boolean isOverWarning(long totalBytes) {
+ return warningBytes != WARNING_DISABLED && totalBytes >= warningBytes;
+ }
+
+ /**
* Test if given measurement is near enough to {@link #limitBytes} to be
* considered over-limit.
*/
@@ -88,6 +104,14 @@
return limitBytes != LIMIT_DISABLED && totalBytes >= limitBytes;
}
+ /**
+ * Clear any existing snooze values, setting to {@link #SNOOZE_NEVER}.
+ */
+ public void clearSnooze() {
+ lastWarningSnooze = SNOOZE_NEVER;
+ lastLimitSnooze = SNOOZE_NEVER;
+ }
+
/** {@inheritDoc} */
public int compareTo(NetworkPolicy another) {
if (another == null || another.limitBytes == LIMIT_DISABLED) {
@@ -103,7 +127,8 @@
@Override
public int hashCode() {
- return Objects.hashCode(template, cycleDay, warningBytes, limitBytes, lastSnooze, metered);
+ return Objects.hashCode(template, cycleDay, warningBytes, limitBytes, lastWarningSnooze,
+ lastLimitSnooze, metered);
}
@Override
@@ -111,8 +136,10 @@
if (obj instanceof NetworkPolicy) {
final NetworkPolicy other = (NetworkPolicy) obj;
return cycleDay == other.cycleDay && warningBytes == other.warningBytes
- && limitBytes == other.limitBytes && lastSnooze == other.lastSnooze
- && metered == other.metered && Objects.equal(template, other.template);
+ && limitBytes == other.limitBytes
+ && lastWarningSnooze == other.lastWarningSnooze
+ && lastLimitSnooze == other.lastLimitSnooze && metered == other.metered
+ && Objects.equal(template, other.template);
}
return false;
}
@@ -120,8 +147,9 @@
@Override
public String toString() {
return "NetworkPolicy[" + template + "]: cycleDay=" + cycleDay + ", warningBytes="
- + warningBytes + ", limitBytes=" + limitBytes + ", lastSnooze=" + lastSnooze
- + ", metered=" + metered;
+ + warningBytes + ", limitBytes=" + limitBytes + ", lastWarningSnooze="
+ + lastWarningSnooze + ", lastLimitSnooze=" + lastLimitSnooze + ", metered="
+ + metered;
}
public static final Creator<NetworkPolicy> CREATOR = new Creator<NetworkPolicy>() {
diff --git a/core/java/android/net/NetworkStats.java b/core/java/android/net/NetworkStats.java
index e8f60b4..7a1ef66 100644
--- a/core/java/android/net/NetworkStats.java
+++ b/core/java/android/net/NetworkStats.java
@@ -102,6 +102,15 @@
this.operations = operations;
}
+ public boolean isNegative() {
+ return rxBytes < 0 || rxPackets < 0 || txBytes < 0 || txPackets < 0 || operations < 0;
+ }
+
+ public boolean isEmpty() {
+ return rxBytes == 0 && rxPackets == 0 && txBytes == 0 && txPackets == 0
+ && operations == 0;
+ }
+
@Override
public String toString() {
final StringBuilder builder = new StringBuilder();
@@ -343,6 +352,7 @@
* on matching {@link #uid} and {@link #tag} rows. Ignores {@link #iface},
* since operation counts are at data layer.
*/
+ @Deprecated
public void spliceOperationsFrom(NetworkStats stats) {
for (int i = 0; i < size; i++) {
final int j = stats.findIndex(IFACE_ALL, uid[i], set[i], tag[i]);
@@ -397,7 +407,7 @@
* Return total of all fields represented by this snapshot object.
*/
public Entry getTotal(Entry recycle) {
- return getTotal(recycle, null, UID_ALL);
+ return getTotal(recycle, null, UID_ALL, false);
}
/**
@@ -405,7 +415,7 @@
* the requested {@link #uid}.
*/
public Entry getTotal(Entry recycle, int limitUid) {
- return getTotal(recycle, null, limitUid);
+ return getTotal(recycle, null, limitUid, false);
}
/**
@@ -413,7 +423,11 @@
* the requested {@link #iface}.
*/
public Entry getTotal(Entry recycle, HashSet<String> limitIface) {
- return getTotal(recycle, limitIface, UID_ALL);
+ return getTotal(recycle, limitIface, UID_ALL, false);
+ }
+
+ public Entry getTotalIncludingTags(Entry recycle) {
+ return getTotal(recycle, null, UID_ALL, true);
}
/**
@@ -423,7 +437,8 @@
* @param limitIface Set of {@link #iface} to include in total; or {@code
* null} to include all ifaces.
*/
- private Entry getTotal(Entry recycle, HashSet<String> limitIface, int limitUid) {
+ private Entry getTotal(
+ Entry recycle, HashSet<String> limitIface, int limitUid, boolean includeTags) {
final Entry entry = recycle != null ? recycle : new Entry();
entry.iface = IFACE_ALL;
@@ -442,7 +457,7 @@
if (matchesUid && matchesIface) {
// skip specific tags, since already counted in TAG_NONE
- if (tag[i] != TAG_NONE) continue;
+ if (tag[i] != TAG_NONE && !includeTags) continue;
entry.rxBytes += rxBytes[i];
entry.rxPackets += rxPackets[i];
@@ -460,7 +475,7 @@
* time, and that none of them have disappeared.
*/
public NetworkStats subtract(NetworkStats right) {
- return subtract(this, right, null);
+ return subtract(this, right, null, null);
}
/**
@@ -471,12 +486,12 @@
* If counters have rolled backwards, they are clamped to {@code 0} and
* reported to the given {@link NonMonotonicObserver}.
*/
- public static NetworkStats subtract(
- NetworkStats left, NetworkStats right, NonMonotonicObserver observer) {
+ public static <C> NetworkStats subtract(
+ NetworkStats left, NetworkStats right, NonMonotonicObserver<C> observer, C cookie) {
long deltaRealtime = left.elapsedRealtime - right.elapsedRealtime;
if (deltaRealtime < 0) {
if (observer != null) {
- observer.foundNonMonotonic(left, -1, right, -1);
+ observer.foundNonMonotonic(left, -1, right, -1, cookie);
}
deltaRealtime = 0;
}
@@ -510,7 +525,7 @@
if (entry.rxBytes < 0 || entry.rxPackets < 0 || entry.txBytes < 0
|| entry.txPackets < 0 || entry.operations < 0) {
if (observer != null) {
- observer.foundNonMonotonic(left, i, right, j);
+ observer.foundNonMonotonic(left, i, right, j, cookie);
}
entry.rxBytes = Math.max(entry.rxBytes, 0);
entry.rxPackets = Math.max(entry.rxPackets, 0);
@@ -663,8 +678,8 @@
}
};
- public interface NonMonotonicObserver {
+ public interface NonMonotonicObserver<C> {
public void foundNonMonotonic(
- NetworkStats left, int leftIndex, NetworkStats right, int rightIndex);
+ NetworkStats left, int leftIndex, NetworkStats right, int rightIndex, C cookie);
}
}
diff --git a/core/java/android/net/NetworkStatsHistory.java b/core/java/android/net/NetworkStatsHistory.java
index 8c01331..faf8a3f 100644
--- a/core/java/android/net/NetworkStatsHistory.java
+++ b/core/java/android/net/NetworkStatsHistory.java
@@ -26,16 +26,18 @@
import static android.net.NetworkStatsHistory.Entry.UNKNOWN;
import static android.net.NetworkStatsHistory.ParcelUtils.readLongArray;
import static android.net.NetworkStatsHistory.ParcelUtils.writeLongArray;
+import static com.android.internal.util.ArrayUtils.total;
import android.os.Parcel;
import android.os.Parcelable;
import android.util.MathUtils;
+import com.android.internal.util.IndentingPrintWriter;
+
import java.io.CharArrayWriter;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
-import java.io.PrintWriter;
import java.net.ProtocolException;
import java.util.Arrays;
import java.util.Random;
@@ -74,6 +76,7 @@
private long[] txBytes;
private long[] txPackets;
private long[] operations;
+ private long totalBytes;
public static class Entry {
public static final long UNKNOWN = -1;
@@ -106,6 +109,12 @@
if ((fields & FIELD_TX_PACKETS) != 0) txPackets = new long[initialSize];
if ((fields & FIELD_OPERATIONS) != 0) operations = new long[initialSize];
bucketCount = 0;
+ totalBytes = 0;
+ }
+
+ public NetworkStatsHistory(NetworkStatsHistory existing, long bucketDuration) {
+ this(bucketDuration, existing.estimateResizeBuckets(bucketDuration));
+ recordEntireHistory(existing);
}
public NetworkStatsHistory(Parcel in) {
@@ -118,6 +127,7 @@
txPackets = readLongArray(in);
operations = readLongArray(in);
bucketCount = bucketStart.length;
+ totalBytes = in.readLong();
}
/** {@inheritDoc} */
@@ -130,6 +140,7 @@
writeLongArray(out, txBytes, bucketCount);
writeLongArray(out, txPackets, bucketCount);
writeLongArray(out, operations, bucketCount);
+ out.writeLong(totalBytes);
}
public NetworkStatsHistory(DataInputStream in) throws IOException {
@@ -144,6 +155,7 @@
txPackets = new long[bucketStart.length];
operations = new long[bucketStart.length];
bucketCount = bucketStart.length;
+ totalBytes = total(rxBytes) + total(txBytes);
break;
}
case VERSION_ADD_PACKETS:
@@ -158,6 +170,7 @@
txPackets = readVarLongArray(in);
operations = readVarLongArray(in);
bucketCount = bucketStart.length;
+ totalBytes = total(rxBytes) + total(txBytes);
break;
}
default: {
@@ -208,6 +221,13 @@
}
/**
+ * Return total bytes represented by this history.
+ */
+ public long getTotalBytes() {
+ return totalBytes;
+ }
+
+ /**
* Return index of bucket that contains or is immediately before the
* requested time.
*/
@@ -266,13 +286,16 @@
* distribute across internal buckets, creating new buckets as needed.
*/
public void recordData(long start, long end, NetworkStats.Entry entry) {
- if (entry.rxBytes < 0 || entry.rxPackets < 0 || entry.txBytes < 0 || entry.txPackets < 0
- || entry.operations < 0) {
+ long rxBytes = entry.rxBytes;
+ long rxPackets = entry.rxPackets;
+ long txBytes = entry.txBytes;
+ long txPackets = entry.txPackets;
+ long operations = entry.operations;
+
+ if (entry.isNegative()) {
throw new IllegalArgumentException("tried recording negative data");
}
- if (entry.rxBytes == 0 && entry.rxPackets == 0 && entry.txBytes == 0 && entry.txPackets == 0
- && entry.operations == 0) {
- // nothing to record; skip
+ if (entry.isEmpty()) {
return;
}
@@ -295,21 +318,23 @@
if (overlap <= 0) continue;
// integer math each time is faster than floating point
- final long fracRxBytes = entry.rxBytes * overlap / duration;
- final long fracRxPackets = entry.rxPackets * overlap / duration;
- final long fracTxBytes = entry.txBytes * overlap / duration;
- final long fracTxPackets = entry.txPackets * overlap / duration;
- final long fracOperations = entry.operations * overlap / duration;
+ final long fracRxBytes = rxBytes * overlap / duration;
+ final long fracRxPackets = rxPackets * overlap / duration;
+ final long fracTxBytes = txBytes * overlap / duration;
+ final long fracTxPackets = txPackets * overlap / duration;
+ final long fracOperations = operations * overlap / duration;
addLong(activeTime, i, overlap);
- addLong(rxBytes, i, fracRxBytes); entry.rxBytes -= fracRxBytes;
- addLong(rxPackets, i, fracRxPackets); entry.rxPackets -= fracRxPackets;
- addLong(txBytes, i, fracTxBytes); entry.txBytes -= fracTxBytes;
- addLong(txPackets, i, fracTxPackets); entry.txPackets -= fracTxPackets;
- addLong(operations, i, fracOperations); entry.operations -= fracOperations;
+ addLong(this.rxBytes, i, fracRxBytes); rxBytes -= fracRxBytes;
+ addLong(this.rxPackets, i, fracRxPackets); rxPackets -= fracRxPackets;
+ addLong(this.txBytes, i, fracTxBytes); txBytes -= fracTxBytes;
+ addLong(this.txPackets, i, fracTxPackets); txPackets -= fracTxPackets;
+ addLong(this.operations, i, fracOperations); operations -= fracOperations;
duration -= overlap;
}
+
+ totalBytes += entry.rxBytes + entry.txBytes;
}
/**
@@ -394,6 +419,7 @@
/**
* Remove buckets older than requested cutoff.
*/
+ @Deprecated
public void removeBucketsBefore(long cutoff) {
int i;
for (i = 0; i < bucketCount; i++) {
@@ -415,6 +441,8 @@
if (txPackets != null) txPackets = Arrays.copyOfRange(txPackets, i, length);
if (operations != null) operations = Arrays.copyOfRange(operations, i, length);
bucketCount -= i;
+
+ // TODO: subtract removed values from totalBytes
}
}
@@ -527,19 +555,17 @@
return (long) (start + (r.nextFloat() * (end - start)));
}
- public void dump(String prefix, PrintWriter pw, boolean fullHistory) {
- pw.print(prefix);
+ public void dump(IndentingPrintWriter pw, boolean fullHistory) {
pw.print("NetworkStatsHistory: bucketDuration="); pw.println(bucketDuration);
+ pw.increaseIndent();
final int start = fullHistory ? 0 : Math.max(0, bucketCount - 32);
if (start > 0) {
- pw.print(prefix);
- pw.print(" (omitting "); pw.print(start); pw.println(" buckets)");
+ pw.print("(omitting "); pw.print(start); pw.println(" buckets)");
}
for (int i = start; i < bucketCount; i++) {
- pw.print(prefix);
- pw.print(" bucketStart="); pw.print(bucketStart[i]);
+ pw.print("bucketStart="); pw.print(bucketStart[i]);
if (activeTime != null) { pw.print(" activeTime="); pw.print(activeTime[i]); }
if (rxBytes != null) { pw.print(" rxBytes="); pw.print(rxBytes[i]); }
if (rxPackets != null) { pw.print(" rxPackets="); pw.print(rxPackets[i]); }
@@ -548,12 +574,14 @@
if (operations != null) { pw.print(" operations="); pw.print(operations[i]); }
pw.println();
}
+
+ pw.decreaseIndent();
}
@Override
public String toString() {
final CharArrayWriter writer = new CharArrayWriter();
- dump("", new PrintWriter(writer), false);
+ dump(new IndentingPrintWriter(writer, " "), false);
return writer.toString();
}
@@ -579,6 +607,10 @@
if (array != null) array[i] += value;
}
+ public int estimateResizeBuckets(long newBucketDuration) {
+ return (int) (size() * getBucketDuration() / newBucketDuration);
+ }
+
/**
* Utility methods for interacting with {@link DataInputStream} and
* {@link DataOutputStream}, mostly dealing with writing partial arrays.
diff --git a/core/java/android/net/NetworkTemplate.java b/core/java/android/net/NetworkTemplate.java
index 418b82f..8ebfd8d 100644
--- a/core/java/android/net/NetworkTemplate.java
+++ b/core/java/android/net/NetworkTemplate.java
@@ -18,6 +18,7 @@
import static android.net.ConnectivityManager.TYPE_ETHERNET;
import static android.net.ConnectivityManager.TYPE_WIFI;
+import static android.net.ConnectivityManager.TYPE_WIFI_P2P;
import static android.net.ConnectivityManager.TYPE_WIMAX;
import static android.net.NetworkIdentity.scrubSubscriberId;
import static android.telephony.TelephonyManager.NETWORK_CLASS_2_G;
@@ -231,10 +232,13 @@
* Check if matches Wi-Fi network template.
*/
private boolean matchesWifi(NetworkIdentity ident) {
- if (ident.mType == TYPE_WIFI) {
- return true;
+ switch (ident.mType) {
+ case TYPE_WIFI:
+ case TYPE_WIFI_P2P:
+ return true;
+ default:
+ return false;
}
- return false;
}
/**
diff --git a/core/java/android/net/TrafficStats.java b/core/java/android/net/TrafficStats.java
index 8bdb669..dfdea38 100644
--- a/core/java/android/net/TrafficStats.java
+++ b/core/java/android/net/TrafficStats.java
@@ -195,7 +195,7 @@
// subtract starting values and return delta
final NetworkStats profilingStop = getDataLayerSnapshotForUid(context);
final NetworkStats profilingDelta = NetworkStats.subtract(
- profilingStop, sActiveProfilingStart, null);
+ profilingStop, sActiveProfilingStart, null, null);
sActiveProfilingStart = null;
return profilingDelta;
}
diff --git a/core/java/android/net/Uri.java b/core/java/android/net/Uri.java
index 0fb49bc..defe7aa 100644
--- a/core/java/android/net/Uri.java
+++ b/core/java/android/net/Uri.java
@@ -28,6 +28,7 @@
import java.util.Collections;
import java.util.LinkedHashSet;
import java.util.List;
+import java.util.Locale;
import java.util.RandomAccess;
import java.util.Set;
import libcore.net.UriCodec;
@@ -1716,6 +1717,38 @@
return (!"false".equals(flag) && !"0".equals(flag));
}
+ /**
+ * Return a normalized representation of this Uri.
+ *
+ * <p>A normalized Uri has a lowercase scheme component.
+ * This aligns the Uri with Android best practices for
+ * intent filtering.
+ *
+ * <p>For example, "HTTP://www.android.com" becomes
+ * "http://www.android.com"
+ *
+ * <p>All URIs received from outside Android (such as user input,
+ * or external sources like Bluetooth, NFC, or the Internet) should
+ * be normalized before they are used to create an Intent.
+ *
+ * <p class="note">This method does <em>not</em> validate bad URI's,
+ * or 'fix' poorly formatted URI's - so do not use it for input validation.
+ * A Uri will always be returned, even if the Uri is badly formatted to
+ * begin with and a scheme component cannot be found.
+ *
+ * @return normalized Uri (never null)
+ * @see {@link android.content.Intent#setData}
+ * @see {@link #setNormalizedData}
+ */
+ public Uri normalize() {
+ String scheme = getScheme();
+ if (scheme == null) return this; // give up
+ String lowerScheme = scheme.toLowerCase(Locale.US);
+ if (scheme.equals(lowerScheme)) return this; // no change
+
+ return buildUpon().scheme(lowerScheme).build();
+ }
+
/** Identifies a null parcelled Uri. */
private static final int NULL_TYPE_ID = 0;
diff --git a/core/java/android/nfc/INfcAdapter.aidl b/core/java/android/nfc/INfcAdapter.aidl
index 0b93ad0..61bc324 100644
--- a/core/java/android/nfc/INfcAdapter.aidl
+++ b/core/java/android/nfc/INfcAdapter.aidl
@@ -17,7 +17,6 @@
package android.nfc;
import android.app.PendingIntent;
-import android.content.ComponentName;
import android.content.IntentFilter;
import android.nfc.NdefMessage;
import android.nfc.Tag;
@@ -44,4 +43,6 @@
void setForegroundDispatch(in PendingIntent intent,
in IntentFilter[] filters, in TechListParcel techLists);
void setForegroundNdefPush(in NdefMessage msg, in INdefPushCallback callback);
+
+ void dispatch(in Tag tag);
}
diff --git a/core/java/android/nfc/NdefMessage.java b/core/java/android/nfc/NdefMessage.java
index 38bc16d..5df9272 100644
--- a/core/java/android/nfc/NdefMessage.java
+++ b/core/java/android/nfc/NdefMessage.java
@@ -92,9 +92,7 @@
* @throws FormatException if the data cannot be parsed
*/
public NdefMessage(byte[] data) throws FormatException {
- if (data == null) {
- throw new NullPointerException("null data");
- }
+ if (data == null) throw new NullPointerException("data is null");
ByteBuffer buffer = ByteBuffer.wrap(data);
mRecords = NdefRecord.parse(buffer, false);
@@ -112,9 +110,8 @@
*/
public NdefMessage(NdefRecord record, NdefRecord ... records) {
// validate
- if (record == null) {
- throw new NullPointerException("record cannot be null");
- }
+ if (record == null) throw new NullPointerException("record cannot be null");
+
for (NdefRecord r : records) {
if (r == null) {
throw new NullPointerException("record cannot be null");
@@ -147,7 +144,12 @@
/**
* Get the NDEF Records inside this NDEF Message.<p>
- * An NDEF Message always has one or more NDEF Records.
+ * An {@link NdefMessage} always has one or more NDEF Records: so the
+ * following code to retrieve the first record is always safe
+ * (no need to check for null or array length >= 1):
+ * <pre>
+ * NdefRecord firstRecord = ndefMessage.getRecords()[0];
+ * </pre>
*
* @return array of one or more NDEF records.
*/
@@ -156,7 +158,28 @@
}
/**
- * Return this NDEF MEssage as raw bytes.<p>
+ * Return the length of this NDEF Message if it is written to a byte array
+ * with {@link #toByteArray}.<p>
+ * An NDEF Message can be formatted to bytes in different ways
+ * depending on chunking, SR, and ID flags, so the length returned
+ * by this method may not be equal to the length of the original
+ * byte array used to construct this NDEF Message. However it will
+ * always be equal to the length of the byte array produced by
+ * {@link #toByteArray}.
+ *
+ * @return length of this NDEF Message when written to bytes with {@link #toByteArray}
+ * @see #toByteArray
+ */
+ public int getByteArrayLength() {
+ int length = 0;
+ for (NdefRecord r : mRecords) {
+ length += r.getByteLength();
+ }
+ return length;
+ }
+
+ /**
+ * Return this NDEF Message as raw bytes.<p>
* The NDEF Message is formatted as per the NDEF 1.0 specification,
* and the byte array is suitable for network transmission or storage
* in an NFC Forum NDEF compatible tag.<p>
@@ -164,13 +187,10 @@
* short record (SR) format and omit the identifier field when possible.
*
* @return NDEF Message in binary format
+ * @see getByteArrayLength
*/
public byte[] toByteArray() {
- int length = 0;
- for (NdefRecord r : mRecords) {
- length += r.getByteLength();
- }
-
+ int length = getByteArrayLength();
ByteBuffer buffer = ByteBuffer.allocate(length);
for (int i=0; i<mRecords.length; i++) {
diff --git a/core/java/android/nfc/NdefRecord.java b/core/java/android/nfc/NdefRecord.java
index b4c488b..0e9e8f4 100644
--- a/core/java/android/nfc/NdefRecord.java
+++ b/core/java/android/nfc/NdefRecord.java
@@ -16,6 +16,7 @@
package android.nfc;
+import android.content.Intent;
import android.net.Uri;
import android.os.Parcel;
import android.os.Parcelable;
@@ -25,6 +26,7 @@
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
+import java.util.Locale;
/**
* Represents an immutable NDEF Record.
@@ -305,9 +307,9 @@
* @return Android application NDEF record
*/
public static NdefRecord createApplicationRecord(String packageName) {
- if (packageName.length() == 0) {
- throw new IllegalArgumentException("empty package name");
- }
+ if (packageName == null) throw new NullPointerException("packageName is null");
+ if (packageName.length() == 0) throw new IllegalArgumentException("packageName is empty");
+
return new NdefRecord(TNF_EXTERNAL_TYPE, RTD_ANDROID_APP, null,
packageName.getBytes(Charsets.UTF_8));
}
@@ -318,32 +320,27 @@
* Uses the well known URI type representation: {@link #TNF_WELL_KNOWN}
* and {@link #RTD_URI}. This is the most efficient encoding
* of a URI into NDEF.<p>
+ * The uri parameter will be normalized with
+ * {@link Uri#normalize} to set the scheme to lower case to
+ * follow Android best practices for intent filtering.
+ * However the unchecked exception
+ * {@link IllegalArgumentException} may be thrown if the uri
+ * parameter has serious problems, for example if it is empty, so always
+ * catch this exception if you are passing user-generated data into this
+ * method.<p>
+ *
* Reference specification: NFCForum-TS-RTD_URI_1.0
*
* @param uri URI to encode.
* @return an NDEF Record containing the URI
- * @throws IllegalArugmentException if a valid record cannot be created
+ * @throws IllegalArugmentException if the uri is empty or invalid
*/
public static NdefRecord createUri(Uri uri) {
- return createUri(uri.toString());
- }
+ if (uri == null) throw new NullPointerException("uri is null");
- /**
- * Create a new NDEF Record containing a URI.<p>
- * Use this method to encode a URI (or URL) into an NDEF Record.<p>
- * Uses the well known URI type representation: {@link #TNF_WELL_KNOWN}
- * and {@link #RTD_URI}. This is the most efficient encoding
- * of a URI into NDEF.<p>
- * Reference specification: NFCForum-TS-RTD_URI_1.0
- *
- * @param uriString string URI to encode.
- * @return an NDEF Record containing the URI
- * @throws IllegalArugmentException if a valid record cannot be created
- */
- public static NdefRecord createUri(String uriString) {
- if (uriString.length() == 0) {
- throw new IllegalArgumentException("empty uriString");
- }
+ uri = uri.normalize();
+ String uriString = uri.toString();
+ if (uriString.length() == 0) throw new IllegalArgumentException("uri is empty");
byte prefix = 0;
for (int i = 1; i < URI_PREFIX_MAP.length; i++) {
@@ -361,28 +358,72 @@
}
/**
+ * Create a new NDEF Record containing a URI.<p>
+ * Use this method to encode a URI (or URL) into an NDEF Record.<p>
+ * Uses the well known URI type representation: {@link #TNF_WELL_KNOWN}
+ * and {@link #RTD_URI}. This is the most efficient encoding
+ * of a URI into NDEF.<p>
+ * The uriString parameter will be normalized with
+ * {@link Uri#normalize} to set the scheme to lower case to
+ * follow Android best practices for intent filtering.
+ * However the unchecked exception
+ * {@link IllegalArgumentException} may be thrown if the uriString
+ * parameter has serious problems, for example if it is empty, so always
+ * catch this exception if you are passing user-generated data into this
+ * method.<p>
+ *
+ * Reference specification: NFCForum-TS-RTD_URI_1.0
+ *
+ * @param uriString string URI to encode.
+ * @return an NDEF Record containing the URI
+ * @throws IllegalArugmentException if the uriString is empty or invalid
+ */
+ public static NdefRecord createUri(String uriString) {
+ return createUri(Uri.parse(uriString));
+ }
+
+ /**
* Create a new NDEF Record containing MIME data.<p>
* Use this method to encode MIME-typed data into an NDEF Record,
* such as "text/plain", or "image/jpeg".<p>
- * Expects US-ASCII characters in mimeType. The encoding of the
- * mimeData depends on the mimeType.<p>
+ * The mimeType parameter will be normalized with
+ * {@link Intent#normalizeMimeType} to follow Android best
+ * practices for intent filtering, for example to force lower-case.
+ * However the unchecked exception
+ * {@link IllegalArgumentException} may be thrown
+ * if the mimeType parameter has serious problems,
+ * for example if it is empty, so always catch this
+ * exception if you are passing user-generated data into this method.
+ * <p>
* For efficiency, This method might not make an internal copy of the
* mimeData byte array, so take care not
- * to re-use the mimeData byte array while still using the returned
+ * to modify the mimeData byte array while still using the returned
* NdefRecord.
*
- * @param mimeType MIME type, expects US-ASCII characters only
+ * @param mimeType a valid MIME type
* @param mimeData MIME data as bytes
* @return an NDEF Record containing the MIME-typed data
- * @throws IllegalArugmentException if a valid record cannot be created
+ * @throws IllegalArugmentException if the mimeType is empty or invalid
+ *
*/
public static NdefRecord createMime(String mimeType, byte[] mimeData) {
- if (mimeType.length() == 0) {
- throw new IllegalArgumentException("empty mimeType");
- }
+ if (mimeType == null) throw new NullPointerException("mimeType is null");
- return new NdefRecord(TNF_MIME_MEDIA, mimeType.getBytes(Charsets.US_ASCII), null,
- mimeData);
+ // We only do basic MIME type validation: trying to follow the
+ // RFCs strictly only ends in tears, since there are lots of MIME
+ // types in common use that are not strictly valid as per RFC rules
+ mimeType = Intent.normalizeMimeType(mimeType);
+ if (mimeType.length() == 0) throw new IllegalArgumentException("mimeType is empty");
+ int slashIndex = mimeType.indexOf('/');
+ if (slashIndex == 0) throw new IllegalArgumentException("mimeType must have major type");
+ if (slashIndex == mimeType.length() - 1) {
+ throw new IllegalArgumentException("mimeType must have minor type");
+ }
+ // missing '/' is allowed
+
+ // MIME RFCs suggest ASCII encoding for content-type
+ byte[] typeBytes = mimeType.getBytes(Charsets.US_ASCII);
+ return new NdefRecord(TNF_MIME_MEDIA, typeBytes, null, mimeData);
}
/**
@@ -391,32 +432,38 @@
* The data is typed by a domain name (usually your Android package name) and
* a domain-specific type. This data is packaged into a "NFC Forum External
* Type" NDEF Record.<p>
- * Both the domain and type used to construct an external record are case
- * insensitive, and this implementation will encode all characters to lower
- * case. Only a subset of ASCII characters are allowed for the domain
- * and type. There are no restrictions on the payload data.<p>
+ * NFC Forum requires that the domain and type used in an external record
+ * are treated as case insensitive, however Android intent filtering is
+ * always case sensitive. So this method will force the domain and type to
+ * lower-case before creating the NDEF Record.<p>
+ * The unchecked exception {@link IllegalArgumentException} will be thrown
+ * if the domain and type have serious problems, for example if either field
+ * is empty, so always catch this
+ * exception if you are passing user-generated data into this method.<p>
+ * There are no such restrictions on the payload data.<p>
* For efficiency, This method might not make an internal copy of the
* data byte array, so take care not
- * to re-use the data byte array while still using the returned
+ * to modify the data byte array while still using the returned
* NdefRecord.
*
* Reference specification: NFCForum-TS-RTD_1.0
* @param domain domain-name of issuing organization
* @param type domain-specific type of data
* @param data payload as bytes
- * @throws IllegalArugmentException if a valid record cannot be created
+ * @throws IllegalArugmentException if either domain or type are empty or invalid
*/
public static NdefRecord createExternal(String domain, String type, byte[] data) {
- if (domain.length() == 0 || type.length() == 0) {
- throw new IllegalArgumentException("empty domain or type");
- }
- byte[] byteDomain = domain.getBytes(Charsets.US_ASCII);
- ensureValidDomain(byteDomain);
- toLowerCase(byteDomain);
- byte[] byteType = type.getBytes(Charsets.US_ASCII);
- ensureValidWkt(byteType);
- toLowerCase(byteType);
+ if (domain == null) throw new NullPointerException("domain is null");
+ if (type == null) throw new NullPointerException("type is null");
+ domain = domain.trim().toLowerCase(Locale.US);
+ type = type.trim().toLowerCase(Locale.US);
+
+ if (domain.length() == 0) throw new IllegalArgumentException("domain is empty");
+ if (type.length() == 0) throw new IllegalArgumentException("type is empty");
+
+ byte[] byteDomain = domain.getBytes(Charsets.UTF_8);
+ byte[] byteType = type.getBytes(Charsets.UTF_8);
byte[] b = new byte[byteDomain.length + 1 + byteType.length];
System.arraycopy(byteDomain, 0, b, 0, byteDomain.length);
b[byteDomain.length] = ':';
@@ -574,51 +621,113 @@
}
/**
- * Helper to return the NdefRecord as a URI.
- * TODO: Consider making a member method instead of static
- * TODO: Consider more validation that this is a URI record
- * TODO: Make a public API
- * @hide
+ * Map this record to a MIME type, or return null if it cannot be mapped.<p>
+ * Currently this method considers all {@link #TNF_MIME_MEDIA} records to
+ * be MIME records, as well as some {@link #TNF_WELL_KNOWN} records such as
+ * {@link #RTD_TEXT}. If this is a MIME record then the MIME type as string
+ * is returned, otherwise null is returned.<p>
+ * This method does not perform validation that the MIME type is
+ * actually valid. It always attempts to
+ * return a string containing the type if this is a MIME record.<p>
+ * The returned MIME type will by normalized to lower-case using
+ * {@link Intent#normalizeMimeType}.<p>
+ * The MIME payload can be obtained using {@link #getPayload}.
+ *
+ * @return MIME type as a string, or null if this is not a MIME record
*/
- public static Uri parseWellKnownUriRecord(NdefRecord record) throws FormatException {
- byte[] payload = record.getPayload();
- if (payload.length < 2) {
- throw new FormatException("Payload is not a valid URI (missing prefix)");
+ public String toMimeType() {
+ switch (mTnf) {
+ case NdefRecord.TNF_WELL_KNOWN:
+ if (Arrays.equals(mType, NdefRecord.RTD_TEXT)) {
+ return "text/plain";
+ }
+ break;
+ case NdefRecord.TNF_MIME_MEDIA:
+ String mimeType = new String(mType, Charsets.US_ASCII);
+ return Intent.normalizeMimeType(mimeType);
}
-
- /*
- * payload[0] contains the URI Identifier Code, per the
- * NFC Forum "URI Record Type Definition" section 3.2.2.
- *
- * payload[1]...payload[payload.length - 1] contains the rest of
- * the URI.
- */
- int prefixIndex = (payload[0] & 0xff);
- if (prefixIndex < 0 || prefixIndex >= URI_PREFIX_MAP.length) {
- throw new FormatException("Payload is not a valid URI (invalid prefix)");
- }
- String prefix = URI_PREFIX_MAP[prefixIndex];
- byte[] fullUri = concat(prefix.getBytes(Charsets.UTF_8),
- Arrays.copyOfRange(payload, 1, payload.length));
- return Uri.parse(new String(fullUri, Charsets.UTF_8));
- }
-
- private static byte[] concat(byte[]... arrays) {
- int length = 0;
- for (byte[] array : arrays) {
- length += array.length;
- }
- byte[] result = new byte[length];
- int pos = 0;
- for (byte[] array : arrays) {
- System.arraycopy(array, 0, result, pos, array.length);
- pos += array.length;
- }
- return result;
+ return null;
}
/**
- * Main parsing method.<p>
+ * Map this record to a URI, or return null if it cannot be mapped.<p>
+ * Currently this method considers the following to be URI records:
+ * <ul>
+ * <li>{@link #TNF_ABSOLUTE_URI} records.</li>
+ * <li>{@link #TNF_WELL_KNOWN} with a type of {@link #RTD_URI}.</li>
+ * <li>{@link #TNF_WELL_KNOWN} with a type of {@link #RTD_SMART_POSTER}
+ * and containing a URI record in the NDEF message nested in the payload.
+ * </li>
+ * <li>{@link #TNF_EXTERNAL_TYPE} records.</li>
+ * </ul>
+ * If this is not a URI record by the above rules, then null is returned.<p>
+ * This method does not perform validation that the URI is
+ * actually valid: it always attempts to create and return a URI if
+ * this record appears to be a URI record by the above rules.<p>
+ * The returned URI will be normalized to have a lower case scheme
+ * using {@link Uri#normalize}.<p>
+ *
+ * @return URI, or null if this is not a URI record
+ */
+ public Uri toUri() {
+ return toUri(false);
+ }
+
+ private Uri toUri(boolean inSmartPoster) {
+ switch (mTnf) {
+ case TNF_WELL_KNOWN:
+ if (Arrays.equals(mType, RTD_SMART_POSTER) && !inSmartPoster) {
+ try {
+ // check payload for a nested NDEF Message containing a URI
+ NdefMessage nestedMessage = new NdefMessage(mPayload);
+ for (NdefRecord nestedRecord : nestedMessage.getRecords()) {
+ Uri uri = nestedRecord.toUri(true);
+ if (uri != null) {
+ return uri;
+ }
+ }
+ } catch (FormatException e) { }
+ } else if (Arrays.equals(mType, RTD_URI)) {
+ return parseWktUri().normalize();
+ }
+ break;
+
+ case TNF_ABSOLUTE_URI:
+ Uri uri = Uri.parse(new String(mType, Charsets.UTF_8));
+ return uri.normalize();
+
+ case TNF_EXTERNAL_TYPE:
+ if (inSmartPoster) {
+ break;
+ }
+ return Uri.parse("vnd.android.nfc://ext/" + new String(mType, Charsets.US_ASCII));
+ }
+ return null;
+ }
+
+ /**
+ * Return complete URI of {@link #TNF_WELL_KNOWN}, {@link #RTD_URI} records.
+ * @return complete URI, or null if invalid
+ */
+ private Uri parseWktUri() {
+ if (mPayload.length < 2) {
+ return null;
+ }
+
+ // payload[0] contains the URI Identifier Code, as per
+ // NFC Forum "URI Record Type Definition" section 3.2.2.
+ int prefixIndex = (mPayload[0] & (byte)0xFF);
+ if (prefixIndex < 0 || prefixIndex >= URI_PREFIX_MAP.length) {
+ return null;
+ }
+ String prefix = URI_PREFIX_MAP[prefixIndex];
+ String suffix = new String(Arrays.copyOfRange(mPayload, 1, mPayload.length),
+ Charsets.UTF_8);
+ return Uri.parse(prefix + suffix);
+ }
+
+ /**
+ * Main record parsing method.<p>
* Expects NdefMessage to begin immediately, allows trailing data.<p>
* Currently has strict validation of all fields as per NDEF 1.0
* specification section 2.5. We will attempt to keep this as strict as
@@ -902,42 +1011,4 @@
}
return s;
}
-
- /** Ensure valid 'DNS-char' as per RFC2234 */
- private static void ensureValidDomain(byte[] bs) {
- for (int i = 0; i < bs.length; i++) {
- byte b = bs[i];
- if ((b >= 'A' && b <= 'Z') ||
- (b >= 'a' && b <= 'z') ||
- (b >= '0' && b <= '9') ||
- b == '.' || b == '-') {
- continue;
- }
- throw new IllegalArgumentException("invalid character in domain");
- }
- }
-
- /** Ensure valid 'WKT-char' as per RFC2234 */
- private static void ensureValidWkt(byte[] bs) {
- for (int i = 0; i < bs.length; i++) {
- byte b = bs[i];
- if ((b >= 'A' && b <= 'Z') ||
- (b >= 'a' && b <= 'z') ||
- (b >= '0' && b <= '9') ||
- b == '(' || b == ')' || b == '+' || b == ',' || b == '-' ||
- b == ':' || b == '=' || b == '@' || b == ';' || b == '$' ||
- b == '_' || b == '!' || b == '*' || b == '\'' || b == '.') {
- continue;
- }
- throw new IllegalArgumentException("invalid character in type");
- }
- }
-
- private static void toLowerCase(byte[] b) {
- for (int i = 0; i < b.length; i++) {
- if (b[i] >= 'A' && b[i] <= 'Z') {
- b[i] += 0x20;
- }
- }
- }
}
diff --git a/core/java/android/nfc/NfcAdapter.java b/core/java/android/nfc/NfcAdapter.java
index 53a0341..5176857 100644
--- a/core/java/android/nfc/NfcAdapter.java
+++ b/core/java/android/nfc/NfcAdapter.java
@@ -66,6 +66,9 @@
* <p>If the tag has an NDEF payload this intent is started before
* {@link #ACTION_TECH_DISCOVERED}. If any activities respond to this intent neither
* {@link #ACTION_TECH_DISCOVERED} or {@link #ACTION_TAG_DISCOVERED} will be started.
+ *
+ * <p>The MIME type or data URI of this intent are normalized before dispatch -
+ * so that MIME, URI scheme and URI host are always lower-case.
*/
@SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
public static final String ACTION_NDEF_DISCOVERED = "android.nfc.action.NDEF_DISCOVERED";
@@ -151,9 +154,13 @@
public static final String EXTRA_TAG = "android.nfc.extra.TAG";
/**
- * Optional extra containing an array of {@link NdefMessage} present on the discovered tag for
- * the {@link #ACTION_NDEF_DISCOVERED}, {@link #ACTION_TECH_DISCOVERED}, and
- * {@link #ACTION_TAG_DISCOVERED} intents.
+ * Extra containing an array of {@link NdefMessage} present on the discovered tag.<p>
+ * This extra is mandatory for {@link #ACTION_NDEF_DISCOVERED} intents,
+ * and optional for {@link #ACTION_TECH_DISCOVERED}, and
+ * {@link #ACTION_TAG_DISCOVERED} intents.<p>
+ * When this extra is present there will always be at least one
+ * {@link NdefMessage} element. Most NDEF tags have only one NDEF message,
+ * but we use an array for future compatibility.
*/
public static final String EXTRA_NDEF_MESSAGES = "android.nfc.extra.NDEF_MESSAGES";
@@ -386,10 +393,10 @@
*/
@Deprecated
public static NfcAdapter getDefaultAdapter() {
- // introduce in API version 9 (GB 2.3)
+ // introduced in API version 9 (GB 2.3)
// deprecated in API version 10 (GB 2.3.3)
// removed from public API in version 16 (ICS MR2)
- // will need to maintain this as a hidden API for a while longer...
+ // should maintain as a hidden API for binary compatibility for a little longer
Log.w(TAG, "WARNING: NfcAdapter.getDefaultAdapter() is deprecated, use " +
"NfcAdapter.getDefaultAdapter(Context) instead", new Exception());
@@ -803,6 +810,7 @@
* @throws IllegalStateException if the Activity has already been paused
* @deprecated use {@link #setNdefPushMessage} instead
*/
+ @Deprecated
public void disableForegroundNdefPush(Activity activity) {
if (activity == null) {
throw new NullPointerException();
@@ -875,6 +883,24 @@
}
/**
+ * Inject a mock NFC tag.<p>
+ * Used for testing purposes.
+ * <p class="note">Requires the
+ * {@link android.Manifest.permission#WRITE_SECURE_SETTINGS} permission.
+ * @hide
+ */
+ public void dispatch(Tag tag) {
+ if (tag == null) {
+ throw new NullPointerException("tag cannot be null");
+ }
+ try {
+ sService.dispatch(tag);
+ } catch (RemoteException e) {
+ attemptDeadServiceRecovery(e);
+ }
+ }
+
+ /**
* @hide
*/
public INfcAdapterExtras getNfcAdapterExtrasInterface() {
diff --git a/core/java/android/nfc/Tag.java b/core/java/android/nfc/Tag.java
index 9fe0bed..f9b765cb 100644
--- a/core/java/android/nfc/Tag.java
+++ b/core/java/android/nfc/Tag.java
@@ -108,14 +108,14 @@
* <p>
*/
public final class Tag implements Parcelable {
- /*package*/ final byte[] mId;
- /*package*/ final int[] mTechList;
- /*package*/ final String[] mTechStringList;
- /*package*/ final Bundle[] mTechExtras;
- /*package*/ final int mServiceHandle; // for use by NFC service, 0 indicates a mock
- /*package*/ final INfcTag mTagService; // interface to NFC service, will be null if mock tag
+ final byte[] mId;
+ final int[] mTechList;
+ final String[] mTechStringList;
+ final Bundle[] mTechExtras;
+ final int mServiceHandle; // for use by NFC service, 0 indicates a mock
+ final INfcTag mTagService; // interface to NFC service, will be null if mock tag
- /*package*/ int mConnectedTechnology;
+ int mConnectedTechnology;
/**
* Hidden constructor to be used by NFC service and internal classes.
diff --git a/core/java/android/nfc/tech/BasicTagTechnology.java b/core/java/android/nfc/tech/BasicTagTechnology.java
index 913ae0e..b6b347c 100644
--- a/core/java/android/nfc/tech/BasicTagTechnology.java
+++ b/core/java/android/nfc/tech/BasicTagTechnology.java
@@ -18,7 +18,6 @@
import android.nfc.ErrorCodes;
import android.nfc.Tag;
-import android.nfc.TagLostException;
import android.nfc.TransceiveResult;
import android.os.RemoteException;
import android.util.Log;
@@ -28,12 +27,13 @@
/**
* A base class for tag technologies that are built on top of transceive().
*/
-/* package */ abstract class BasicTagTechnology implements TagTechnology {
+abstract class BasicTagTechnology implements TagTechnology {
private static final String TAG = "NFC";
- /*package*/ final Tag mTag;
- /*package*/ boolean mIsConnected;
- /*package*/ int mSelectedTechnology;
+ final Tag mTag;
+
+ boolean mIsConnected;
+ int mSelectedTechnology;
BasicTagTechnology(Tag tag, int tech) throws RemoteException {
mTag = tag;
@@ -139,7 +139,7 @@
}
}
/** Internal transceive */
- /*package*/ byte[] transceive(byte[] data, boolean raw) throws IOException {
+ byte[] transceive(byte[] data, boolean raw) throws IOException {
checkConnected();
try {
diff --git a/core/java/android/os/AsyncTask.java b/core/java/android/os/AsyncTask.java
index 5e9abb7..fd6bed7 100644
--- a/core/java/android/os/AsyncTask.java
+++ b/core/java/android/os/AsyncTask.java
@@ -135,6 +135,8 @@
* <p>There are a few threading rules that must be followed for this class to
* work properly:</p>
* <ul>
+ * <li>The AsyncTask class must be loaded on the UI thread. This is done
+ * automatically as of {@link android.os.Build.VERSION_CODES#JELLY_BEAN}.</li>
* <li>The task instance must be created on the UI thread.</li>
* <li>{@link #execute} must be invoked on the UI thread.</li>
* <li>Do not call {@link #onPreExecute()}, {@link #onPostExecute},
diff --git a/core/java/android/os/Build.java b/core/java/android/os/Build.java
index 88fea91..c106092 100644
--- a/core/java/android/os/Build.java
+++ b/core/java/android/os/Build.java
@@ -167,6 +167,8 @@
* medium density normal size screens unless otherwise indicated).
* They can still explicitly specify screen support either way with the
* supports-screens manifest tag.
+ * <li> {@link android.widget.TabHost} will use the new dark tab
+ * background design.
* </ul>
*/
public static final int DONUT = 4;
@@ -208,6 +210,13 @@
/**
* November 2010: Android 2.3
+ *
+ * <p>Applications targeting this or a later release will get these
+ * new changes in behavior:</p>
+ * <ul>
+ * <li> The application's notification icons will be shown on the new
+ * dark status bar background, so must be visible in this situation.
+ * </ul>
*/
public static final int GINGERBREAD = 9;
@@ -224,14 +233,34 @@
* <ul>
* <li> The default theme for applications is now dark holographic:
* {@link android.R.style#Theme_Holo}.
+ * <li> On large screen devices that do not have a physical menu
+ * button, the soft (compatibility) menu is disabled.
* <li> The activity lifecycle has changed slightly as per
* {@link android.app.Activity}.
+ * <li> An application will crash if it does not call through
+ * to the super implementation of its
+ * {@link android.app.Activity#onPause Activity.onPause()} method.
* <li> When an application requires a permission to access one of
* its components (activity, receiver, service, provider), this
* permission is no longer enforced when the application wants to
* access its own component. This means it can require a permission
* on a component that it does not itself hold and still access that
* component.
+ * <li> {@link android.content.Context#getSharedPreferences
+ * Context.getSharedPreferences()} will not automatically reload
+ * the preferences if they have changed on storage, unless
+ * {@link android.content.Context#MODE_MULTI_PROCESS} is used.
+ * <li> {@link android.view.ViewGroup#setMotionEventSplittingEnabled}
+ * will default to true.
+ * <li> {@link android.view.WindowManager.LayoutParams#FLAG_SPLIT_TOUCH}
+ * is enabled by default on windows.
+ * <li> {@link android.widget.PopupWindow#isSplitTouchEnabled()
+ * PopupWindow.isSplitTouchEnabled()} will return true by default.
+ * <li> {@link android.widget.GridView} and {@link android.widget.ListView}
+ * will use {@link android.view.View#setActivated View.setActivated}
+ * for selected items if they do not implement {@link android.widget.Checkable}.
+ * <li> {@link android.widget.Scroller} will be constructed with
+ * "flywheel" behavior enabled by default.
* </ul>
*/
public static final int HONEYCOMB = 11;
@@ -266,13 +295,26 @@
* preferred over the older screen size buckets and for older devices
* the appropriate buckets will be inferred from them.</p>
*
- * <p>New {@link android.content.pm.PackageManager#FEATURE_SCREEN_PORTRAIT}
+ * <p>Applications targeting this or a later release will get these
+ * new changes in behavior:</p>
+ * <ul>
+ * <li><p>New {@link android.content.pm.PackageManager#FEATURE_SCREEN_PORTRAIT}
* and {@link android.content.pm.PackageManager#FEATURE_SCREEN_LANDSCAPE}
- * features are introduced in this release. Applications that target
+ * features were introduced in this release. Applications that target
* previous platform versions are assumed to require both portrait and
* landscape support in the device; when targeting Honeycomb MR1 or
* greater the application is responsible for specifying any specific
* orientation it requires.</p>
+ * <li><p>{@link android.os.AsyncTask} will use the serial executor
+ * by default when calling {@link android.os.AsyncTask#execute}.</p>
+ * <li><p>{@link android.content.pm.ActivityInfo#configChanges
+ * ActivityInfo.configChanges} will have the
+ * {@link android.content.pm.ActivityInfo#CONFIG_SCREEN_SIZE} and
+ * {@link android.content.pm.ActivityInfo#CONFIG_SMALLEST_SCREEN_SIZE}
+ * bits set; these need to be cleared for older applications because
+ * some developers have done absolute comparisons against this value
+ * instead of correctly masking the bits they are interested in.
+ * </ul>
*/
public static final int HONEYCOMB_MR2 = 13;
@@ -306,14 +348,31 @@
* <li> The fadingEdge attribute on views will be ignored (fading edges is no
* longer a standard part of the UI). A new requiresFadingEdge attribute allows
* applications to still force fading edges on for special cases.
+ * <li> {@link android.content.Context#bindService Context.bindService()}
+ * will not automatically add in {@link android.content.Context#BIND_WAIVE_PRIORITY}.
+ * <li> App Widgets will have standard padding automatically added around
+ * them, rather than relying on the padding being baked into the widget itself.
+ * <li> An exception will be thrown if you try to change the type of a
+ * window after it has been added to the window manager. Previously this
+ * would result in random incorrect behavior.
+ * <li> {@link android.view.animation.AnimationSet} will parse out
+ * the duration, fillBefore, fillAfter, repeatMode, and startOffset
+ * XML attributes that are defined.
+ * <li> {@link android.app.ActionBar#setHomeButtonEnabled
+ * ActionBar.setHomeButtonEnabled()} is false by default.
* </ul>
*/
public static final int ICE_CREAM_SANDWICH = 14;
/**
- * Android 4.0.3.
+ * December 2011: Android 4.0.3.
*/
public static final int ICE_CREAM_SANDWICH_MR1 = 15;
+
+ /**
+ * Next up on Android!
+ */
+ public static final int JELLY_BEAN = CUR_DEVELOPMENT;
}
/** The type of build, like "user" or "eng". */
diff --git a/core/java/android/os/IPowerManager.aidl b/core/java/android/os/IPowerManager.aidl
index 9a53d76..270e9be 100644
--- a/core/java/android/os/IPowerManager.aidl
+++ b/core/java/android/os/IPowerManager.aidl
@@ -45,4 +45,5 @@
// sets the brightness of the backlights (screen, keyboard, button) 0-255
void setBacklightBrightness(int brightness);
void setAttentionLight(boolean on, int color);
+ void setAutoBrightnessAdjustment(float adj);
}
diff --git a/core/java/android/provider/MediaStore.java b/core/java/android/provider/MediaStore.java
index 4e01672..d11219b 100644
--- a/core/java/android/provider/MediaStore.java
+++ b/core/java/android/provider/MediaStore.java
@@ -62,6 +62,14 @@
public static final String ACTION_MTP_SESSION_END = "android.provider.action.MTP_SESSION_END";
/**
+ * The method name used by the media scanner and mtp to tell the media provider to
+ * rescan and reclassify that have become unhidden because of renaming folders or
+ * removing nomedia files
+ * @hide
+ */
+ public static final String UNHIDE_CALL = "unhide";
+
+ /**
* Activity Action: Launch a music player.
* The activity should be able to play, browse, or manipulate music files stored on the device.
*
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 0202c47..375e5e4 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -747,7 +747,7 @@
Cursor c = null;
try {
c = cp.query(mUri, SELECT_VALUE, NAME_EQ_PLACEHOLDER,
- new String[]{name}, null);
+ new String[]{name}, null, null);
if (c == null) {
Log.w(TAG, "Can't get key " + name + " from " + mUri);
return null;
@@ -1401,6 +1401,12 @@
public static final String SCREEN_BRIGHTNESS_MODE = "screen_brightness_mode";
/**
+ * Adjustment to auto-brightness to make it generally more (>0.0 <1.0)
+ * or less (<0.0 >-1.0) bright.
+ */
+ public static final String SCREEN_AUTO_BRIGHTNESS_ADJ = "screen_auto_brightness_adj";
+
+ /**
* SCREEN_BRIGHTNESS_MODE value for manual mode.
*/
public static final int SCREEN_BRIGHTNESS_MODE_MANUAL = 0;
@@ -1672,6 +1678,13 @@
public static final String TRANSITION_ANIMATION_SCALE = "transition_animation_scale";
/**
+ * Scaling factor for Animator-based animations. This affects both the start delay and
+ * duration of all such animations. Setting to 0 will cause animations to end immediately.
+ * The default value is 1.
+ */
+ public static final String ANIMATOR_DURATION_SCALE = "animator_duration_scale";
+
+ /**
* Scaling factor for normal window animations. Setting to 0 will disable window
* animations.
* @hide
@@ -1927,6 +1940,7 @@
SCREEN_OFF_TIMEOUT,
SCREEN_BRIGHTNESS,
SCREEN_BRIGHTNESS_MODE,
+ SCREEN_AUTO_BRIGHTNESS_ADJ,
VIBRATE_ON,
MODE_RINGER,
MODE_RINGER_STREAMS_AFFECTED,
@@ -2468,6 +2482,11 @@
Uri.parse("content://" + AUTHORITY + "/secure");
/**
+ * Whether user has enabled development settings.
+ */
+ public static final String DEVELOPMENT_SETTINGS_ENABLED = "development_settings_enabled";
+
+ /**
* Whether ADB is enabled.
*/
public static final String ADB_ENABLED = "adb_enabled";
@@ -4104,17 +4123,38 @@
/** {@hide} */
public static final String NETSTATS_POLL_INTERVAL = "netstats_poll_interval";
/** {@hide} */
- public static final String NETSTATS_PERSIST_THRESHOLD = "netstats_persist_threshold";
+ public static final String NETSTATS_TIME_CACHE_MAX_AGE = "netstats_time_cache_max_age";
/** {@hide} */
- public static final String NETSTATS_NETWORK_BUCKET_DURATION = "netstats_network_bucket_duration";
+ public static final String NETSTATS_GLOBAL_ALERT_BYTES = "netstats_global_alert_bytes";
/** {@hide} */
- public static final String NETSTATS_NETWORK_MAX_HISTORY = "netstats_network_max_history";
+ public static final String NETSTATS_SAMPLE_ENABLED = "netstats_sample_enabled";
+
+ /** {@hide} */
+ public static final String NETSTATS_DEV_BUCKET_DURATION = "netstats_dev_bucket_duration";
+ /** {@hide} */
+ public static final String NETSTATS_DEV_PERSIST_BYTES = "netstats_dev_persist_bytes";
+ /** {@hide} */
+ public static final String NETSTATS_DEV_ROTATE_AGE = "netstats_dev_rotate_age";
+ /** {@hide} */
+ public static final String NETSTATS_DEV_DELETE_AGE = "netstats_dev_delete_age";
+
/** {@hide} */
public static final String NETSTATS_UID_BUCKET_DURATION = "netstats_uid_bucket_duration";
/** {@hide} */
- public static final String NETSTATS_UID_MAX_HISTORY = "netstats_uid_max_history";
+ public static final String NETSTATS_UID_PERSIST_BYTES = "netstats_uid_persist_bytes";
/** {@hide} */
- public static final String NETSTATS_TAG_MAX_HISTORY = "netstats_tag_max_history";
+ public static final String NETSTATS_UID_ROTATE_AGE = "netstats_uid_rotate_age";
+ /** {@hide} */
+ public static final String NETSTATS_UID_DELETE_AGE = "netstats_uid_delete_age";
+
+ /** {@hide} */
+ public static final String NETSTATS_UID_TAG_BUCKET_DURATION = "netstats_uid_tag_bucket_duration";
+ /** {@hide} */
+ public static final String NETSTATS_UID_TAG_PERSIST_BYTES = "netstats_uid_tag_persist_bytes";
+ /** {@hide} */
+ public static final String NETSTATS_UID_TAG_ROTATE_AGE = "netstats_uid_tag_rotate_age";
+ /** {@hide} */
+ public static final String NETSTATS_UID_TAG_DELETE_AGE = "netstats_uid_tag_delete_age";
/** Preferred NTP server. {@hide} */
public static final String NTP_SERVER = "ntp_server";
diff --git a/core/java/android/text/MeasuredText.java b/core/java/android/text/MeasuredText.java
index c184c11..a52e2ba 100644
--- a/core/java/android/text/MeasuredText.java
+++ b/core/java/android/text/MeasuredText.java
@@ -109,6 +109,9 @@
for (int i = 0; i < spans.length; i++) {
int startInPara = spanned.getSpanStart(spans[i]) - start;
int endInPara = spanned.getSpanEnd(spans[i]) - start;
+ // The span interval may be larger and must be restricted to [start, end[
+ if (startInPara < 0) startInPara = 0;
+ if (endInPara > len) endInPara = len;
for (int j = startInPara; j < endInPara; j++) {
mChars[j] = '\uFFFC';
}
diff --git a/core/java/android/text/format/Time.java b/core/java/android/text/format/Time.java
index b4445ca..e9b0d32 100644
--- a/core/java/android/text/format/Time.java
+++ b/core/java/android/text/format/Time.java
@@ -481,6 +481,9 @@
* @throws android.util.TimeFormatException if s cannot be parsed.
*/
public boolean parse3339(String s) {
+ if (s == null) {
+ throw new NullPointerException("time string is null");
+ }
if (nativeParse3339(s)) {
timezone = TIMEZONE_UTC;
return true;
diff --git a/core/java/android/text/style/SuggestionSpan.java b/core/java/android/text/style/SuggestionSpan.java
index 0f26a34..5dc206f 100644
--- a/core/java/android/text/style/SuggestionSpan.java
+++ b/core/java/android/text/style/SuggestionSpan.java
@@ -25,6 +25,7 @@
import android.text.ParcelableSpan;
import android.text.TextPaint;
import android.text.TextUtils;
+import android.util.Log;
import android.widget.TextView;
import java.util.Arrays;
@@ -114,7 +115,7 @@
* @param context Context for the application
* @param locale locale Locale of the suggestions
* @param suggestions Suggestions for the string under the span. Only the first up to
- * {@link SuggestionSpan#SUGGESTIONS_MAX_SIZE} will be considered.
+ * {@link SuggestionSpan#SUGGESTIONS_MAX_SIZE} will be considered. Null values not permitted.
* @param flags Additional flags indicating how this span is handled in TextView
* @param notificationTargetClass if not null, this class will get notified when the user
* selects one of the suggestions.
@@ -124,10 +125,13 @@
final int N = Math.min(SUGGESTIONS_MAX_SIZE, suggestions.length);
mSuggestions = Arrays.copyOf(suggestions, N);
mFlags = flags;
- if (context != null && locale == null) {
+ if (locale != null) {
+ mLocaleString = locale.toString();
+ } else if (context != null) {
mLocaleString = context.getResources().getConfiguration().locale.toString();
} else {
- mLocaleString = locale.toString();
+ Log.e("SuggestionSpan", "No locale or context specified in SuggestionSpan constructor");
+ mLocaleString = "";
}
if (notificationTargetClass != null) {
diff --git a/core/java/android/util/DisplayMetrics.java b/core/java/android/util/DisplayMetrics.java
index 519b980..a43d36c 100644
--- a/core/java/android/util/DisplayMetrics.java
+++ b/core/java/android/util/DisplayMetrics.java
@@ -57,6 +57,13 @@
public static final int DENSITY_XHIGH = 320;
/**
+ * Standard quantized DPI for extra-extra-high-density screens. Applications
+ * should not generally worry about this density; relying on XHIGH graphics
+ * being scaled up to it should be sufficient for almost all cases.
+ */
+ public static final int DENSITY_XXHIGH = 480;
+
+ /**
* The reference density used throughout the system.
*/
public static final int DENSITY_DEFAULT = DENSITY_MEDIUM;
diff --git a/core/java/android/view/AccessibilityNodeInfoCache.java b/core/java/android/view/AccessibilityNodeInfoCache.java
new file mode 100644
index 0000000..244a491
--- /dev/null
+++ b/core/java/android/view/AccessibilityNodeInfoCache.java
@@ -0,0 +1,171 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.view;
+
+import android.util.LongSparseArray;
+import android.view.accessibility.AccessibilityEvent;
+import android.view.accessibility.AccessibilityNodeInfo;
+
+/**
+ * Simple cache for AccessibilityNodeInfos. The cache is mapping an
+ * accessibility id to an info. The cache allows storing of
+ * <code>null</code> values. It also tracks accessibility events
+ * and invalidates accordingly.
+ *
+ * @hide
+ */
+public class AccessibilityNodeInfoCache {
+
+ private final boolean ENABLED = true;
+
+ /**
+ * @return A new <strong>not synchronized</strong> AccessibilityNodeInfoCache.
+ */
+ public static AccessibilityNodeInfoCache newAccessibilityNodeInfoCache() {
+ return new AccessibilityNodeInfoCache();
+ }
+
+ /**
+ * @return A new <strong>synchronized</strong> AccessibilityNodeInfoCache.
+ */
+ public static AccessibilityNodeInfoCache newSynchronizedAccessibilityNodeInfoCache() {
+ return new AccessibilityNodeInfoCache() {
+ private final Object mLock = new Object();
+
+ @Override
+ public void clear() {
+ synchronized(mLock) {
+ super.clear();
+ }
+ }
+
+ @Override
+ public AccessibilityNodeInfo get(long accessibilityNodeId) {
+ synchronized(mLock) {
+ return super.get(accessibilityNodeId);
+ }
+ }
+
+ @Override
+ public void put(long accessibilityNodeId, AccessibilityNodeInfo info) {
+ synchronized(mLock) {
+ super.put(accessibilityNodeId, info);
+ }
+ }
+
+ @Override
+ public void remove(long accessibilityNodeId) {
+ synchronized(mLock) {
+ super.remove(accessibilityNodeId);
+ }
+ }
+ };
+ }
+
+ private final LongSparseArray<AccessibilityNodeInfo> mCacheImpl;
+
+ private AccessibilityNodeInfoCache() {
+ if (ENABLED) {
+ mCacheImpl = new LongSparseArray<AccessibilityNodeInfo>();
+ } else {
+ mCacheImpl = null;
+ }
+ }
+
+ /**
+ * The cache keeps track of {@link AccessibilityEvent}s and invalidates
+ * cached nodes as appropriate.
+ *
+ * @param event An event.
+ */
+ public void onAccessibilityEvent(AccessibilityEvent event) {
+ final int eventType = event.getEventType();
+ switch (eventType) {
+ case AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED:
+ case AccessibilityEvent.TYPE_VIEW_SCROLLED:
+ clear();
+ break;
+ case AccessibilityEvent.TYPE_VIEW_FOCUSED:
+ case AccessibilityEvent.TYPE_VIEW_SELECTED:
+ case AccessibilityEvent.TYPE_VIEW_TEXT_CHANGED:
+ case AccessibilityEvent.TYPE_VIEW_TEXT_SELECTION_CHANGED:
+ final long accessibilityNodeId = event.getSourceNodeId();
+ remove(accessibilityNodeId);
+ break;
+ }
+ }
+
+ /**
+ * Gets a cached {@link AccessibilityNodeInfo} given its accessibility node id.
+ *
+ * @param accessibilityNodeId The info accessibility node id.
+ * @return The cached {@link AccessibilityNodeInfo} or null if such not found.
+ */
+ public AccessibilityNodeInfo get(long accessibilityNodeId) {
+ if (ENABLED) {
+ return mCacheImpl.get(accessibilityNodeId);
+ } else {
+ return null;
+ }
+ }
+
+ /**
+ * Caches an {@link AccessibilityNodeInfo} given its accessibility node id.
+ *
+ * @param accessibilityNodeId The info accessibility node id.
+ * @param info The {@link AccessibilityNodeInfo} to cache.
+ */
+ public void put(long accessibilityNodeId, AccessibilityNodeInfo info) {
+ if (ENABLED) {
+ mCacheImpl.put(accessibilityNodeId, info);
+ }
+ }
+
+ /**
+ * Returns whether the cache contains an accessibility node id key.
+ *
+ * @param accessibilityNodeId The key for which to check.
+ * @return True if the key is in the cache.
+ */
+ public boolean containsKey(long accessibilityNodeId) {
+ if (ENABLED) {
+ return (mCacheImpl.indexOfKey(accessibilityNodeId) >= 0);
+ } else {
+ return false;
+ }
+ }
+
+ /**
+ * Removes a cached {@link AccessibilityNodeInfo}.
+ *
+ * @param accessibilityNodeId The info accessibility node id.
+ */
+ public void remove(long accessibilityNodeId) {
+ if (ENABLED) {
+ mCacheImpl.remove(accessibilityNodeId);
+ }
+ }
+
+ /**
+ * Clears the cache.
+ */
+ public void clear() {
+ if (ENABLED) {
+ mCacheImpl.clear();
+ }
+ }
+}
diff --git a/core/java/android/view/ActionMode.java b/core/java/android/view/ActionMode.java
index 34e7d4d..0349a2b 100644
--- a/core/java/android/view/ActionMode.java
+++ b/core/java/android/view/ActionMode.java
@@ -18,9 +18,15 @@
/**
- * Represents a contextual mode of the user interface. Action modes can be used for
- * modal interactions with content and replace parts of the normal UI until finished.
- * Examples of good action modes include selection modes, search, content editing, etc.
+ * Represents a contextual mode of the user interface. Action modes can be used to provide
+ * alternative interaction modes and replace parts of the normal UI until finished.
+ * Examples of good action modes include text selection and contextual actions.
+ * <div class="special reference">
+ * <h3>Developer Guides</h3>
+ * <p>For information about how to provide contextual actions with {@code ActionMode},
+ * read the <a href="{@docRoot}guide/topics/ui/menu.html#context-menu">Menus</a>
+ * developer guide.</p>
+ * </div>
*/
public abstract class ActionMode {
private Object mTag;
diff --git a/core/java/android/view/Choreographer.java b/core/java/android/view/Choreographer.java
index 63de128..c86ea77 100644
--- a/core/java/android/view/Choreographer.java
+++ b/core/java/android/view/Choreographer.java
@@ -26,7 +26,7 @@
import android.util.Log;
/**
- * Coodinates animations and drawing for UI on a particular thread.
+ * Coordinates animations and drawing for UI on a particular thread.
* @hide
*/
public final class Choreographer extends Handler {
@@ -94,8 +94,8 @@
}
/**
- * Gets the choreographer for this thread.
- * Must be called on the UI thread.
+ * Gets the choreographer for the calling thread. Must be called from
+ * a thread that already has a {@link android.os.Looper} associated with it.
*
* @return The choreographer for this thread.
* @throws IllegalStateException if the thread does not have a looper.
@@ -163,6 +163,15 @@
}
/**
+ * Return true if {@link #scheduleAnimation()} has been called but
+ * {@link OnAnimateListener#onAnimate() OnAnimateListener.onAnimate()} has
+ * not yet been called.
+ */
+ public boolean isAnimationScheduled() {
+ return mAnimationScheduled;
+ }
+
+ /**
* Schedules drawing to occur on the next frame synchronization boundary.
* Must be called on the UI thread.
*/
@@ -180,6 +189,15 @@
}
}
+ /**
+ * Return true if {@link #scheduleDraw()} has been called but
+ * {@link OnDrawListener#onDraw() OnDrawListener.onDraw()} has
+ * not yet been called.
+ */
+ public boolean isDrawScheduled() {
+ return mDrawScheduled;
+ }
+
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
diff --git a/core/java/android/view/GLES20Canvas.java b/core/java/android/view/GLES20Canvas.java
index e06d661..fa4dd25 100644
--- a/core/java/android/view/GLES20Canvas.java
+++ b/core/java/android/view/GLES20Canvas.java
@@ -22,6 +22,7 @@
import android.graphics.DrawFilter;
import android.graphics.Matrix;
import android.graphics.Paint;
+import android.graphics.PaintFlagsDrawFilter;
import android.graphics.Path;
import android.graphics.Picture;
import android.graphics.PorterDuff;
@@ -188,7 +189,7 @@
}
private static native int nGetMaximumTextureWidth();
- private static native int nGetMaximumTextureHeight();
+ private static native int nGetMaximumTextureHeight();
///////////////////////////////////////////////////////////////////////////
// Setup
@@ -267,6 +268,24 @@
private static native void nFinish(int renderer);
+ /**
+ * Returns the size of the stencil buffer required by the underlying
+ * implementation.
+ *
+ * @return The minimum number of bits the stencil buffer must. Always >= 0.
+ *
+ * @hide
+ */
+ public static int getStencilSize() {
+ return nGetStencilSize();
+ }
+
+ private static native int nGetStencilSize();
+
+ ///////////////////////////////////////////////////////////////////////////
+ // Functor
+ ///////////////////////////////////////////////////////////////////////////
+
@Override
public boolean callDrawGLFunction(int drawGLFunction) {
return nCallDrawGLFunction(mRenderer, drawGLFunction);
@@ -274,7 +293,6 @@
private static native boolean nCallDrawGLFunction(int renderer, int drawGLFunction);
-
///////////////////////////////////////////////////////////////////////////
// Memory
///////////////////////////////////////////////////////////////////////////
@@ -360,6 +378,12 @@
private static native int nGetDisplayListSize(int displayList);
+ static void setDisplayListName(int displayList, String name) {
+ nSetDisplayListName(displayList, name);
+ }
+
+ private static native void nSetDisplayListName(int displayList, String name);
+
@Override
public boolean drawDisplayList(DisplayList displayList, int width, int height, Rect dirty) {
return nDrawDisplayList(mRenderer,
@@ -546,6 +570,7 @@
private static native void nSetMatrix(int renderer, int matrix);
+ @SuppressWarnings("deprecation")
@Override
public void getMatrix(Matrix matrix) {
nGetMatrix(mRenderer, matrix.native_instance);
@@ -658,8 +683,17 @@
@Override
public void setDrawFilter(DrawFilter filter) {
mFilter = filter;
+ if (filter == null) {
+ nResetPaintFilter(mRenderer);
+ } else if (filter instanceof PaintFlagsDrawFilter) {
+ PaintFlagsDrawFilter flagsFilter = (PaintFlagsDrawFilter) filter;
+ nSetupPaintFilter(mRenderer, flagsFilter.clearBits, flagsFilter.setBits);
+ }
}
+ private static native void nResetPaintFilter(int renderer);
+ private static native void nSetupPaintFilter(int renderer, int clearBits, int setBits);
+
@Override
public DrawFilter getDrawFilter() {
return mFilter;
@@ -968,6 +1002,7 @@
private static native void nDrawPoints(int renderer, float[] points,
int offset, int count, int paint);
+ @SuppressWarnings("deprecation")
@Override
public void drawPosText(char[] text, int index, int count, float[] pos, Paint paint) {
if (index < 0 || index + count > text.length || count * 2 > pos.length) {
@@ -985,6 +1020,7 @@
private static native void nDrawPosText(int renderer, char[] text, int index, int count,
float[] pos, int paint);
+ @SuppressWarnings("deprecation")
@Override
public void drawPosText(String text, float[] pos, Paint paint) {
if (text.length() * 2 > pos.length) {
diff --git a/core/java/android/view/GLES20DisplayList.java b/core/java/android/view/GLES20DisplayList.java
index 0cb9449..969c9ab 100644
--- a/core/java/android/view/GLES20DisplayList.java
+++ b/core/java/android/view/GLES20DisplayList.java
@@ -31,10 +31,17 @@
private GLES20RecordingCanvas mCanvas;
private boolean mValid;
+ // Used for debugging
+ private final String mName;
+
// The native display list will be destroyed when this object dies.
// DO NOT overwrite this reference once it is set.
private DisplayListFinalizer mFinalizer;
+ GLES20DisplayList(String name) {
+ mName = name;
+ }
+
int getNativeDisplayList() {
if (!mValid || mFinalizer == null) {
throw new IllegalStateException("The display list is not valid.");
@@ -75,6 +82,7 @@
mCanvas.end(mFinalizer.mNativeDisplayList);
} else {
mFinalizer = new DisplayListFinalizer(mCanvas.end(0));
+ GLES20Canvas.setDisplayListName(mFinalizer.mNativeDisplayList, mName);
}
mCanvas.recycle();
mCanvas = null;
diff --git a/core/java/android/view/HardwareRenderer.java b/core/java/android/view/HardwareRenderer.java
index 4592ae6..9e8a228 100644
--- a/core/java/android/view/HardwareRenderer.java
+++ b/core/java/android/view/HardwareRenderer.java
@@ -238,6 +238,15 @@
private static native void nSetupShadersDiskCache(String cacheFile);
/**
+ * Notifies EGL that the frame is about to be rendered.
+ */
+ private static void beginFrame() {
+ nBeginFrame();
+ }
+
+ private static native void nBeginFrame();
+
+ /**
* Interface used to receive callbacks whenever a view is drawn by
* a hardware renderer instance.
*/
@@ -274,9 +283,12 @@
* Creates a new display list that can be used to record batches of
* drawing operations.
*
+ * @param name The name of the display list, used for debugging purpose.
+ * May be null
+ *
* @return A new display list.
*/
- public abstract DisplayList createDisplayList();
+ public abstract DisplayList createDisplayList(String name);
/**
* Creates a new hardware layer. A hardware layer built by calling this
@@ -808,6 +820,7 @@
}
void onPreDraw(Rect dirty) {
+
}
void onPostDraw() {
@@ -832,6 +845,8 @@
dirty = null;
}
+ beginFrame();
+
onPreDraw(dirty);
HardwareCanvas canvas = mCanvas;
@@ -1035,7 +1050,7 @@
EGL_BLUE_SIZE, 8,
EGL_ALPHA_SIZE, 8,
EGL_DEPTH_SIZE, 0,
- EGL_STENCIL_SIZE, 0,
+ EGL_STENCIL_SIZE, GLES20Canvas.getStencilSize(),
EGL_SURFACE_TYPE, EGL_WINDOW_BIT |
(dirtyRegions ? EGL_SWAP_BEHAVIOR_PRESERVED_BIT : 0),
EGL_NONE
@@ -1082,8 +1097,8 @@
}
@Override
- public DisplayList createDisplayList() {
- return new GLES20DisplayList();
+ public DisplayList createDisplayList(String name) {
+ return new GLES20DisplayList(name);
}
@Override
diff --git a/core/java/android/view/IWindowManager.aidl b/core/java/android/view/IWindowManager.aidl
index 93a9d50..c54d09e 100644
--- a/core/java/android/view/IWindowManager.aidl
+++ b/core/java/android/view/IWindowManager.aidl
@@ -229,4 +229,9 @@
* Device has a software navigation bar (separate from the status bar).
*/
boolean hasNavigationBar();
+
+ /**
+ * Lock the device immediately.
+ */
+ void lockNow();
}
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index a9d6cdf..7ba17b3 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -3761,8 +3761,14 @@
}
/**
- * Called when this view wants to give up focus. This will cause
- * {@link #onFocusChanged(boolean, int, android.graphics.Rect)} to be called.
+ * Called when this view wants to give up focus. If focus is cleared
+ * {@link #onFocusChanged(boolean, int, android.graphics.Rect)} is called.
+ * <p>
+ * <strong>Note:</strong> When a View clears focus the framework is trying
+ * to give focus to the first focusable View from the top. Hence, if this
+ * View is the first from the top that can take focus, then its focus will
+ * not be cleared nor will the focus change callback be invoked.
+ * </p>
*/
public void clearFocus() {
if (DBG) {
@@ -3770,6 +3776,14 @@
}
if ((mPrivateFlags & FOCUSED) != 0) {
+ // If this is the first focusable do not clear focus since the we
+ // try to give it focus every time a view clears its focus. Hence,
+ // the view that would gain focus already has it.
+ View firstFocusable = getFirstFocusable();
+ if (firstFocusable == this) {
+ return;
+ }
+
mPrivateFlags &= ~FOCUSED;
if (mParent != null) {
@@ -3778,9 +3792,24 @@
onFocusChanged(false, 0, null);
refreshDrawableState();
+
+ // The view cleared focus and invoked the callbacks, so now is the
+ // time to give focus to the the first focusable to ensure that the
+ // gain focus is announced after clear focus.
+ if (firstFocusable != null) {
+ firstFocusable.requestFocus(FOCUS_FORWARD);
+ }
}
}
+ private View getFirstFocusable() {
+ ViewRootImpl viewRoot = getViewRootImpl();
+ if (viewRoot != null) {
+ return viewRoot.focusSearch(null, FOCUS_FORWARD);
+ }
+ return null;
+ }
+
/**
* Called to clear the focus of a view that is about to be removed.
* Doesn't call clearChildFocus, which prevents this view from taking
@@ -6822,7 +6851,8 @@
if ((changed & VISIBILITY_MASK) != 0) {
if (mParent instanceof ViewGroup) {
- ((ViewGroup) mParent).onChildVisibilityChanged(this, (flags & VISIBILITY_MASK));
+ ((ViewGroup) mParent).onChildVisibilityChanged(this, (changed & VISIBILITY_MASK),
+ (flags & VISIBILITY_MASK));
((View) mParent).invalidate(true);
} else if (mParent != null) {
mParent.invalidateChild(this, null);
@@ -7282,6 +7312,7 @@
*
* @return The degrees of rotation.
*/
+ @ViewDebug.ExportedProperty(category = "drawing")
public float getRotation() {
return mTransformationInfo != null ? mTransformationInfo.mRotation : 0;
}
@@ -7323,6 +7354,7 @@
*
* @return The degrees of Y rotation.
*/
+ @ViewDebug.ExportedProperty(category = "drawing")
public float getRotationY() {
return mTransformationInfo != null ? mTransformationInfo.mRotationY : 0;
}
@@ -7369,6 +7401,7 @@
*
* @return The degrees of X rotation.
*/
+ @ViewDebug.ExportedProperty(category = "drawing")
public float getRotationX() {
return mTransformationInfo != null ? mTransformationInfo.mRotationX : 0;
}
@@ -7416,6 +7449,7 @@
* @see #getPivotY()
* @return The scaling factor.
*/
+ @ViewDebug.ExportedProperty(category = "drawing")
public float getScaleX() {
return mTransformationInfo != null ? mTransformationInfo.mScaleX : 1;
}
@@ -7454,6 +7488,7 @@
* @see #getPivotY()
* @return The scaling factor.
*/
+ @ViewDebug.ExportedProperty(category = "drawing")
public float getScaleY() {
return mTransformationInfo != null ? mTransformationInfo.mScaleY : 1;
}
@@ -7492,6 +7527,7 @@
* @see #getPivotY()
* @return The x location of the pivot point.
*/
+ @ViewDebug.ExportedProperty(category = "drawing")
public float getPivotX() {
return mTransformationInfo != null ? mTransformationInfo.mPivotX : 0;
}
@@ -7536,6 +7572,7 @@
* @see #getPivotY()
* @return The y location of the pivot point.
*/
+ @ViewDebug.ExportedProperty(category = "drawing")
public float getPivotY() {
return mTransformationInfo != null ? mTransformationInfo.mPivotY : 0;
}
@@ -7576,6 +7613,7 @@
* <p>By default this is 1.0f.
* @return The opacity of the view.
*/
+ @ViewDebug.ExportedProperty(category = "drawing")
public float getAlpha() {
return mTransformationInfo != null ? mTransformationInfo.mAlpha : 1;
}
@@ -7589,6 +7627,10 @@
* equivalent to calling {@link #setLayerType(int, android.graphics.Paint)} and
* setting a hardware layer.</p>
*
+ * <p>Note that setting alpha to a translucent value (0 < alpha < 1) may have
+ * performance implications. It is generally best to use the alpha property sparingly and
+ * transiently, as in the case of fading animations.</p>
+ *
* @param alpha The opacity of the view.
*
* @see #setLayerType(int, android.graphics.Paint)
@@ -7886,6 +7928,7 @@
*
* @return The visual x position of this view, in pixels.
*/
+ @ViewDebug.ExportedProperty(category = "drawing")
public float getX() {
return mLeft + (mTransformationInfo != null ? mTransformationInfo.mTranslationX : 0);
}
@@ -7908,6 +7951,7 @@
*
* @return The visual y position of this view, in pixels.
*/
+ @ViewDebug.ExportedProperty(category = "drawing")
public float getY() {
return mTop + (mTransformationInfo != null ? mTransformationInfo.mTranslationY : 0);
}
@@ -7931,6 +7975,7 @@
*
* @return The horizontal position of this view relative to its left position, in pixels.
*/
+ @ViewDebug.ExportedProperty(category = "drawing")
public float getTranslationX() {
return mTransformationInfo != null ? mTransformationInfo.mTranslationX : 0;
}
@@ -7967,6 +8012,7 @@
* @return The vertical position of this view relative to its top position,
* in pixels.
*/
+ @ViewDebug.ExportedProperty(category = "drawing")
public float getTranslationY() {
return mTransformationInfo != null ? mTransformationInfo.mTranslationY : 0;
}
@@ -7996,84 +8042,6 @@
}
/**
- * @hide
- */
- public void setFastTranslationX(float x) {
- ensureTransformationInfo();
- final TransformationInfo info = mTransformationInfo;
- info.mTranslationX = x;
- info.mMatrixDirty = true;
- }
-
- /**
- * @hide
- */
- public void setFastTranslationY(float y) {
- ensureTransformationInfo();
- final TransformationInfo info = mTransformationInfo;
- info.mTranslationY = y;
- info.mMatrixDirty = true;
- }
-
- /**
- * @hide
- */
- public void setFastX(float x) {
- ensureTransformationInfo();
- final TransformationInfo info = mTransformationInfo;
- info.mTranslationX = x - mLeft;
- info.mMatrixDirty = true;
- }
-
- /**
- * @hide
- */
- public void setFastY(float y) {
- ensureTransformationInfo();
- final TransformationInfo info = mTransformationInfo;
- info.mTranslationY = y - mTop;
- info.mMatrixDirty = true;
- }
-
- /**
- * @hide
- */
- public void setFastScaleX(float x) {
- ensureTransformationInfo();
- final TransformationInfo info = mTransformationInfo;
- info.mScaleX = x;
- info.mMatrixDirty = true;
- }
-
- /**
- * @hide
- */
- public void setFastScaleY(float y) {
- ensureTransformationInfo();
- final TransformationInfo info = mTransformationInfo;
- info.mScaleY = y;
- info.mMatrixDirty = true;
- }
-
- /**
- * @hide
- */
- public void setFastAlpha(float alpha) {
- ensureTransformationInfo();
- mTransformationInfo.mAlpha = alpha;
- }
-
- /**
- * @hide
- */
- public void setFastRotationY(float y) {
- ensureTransformationInfo();
- final TransformationInfo info = mTransformationInfo;
- info.mRotationY = y;
- info.mMatrixDirty = true;
- }
-
- /**
* Hit rectangle in parent's coordinates
*
* @param outRect The hit rectangle of the view.
@@ -8650,37 +8618,6 @@
}
/**
- * @hide
- */
- public void fastInvalidate() {
- if (skipInvalidate()) {
- return;
- }
- if ((mPrivateFlags & (DRAWN | HAS_BOUNDS)) == (DRAWN | HAS_BOUNDS) ||
- (mPrivateFlags & DRAWING_CACHE_VALID) == DRAWING_CACHE_VALID ||
- (mPrivateFlags & INVALIDATED) != INVALIDATED) {
- if (mParent instanceof View) {
- ((View) mParent).mPrivateFlags |= INVALIDATED;
- }
- mPrivateFlags &= ~DRAWN;
- mPrivateFlags |= DIRTY;
- mPrivateFlags |= INVALIDATED;
- mPrivateFlags &= ~DRAWING_CACHE_VALID;
- if (mParent != null && mAttachInfo != null) {
- if (mAttachInfo.mHardwareAccelerated) {
- mParent.invalidateChild(this, null);
- } else {
- final Rect r = mAttachInfo.mTmpInvalRect;
- r.set(0, 0, mRight - mLeft, mBottom - mTop);
- // Don't call invalidate -- we don't want to internally scroll
- // our own bounds
- mParent.invalidateChild(this, r);
- }
- }
- }
- }
-
- /**
* Used to indicate that the parent of this view should clear its caches. This functionality
* is used to force the parent to rebuild its display list (when hardware-accelerated),
* which is necessary when various parent-managed properties of the view change, such as
@@ -10482,7 +10419,8 @@
// we copy in child display lists into ours in drawChild()
mRecreateDisplayList = true;
if (mDisplayList == null) {
- mDisplayList = mAttachInfo.mHardwareRenderer.createDisplayList();
+ final String name = getClass().getSimpleName();
+ mDisplayList = mAttachInfo.mHardwareRenderer.createDisplayList(name);
// If we're creating a new display list, make sure our parent gets invalidated
// since they will need to recreate their display list to account for this
// new child display list.
@@ -12763,6 +12701,11 @@
ViewDebug.trace(this, ViewDebug.HierarchyTraceType.REQUEST_LAYOUT);
}
+ if (getAccessibilityNodeProvider() != null) {
+ throw new IllegalStateException("Views with AccessibilityNodeProvider"
+ + " can't have children.");
+ }
+
mPrivateFlags |= FORCE_LAYOUT;
mPrivateFlags |= INVALIDATED;
diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java
index 5c63366..d3af618 100644
--- a/core/java/android/view/ViewGroup.java
+++ b/core/java/android/view/ViewGroup.java
@@ -675,11 +675,14 @@
*/
@Override
public void clearFocus() {
- super.clearFocus();
-
- // clear any child focus if it exists
- if (mFocused != null) {
+ if (DBG) {
+ System.out.println(this + " clearFocus()");
+ }
+ if (mFocused == null) {
+ super.clearFocus();
+ } else {
mFocused.clearFocus();
+ mFocused = null;
}
}
@@ -691,12 +694,12 @@
if (DBG) {
System.out.println(this + " unFocus()");
}
-
- super.unFocus();
- if (mFocused != null) {
+ if (mFocused == null) {
+ super.unFocus();
+ } else {
mFocused.unFocus();
+ mFocused = null;
}
- mFocused = null;
}
/**
@@ -888,18 +891,20 @@
}
/**
+ * Called when a view's visibility has changed. Notify the parent to take any appropriate
+ * action.
+ *
+ * @param child The view whose visibility has changed
+ * @param oldVisibility The previous visibility value (GONE, INVISIBLE, or VISIBLE).
+ * @param newVisibility The new visibility value (GONE, INVISIBLE, or VISIBLE).
* @hide
- * @param child
- * @param visibility
*/
- protected void onChildVisibilityChanged(View child, int visibility) {
+ protected void onChildVisibilityChanged(View child, int oldVisibility, int newVisibility) {
if (mTransition != null) {
- if (visibility == VISIBLE) {
- mTransition.showChild(this, child);
+ if (newVisibility == VISIBLE) {
+ mTransition.showChild(this, child, oldVisibility);
} else {
- mTransition.hideChild(this, child);
- }
- if (visibility != VISIBLE) {
+ mTransition.hideChild(this, child, newVisibility);
// Only track this on disappearing views - appearing views are already visible
// and don't need special handling during drawChild()
if (mVisibilityChangingChildren == null) {
@@ -914,7 +919,7 @@
// in all cases, for drags
if (mCurrentDrag != null) {
- if (visibility == VISIBLE) {
+ if (newVisibility == VISIBLE) {
notifyChildOfDrag(child);
}
}
@@ -2661,8 +2666,7 @@
child.onAnimationStart();
}
- more = a.getTransformation(drawingTime, mChildTransformation,
- scalingRequired ? mAttachInfo.mApplicationScale : 1f);
+ more = a.getTransformation(drawingTime, mChildTransformation, 1f);
if (scalingRequired && mAttachInfo.mApplicationScale != 1f) {
if (mInvalidationTransformation == null) {
mInvalidationTransformation = new Transformation();
@@ -3352,6 +3356,11 @@
private void addViewInner(View child, int index, LayoutParams params,
boolean preventRequestLayout) {
+ if (getAccessibilityNodeProvider() != null) {
+ throw new IllegalStateException("Views with AccessibilityNodeProvider"
+ + " can't have children.");
+ }
+
if (mTransition != null) {
// Don't prevent other add transitions from completing, but cancel remove
// transitions to let them complete the process before we add to the container
diff --git a/core/java/android/view/ViewPropertyAnimator.java b/core/java/android/view/ViewPropertyAnimator.java
index 89a1ef2..0fdcd0f 100644
--- a/core/java/android/view/ViewPropertyAnimator.java
+++ b/core/java/android/view/ViewPropertyAnimator.java
@@ -113,6 +113,10 @@
* on that list are added to the list of properties associated with that animator.
*/
ArrayList<NameValuesHolder> mPendingAnimations = new ArrayList<NameValuesHolder>();
+ private Runnable mPendingSetupAction;
+ private Runnable mPendingCleanupAction;
+ private Runnable mPendingOnStartAction;
+ private Runnable mPendingOnEndAction;
/**
* Constants used to associate a property being requested and the mechanism used to set
@@ -199,6 +203,10 @@
*/
private HashMap<Animator, PropertyBundle> mAnimatorMap =
new HashMap<Animator, PropertyBundle>();
+ private HashMap<Animator, Runnable> mAnimatorSetupMap;
+ private HashMap<Animator, Runnable> mAnimatorCleanupMap;
+ private HashMap<Animator, Runnable> mAnimatorOnStartMap;
+ private HashMap<Animator, Runnable> mAnimatorOnEndMap;
/**
* This is the information we need to set each property during the animation.
@@ -614,6 +622,93 @@
}
/**
+ * The View associated with this ViewPropertyAnimator will have its
+ * {@link View#setLayerType(int, android.graphics.Paint) layer type} set to
+ * {@link View#LAYER_TYPE_HARDWARE} for the duration of the next animation. This state
+ * is not persistent, either on the View or on this ViewPropertyAnimator: the layer type
+ * of the View will be restored when the animation ends to what it was when this method was
+ * called, and this setting on ViewPropertyAnimator is only valid for the next animation.
+ * Note that calling this method and then independently setting the layer type of the View
+ * (by a direct call to {@link View#setLayerType(int, android.graphics.Paint)}) will result
+ * in some inconsistency, including having the layer type restored to its pre-withLayer()
+ * value when the animation ends.
+ *
+ * @see View#setLayerType(int, android.graphics.Paint)
+ * @return This object, allowing calls to methods in this class to be chained.
+ */
+ public ViewPropertyAnimator withLayer() {
+ mPendingSetupAction= new Runnable() {
+ @Override
+ public void run() {
+ mView.setLayerType(View.LAYER_TYPE_HARDWARE, null);
+ }
+ };
+ final int currentLayerType = mView.getLayerType();
+ mPendingCleanupAction = new Runnable() {
+ @Override
+ public void run() {
+ mView.setLayerType(currentLayerType, null);
+ }
+ };
+ if (mAnimatorSetupMap == null) {
+ mAnimatorSetupMap = new HashMap<Animator, Runnable>();
+ }
+ if (mAnimatorCleanupMap == null) {
+ mAnimatorCleanupMap = new HashMap<Animator, Runnable>();
+ }
+
+ return this;
+ }
+
+ /**
+ * Specifies an action to take place when the next animation runs. If there is a
+ * {@link #setStartDelay(long) startDelay} set on this ViewPropertyAnimator, then the
+ * action will run after that startDelay expires, when the actual animation begins.
+ * This method, along with {@link #withEndAction(Runnable)}, is intended to help facilitate
+ * choreographing ViewPropertyAnimator animations with other animations or actions
+ * in the application.
+ *
+ * @param runnable The action to run when the next animation starts.
+ * @return This object, allowing calls to methods in this class to be chained.
+ */
+ public ViewPropertyAnimator withStartAction(Runnable runnable) {
+ mPendingOnStartAction = runnable;
+ if (runnable != null && mAnimatorOnStartMap == null) {
+ mAnimatorOnStartMap = new HashMap<Animator, Runnable>();
+ }
+ return this;
+ }
+
+ /**
+ * Specifies an action to take place when the next animation ends. The action is only
+ * run if the animation ends normally; if the ViewPropertyAnimator is canceled during
+ * that animation, the runnable will not run.
+ * This method, along with {@link #withStartAction(Runnable)}, is intended to help facilitate
+ * choreographing ViewPropertyAnimator animations with other animations or actions
+ * in the application.
+ *
+ * <p>For example, the following code animates a view to x=200 and then back to 0:</p>
+ * <pre>
+ * Runnable endAction = new Runnable() {
+ * public void run() {
+ * view.animate().x(0);
+ * }
+ * };
+ * view.animate().x(200).onEnd(endAction);
+ * </pre>
+ *
+ * @param runnable The action to run when the next animation ends.
+ * @return This object, allowing calls to methods in this class to be chained.
+ */
+ public ViewPropertyAnimator withEndAction(Runnable runnable) {
+ mPendingOnEndAction = runnable;
+ if (runnable != null && mAnimatorOnEndMap == null) {
+ mAnimatorOnEndMap = new HashMap<Animator, Runnable>();
+ }
+ return this;
+ }
+
+ /**
* Starts the underlying Animator for a set of properties. We use a single animator that
* simply runs from 0 to 1, and then use that fractional value to set each property
* value accordingly.
@@ -630,6 +725,22 @@
propertyMask |= nameValuesHolder.mNameConstant;
}
mAnimatorMap.put(animator, new PropertyBundle(propertyMask, nameValueList));
+ if (mPendingSetupAction != null) {
+ mAnimatorSetupMap.put(animator, mPendingSetupAction);
+ mPendingSetupAction = null;
+ }
+ if (mPendingCleanupAction != null) {
+ mAnimatorCleanupMap.put(animator, mPendingCleanupAction);
+ mPendingCleanupAction = null;
+ }
+ if (mPendingOnStartAction != null) {
+ mAnimatorOnStartMap.put(animator, mPendingOnStartAction);
+ mPendingOnStartAction = null;
+ }
+ if (mPendingOnEndAction != null) {
+ mAnimatorOnEndMap.put(animator, mPendingOnEndAction);
+ mPendingOnEndAction = null;
+ }
animator.addUpdateListener(mAnimatorEventListener);
animator.addListener(mAnimatorEventListener);
if (mStartDelaySet) {
@@ -800,6 +911,20 @@
implements Animator.AnimatorListener, ValueAnimator.AnimatorUpdateListener {
@Override
public void onAnimationStart(Animator animation) {
+ if (mAnimatorSetupMap != null) {
+ Runnable r = mAnimatorSetupMap.get(animation);
+ if (r != null) {
+ r.run();
+ }
+ mAnimatorSetupMap.remove(animation);
+ }
+ if (mAnimatorOnStartMap != null) {
+ Runnable r = mAnimatorOnStartMap.get(animation);
+ if (r != null) {
+ r.run();
+ }
+ mAnimatorOnStartMap.remove(animation);
+ }
if (mListener != null) {
mListener.onAnimationStart(animation);
}
@@ -810,6 +935,9 @@
if (mListener != null) {
mListener.onAnimationCancel(animation);
}
+ if (mAnimatorOnEndMap != null) {
+ mAnimatorOnEndMap.remove(animation);
+ }
}
@Override
@@ -824,6 +952,20 @@
if (mListener != null) {
mListener.onAnimationEnd(animation);
}
+ if (mAnimatorOnEndMap != null) {
+ Runnable r = mAnimatorOnEndMap.get(animation);
+ if (r != null) {
+ r.run();
+ }
+ mAnimatorOnEndMap.remove(animation);
+ }
+ if (mAnimatorCleanupMap != null) {
+ Runnable r = mAnimatorCleanupMap.get(animation);
+ if (r != null) {
+ r.run();
+ }
+ mAnimatorCleanupMap.remove(animation);
+ }
mAnimatorMap.remove(animation);
}
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 1a4bdf4..cbf4b5a 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -18,11 +18,13 @@
import android.Manifest;
import android.animation.LayoutTransition;
+import android.animation.ValueAnimator;
import android.app.ActivityManagerNative;
import android.content.ClipDescription;
import android.content.ComponentCallbacks;
import android.content.ComponentCallbacks2;
import android.content.Context;
+import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.content.res.CompatibilityInfo;
import android.content.res.Configuration;
@@ -52,6 +54,7 @@
import android.util.DisplayMetrics;
import android.util.EventLog;
import android.util.Log;
+import android.util.LongSparseArray;
import android.util.Pool;
import android.util.Poolable;
import android.util.PoolableManager;
@@ -81,7 +84,6 @@
import java.io.IOException;
import java.io.OutputStream;
-import java.io.PrintWriter;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.List;
@@ -139,6 +141,10 @@
static final ArrayList<ComponentCallbacks> sConfigCallbacks
= new ArrayList<ComponentCallbacks>();
+ private static boolean sUseRenderThread = false;
+ private static boolean sRenderThreadQueried = false;
+ private static final Object[] sRenderThreadQueryLock = new Object[0];
+
long mLastTrackballTime = 0;
final TrackballAxis mTrackballAxisX = new TrackballAxis();
final TrackballAxis mTrackballAxisY = new TrackballAxis();
@@ -168,6 +174,7 @@
View mView;
View mFocusedView;
View mRealFocusedView; // this is not set to null in touch mode
+ View mOldFocusedView;
int mViewVisibility;
boolean mAppVisible = true;
int mOrigWindowType = -1;
@@ -301,6 +308,8 @@
SendWindowContentChangedAccessibilityEvent mSendWindowContentChangedAccessibilityEvent;
+ AccessibilityPrefetchStrategy mAccessibilityPrefetchStrategy;
+
private final int mDensity;
/**
@@ -315,8 +324,11 @@
if (!mInitialized) {
try {
InputMethodManager imm = InputMethodManager.getInstance(mainLooper);
- sWindowSession = Display.getWindowManager().openSession(
+ IWindowManager windowManager = Display.getWindowManager();
+ sWindowSession = windowManager.openSession(
imm.getClient(), imm.getInputContext());
+ float animatorScale = windowManager.getAnimationScale(2);
+ ValueAnimator.setDurationScale(animatorScale);
mInitialized = true;
} catch (RemoteException e) {
}
@@ -377,6 +389,31 @@
mChoreographer = Choreographer.getInstance();
}
+ /**
+ * @return True if the application requests the use of a separate render thread,
+ * false otherwise
+ */
+ private static boolean isRenderThreadRequested(Context context) {
+ synchronized (sRenderThreadQueryLock) {
+ if (!sRenderThreadQueried) {
+ final PackageManager packageManager = context.getPackageManager();
+ final String packageName = context.getApplicationInfo().packageName;
+ try {
+ ApplicationInfo applicationInfo = packageManager.getApplicationInfo(packageName,
+ PackageManager.GET_META_DATA);
+ if (applicationInfo.metaData != null) {
+ sUseRenderThread = applicationInfo.metaData.getBoolean(
+ "android.graphics.renderThread", false);
+ }
+ } catch (PackageManager.NameNotFoundException e) {
+ } finally {
+ sRenderThreadQueried = true;
+ }
+ }
+ return sUseRenderThread;
+ }
+ }
+
public static void addFirstDrawHandler(Runnable callback) {
synchronized (sFirstDrawHandlers) {
if (!sFirstDrawComplete) {
@@ -447,7 +484,7 @@
// If the application owns the surface, don't enable hardware acceleration
if (mSurfaceHolder == null) {
- enableHardwareAcceleration(attrs);
+ enableHardwareAcceleration(mView.getContext(), attrs);
}
boolean restore = false;
@@ -607,7 +644,7 @@
}
}
- private void enableHardwareAcceleration(WindowManager.LayoutParams attrs) {
+ private void enableHardwareAcceleration(Context context, WindowManager.LayoutParams attrs) {
mAttachInfo.mHardwareAccelerated = false;
mAttachInfo.mHardwareAccelerationRequested = false;
@@ -640,20 +677,27 @@
if (!HardwareRenderer.sRendererDisabled || (HardwareRenderer.sSystemRendererDisabled
&& forceHwAccelerated)) {
// Don't enable hardware acceleration when we're not on the main thread
- if (!HardwareRenderer.sSystemRendererDisabled
- && Looper.getMainLooper() != Looper.myLooper()) {
- Log.w(HardwareRenderer.LOG_TAG, "Attempting to initialize hardware "
+ if (!HardwareRenderer.sSystemRendererDisabled &&
+ Looper.getMainLooper() != Looper.myLooper()) {
+ Log.w(HardwareRenderer.LOG_TAG, "Attempting to initialize hardware "
+ "acceleration outside of the main thread, aborting");
return;
}
- final boolean translucent = attrs.format != PixelFormat.OPAQUE;
+ boolean renderThread = isRenderThreadRequested(context);
+ if (renderThread) {
+ Log.i(HardwareRenderer.LOG_TAG, "Render threat initiated");
+ }
+
if (mAttachInfo.mHardwareRenderer != null) {
mAttachInfo.mHardwareRenderer.destroy(true);
- }
+ }
+
+ final boolean translucent = attrs.format != PixelFormat.OPAQUE;
mAttachInfo.mHardwareRenderer = HardwareRenderer.createGlRenderer(2, translucent);
mAttachInfo.mHardwareAccelerated = mAttachInfo.mHardwareAccelerationRequested
= mAttachInfo.mHardwareRenderer != null;
+
} else if (fakeHwAccelerated) {
// The window had wanted to use hardware acceleration, but this
// is not allowed in its process. By setting this flag, it can
@@ -2226,32 +2270,33 @@
public void requestChildFocus(View child, View focused) {
checkThread();
- if (mFocusedView != focused) {
- mAttachInfo.mTreeObserver.dispatchOnGlobalFocusChange(mFocusedView, focused);
- scheduleTraversals();
+
+ if (DEBUG_INPUT_RESIZE) {
+ Log.v(TAG, "Request child focus: focus now " + focused);
}
+
+ mAttachInfo.mTreeObserver.dispatchOnGlobalFocusChange(mOldFocusedView, focused);
+ scheduleTraversals();
+
mFocusedView = mRealFocusedView = focused;
- if (DEBUG_INPUT_RESIZE) Log.v(TAG, "Request child focus: focus now "
- + mFocusedView);
}
public void clearChildFocus(View child) {
checkThread();
- View oldFocus = mFocusedView;
-
- if (DEBUG_INPUT_RESIZE) Log.v(TAG, "Clearing child focus");
- mFocusedView = mRealFocusedView = null;
- if (mView != null && !mView.hasFocus()) {
- // If a view gets the focus, the listener will be invoked from requestChildFocus()
- if (!mView.requestFocus(View.FOCUS_FORWARD)) {
- mAttachInfo.mTreeObserver.dispatchOnGlobalFocusChange(oldFocus, null);
- }
- } else if (oldFocus != null) {
- mAttachInfo.mTreeObserver.dispatchOnGlobalFocusChange(oldFocus, null);
+ if (DEBUG_INPUT_RESIZE) {
+ Log.v(TAG, "Clearing child focus");
}
- }
+ mOldFocusedView = mFocusedView;
+
+ // Invoke the listener only if there is no view to take focus
+ if (focusSearch(null, View.FOCUS_FORWARD) == null) {
+ mAttachInfo.mTreeObserver.dispatchOnGlobalFocusChange(mOldFocusedView, null);
+ }
+
+ mFocusedView = mRealFocusedView = null;
+ }
public void focusableViewAvailable(View v) {
checkThread();
@@ -2724,6 +2769,7 @@
mView.unFocus();
mAttachInfo.mTreeObserver.dispatchOnGlobalFocusChange(focused, null);
mFocusedView = null;
+ mOldFocusedView = null;
return true;
}
}
@@ -3438,11 +3484,11 @@
if (args.localChanges != 0) {
if (mAttachInfo != null) {
mAttachInfo.mSystemUiVisibility =
- (mAttachInfo.mSystemUiVisibility&~args.localChanges)
- | (args.localValue&args.localChanges);
+ (mAttachInfo.mSystemUiVisibility & ~args.localChanges) |
+ (args.localValue & args.localChanges);
+ mAttachInfo.mRecomputeGlobalAttributes = true;
}
mView.updateLocalSystemUiVisibility(args.localValue, args.localChanges);
- mAttachInfo.mRecomputeGlobalAttributes = true;
scheduleTraversals();
}
mView.dispatchSystemUiVisibilityChanged(args.globalVisibility);
@@ -3480,6 +3526,17 @@
return mAccessibilityInteractionController;
}
+ public AccessibilityPrefetchStrategy getAccessibilityPrefetchStrategy() {
+ if (mView == null) {
+ throw new IllegalStateException("getAccessibilityPrefetchStrategy"
+ + " called when there is no mView");
+ }
+ if (mAccessibilityPrefetchStrategy == null) {
+ mAccessibilityPrefetchStrategy = new AccessibilityPrefetchStrategy();
+ }
+ return mAccessibilityPrefetchStrategy;
+ }
+
private int relayoutWindow(WindowManager.LayoutParams params, int viewVisibility,
boolean insetsPending) throws RemoteException {
@@ -3585,7 +3642,7 @@
mView.debug();
}
- public void dumpGfxInfo(PrintWriter pw, int[] info) {
+ public void dumpGfxInfo(int[] info) {
if (mView != null) {
getGfxInfo(mView, info);
} else {
@@ -3697,7 +3754,7 @@
* Represents a pending input event that is waiting in a queue.
*
* Input events are processed in serial order by the timestamp specified by
- * {@link InputEvent#getEventTime()}. In general, the input dispatcher delivers
+ * {@link InputEvent#getEventTimeNano()}. In general, the input dispatcher delivers
* one input event to the application at a time and waits for the application
* to finish handling it before delivering the next one.
*
@@ -3706,7 +3763,7 @@
* needing a queue on the application's side.
*/
private static final class QueuedInputEvent {
- public static final int FLAG_DELIVER_POST_IME = 1 << 0;
+ public static final int FLAG_DELIVER_POST_IME = 1;
public QueuedInputEvent mNext;
@@ -3980,6 +4037,7 @@
if (mView == null) {
return false;
}
+ getAccessibilityPrefetchStrategy().onAccessibilityEvent(event);
mAccessibilityManager.sendAccessibilityEvent(event);
return true;
}
@@ -4539,6 +4597,13 @@
viewRootImpl.getAccessibilityInteractionController()
.findAccessibilityNodeInfoByAccessibilityIdClientThread(accessibilityNodeId,
interactionId, callback, interrogatingPid, interrogatingTid);
+ } else {
+ // We cannot make the call and notify the caller so it does not wait.
+ try {
+ callback.setFindAccessibilityNodeInfosResult(null, interactionId);
+ } catch (RemoteException re) {
+ /* best effort - ignore */
+ }
}
}
@@ -4550,28 +4615,49 @@
viewRootImpl.getAccessibilityInteractionController()
.performAccessibilityActionClientThread(accessibilityNodeId, action,
interactionId, callback, interogatingPid, interrogatingTid);
+ } else {
+ // We cannot make the call and notify the caller so it does not
+ try {
+ callback.setPerformAccessibilityActionResult(false, interactionId);
+ } catch (RemoteException re) {
+ /* best effort - ignore */
+ }
}
}
- public void findAccessibilityNodeInfoByViewId(int viewId,
+ public void findAccessibilityNodeInfoByViewId(long accessibilityNodeId, int viewId,
int interactionId, IAccessibilityInteractionConnectionCallback callback,
int interrogatingPid, long interrogatingTid) {
ViewRootImpl viewRootImpl = mViewRootImpl.get();
if (viewRootImpl != null && viewRootImpl.mView != null) {
viewRootImpl.getAccessibilityInteractionController()
- .findAccessibilityNodeInfoByViewIdClientThread(viewId, interactionId, callback,
- interrogatingPid, interrogatingTid);
- }
- }
-
- public void findAccessibilityNodeInfosByText(String text, long accessibilityNodeId,
- int interactionId, IAccessibilityInteractionConnectionCallback callback,
- int interrogatingPid, long interrogatingTid) {
- ViewRootImpl viewRootImpl = mViewRootImpl.get();
- if (viewRootImpl != null && viewRootImpl.mView != null) {
- viewRootImpl.getAccessibilityInteractionController()
- .findAccessibilityNodeInfosByTextClientThread(text, accessibilityNodeId,
+ .findAccessibilityNodeInfoByViewIdClientThread(accessibilityNodeId, viewId,
interactionId, callback, interrogatingPid, interrogatingTid);
+ } else {
+ // We cannot make the call and notify the caller so it does not
+ try {
+ callback.setFindAccessibilityNodeInfoResult(null, interactionId);
+ } catch (RemoteException re) {
+ /* best effort - ignore */
+ }
+ }
+ }
+
+ public void findAccessibilityNodeInfosByText(long accessibilityNodeId, String text,
+ int interactionId, IAccessibilityInteractionConnectionCallback callback,
+ int interrogatingPid, long interrogatingTid) {
+ ViewRootImpl viewRootImpl = mViewRootImpl.get();
+ if (viewRootImpl != null && viewRootImpl.mView != null) {
+ viewRootImpl.getAccessibilityInteractionController()
+ .findAccessibilityNodeInfosByTextClientThread(accessibilityNodeId, text,
+ interactionId, callback, interrogatingPid, interrogatingTid);
+ } else {
+ // We cannot make the call and notify the caller so it does not
+ try {
+ callback.setFindAccessibilityNodeInfosResult(null, interactionId);
+ } catch (RemoteException re) {
+ /* best effort - ignore */
+ }
}
}
}
@@ -4649,6 +4735,7 @@
long interrogatingTid) {
Message message = Message.obtain();
message.what = DO_FIND_ACCESSIBLITY_NODE_INFO_BY_ACCESSIBILITY_ID;
+ message.arg1 = interrogatingPid;
SomeArgs args = mPool.acquire();
args.argi1 = AccessibilityNodeInfo.getAccessibilityViewId(accessibilityNodeId);
args.argi2 = AccessibilityNodeInfo.getVirtualDescendantId(accessibilityNodeId);
@@ -4671,40 +4758,47 @@
public void findAccessibilityNodeInfoByAccessibilityIdUiThread(Message message) {
SomeArgs args = (SomeArgs) message.obj;
+ final int interrogatingPid = message.arg1;
final int accessibilityViewId = args.argi1;
final int virtualDescendantId = args.argi2;
final int interactionId = args.argi3;
final IAccessibilityInteractionConnectionCallback callback =
(IAccessibilityInteractionConnectionCallback) args.arg1;
mPool.release(args);
- AccessibilityNodeInfo info = null;
+ List<AccessibilityNodeInfo> infos = mTempAccessibilityNodeInfoList;
+ infos.clear();
try {
View target = findViewByAccessibilityId(accessibilityViewId);
if (target != null && target.getVisibility() == View.VISIBLE) {
AccessibilityNodeProvider provider = target.getAccessibilityNodeProvider();
if (provider != null) {
- info = provider.createAccessibilityNodeInfo(virtualDescendantId);
+ infos.add(provider.createAccessibilityNodeInfo(virtualDescendantId));
} else if (virtualDescendantId == View.NO_ID) {
- info = target.createAccessibilityNodeInfo();
+ getAccessibilityPrefetchStrategy().prefetchAccessibilityNodeInfos(
+ interrogatingPid, target, infos);
}
}
} finally {
try {
- callback.setFindAccessibilityNodeInfoResult(info, interactionId);
+ callback.setFindAccessibilityNodeInfosResult(infos, interactionId);
+ infos.clear();
} catch (RemoteException re) {
/* ignore - the other side will time out */
}
}
}
- public void findAccessibilityNodeInfoByViewIdClientThread(int viewId, int interactionId,
- IAccessibilityInteractionConnectionCallback callback, int interrogatingPid,
- long interrogatingTid) {
+ public void findAccessibilityNodeInfoByViewIdClientThread(long accessibilityNodeId,
+ int viewId, int interactionId, IAccessibilityInteractionConnectionCallback callback,
+ int interrogatingPid, long interrogatingTid) {
Message message = Message.obtain();
message.what = DO_FIND_ACCESSIBLITY_NODE_INFO_BY_VIEW_ID;
- message.arg1 = viewId;
- message.arg2 = interactionId;
- message.obj = callback;
+ message.arg1 = AccessibilityNodeInfo.getAccessibilityViewId(accessibilityNodeId);
+ SomeArgs args = mPool.acquire();
+ args.argi1 = viewId;
+ args.argi2 = interactionId;
+ args.arg1 = callback;
+ message.obj = args;
// If the interrogation is performed by the same thread as the main UI
// thread in this process, set the message as a static reference so
// after this call completes the same thread but in the interrogating
@@ -4720,17 +4814,26 @@
}
public void findAccessibilityNodeInfoByViewIdUiThread(Message message) {
- final int viewId = message.arg1;
- final int interactionId = message.arg2;
+ final int accessibilityViewId = message.arg1;
+ SomeArgs args = (SomeArgs) message.obj;
+ final int viewId = args.argi1;
+ final int interactionId = args.argi2;
final IAccessibilityInteractionConnectionCallback callback =
- (IAccessibilityInteractionConnectionCallback) message.obj;
-
+ (IAccessibilityInteractionConnectionCallback) args.arg1;
+ mPool.release(args);
AccessibilityNodeInfo info = null;
try {
- View root = ViewRootImpl.this.mView;
- View target = root.findViewById(viewId);
- if (target != null && target.getVisibility() == View.VISIBLE) {
- info = target.createAccessibilityNodeInfo();
+ View root = null;
+ if (accessibilityViewId != View.NO_ID) {
+ root = findViewByAccessibilityId(accessibilityViewId);
+ } else {
+ root = ViewRootImpl.this.mView;
+ }
+ if (root != null) {
+ View target = root.findViewById(viewId);
+ if (target != null && target.getVisibility() == View.VISIBLE) {
+ info = target.createAccessibilityNodeInfo();
+ }
}
} finally {
try {
@@ -4741,8 +4844,8 @@
}
}
- public void findAccessibilityNodeInfosByTextClientThread(String text,
- long accessibilityNodeId, int interactionId,
+ public void findAccessibilityNodeInfosByTextClientThread(long accessibilityNodeId,
+ String text, int interactionId,
IAccessibilityInteractionConnectionCallback callback, int interrogatingPid,
long interrogatingTid) {
Message message = Message.obtain();
@@ -4779,7 +4882,7 @@
mPool.release(args);
List<AccessibilityNodeInfo> infos = null;
try {
- View target = null;
+ View target;
if (accessibilityViewId != View.NO_ID) {
target = findViewByAccessibilityId(accessibilityViewId);
} else {
@@ -4934,4 +5037,88 @@
}
}
}
+
+ /**
+ * This class encapsulates a prefetching strategy for the accessibility APIs for
+ * querying window content.It is responsible to prefetch a batch of
+ * AccessibilityNodeInfos in addition to the one for a requested node. It caches
+ * the ids of the prefeteched nodes such that they are fetched only once.
+ */
+ class AccessibilityPrefetchStrategy {
+ private static final int MAX_ACCESSIBILITY_NODE_INFO_BATCH_SIZE = 100;
+
+ // We need to keep track of what we have sent for each interrogating
+ // process. Usually there will be only one such process but we
+ // should support the general case. Note that the accessibility event
+ // stream will take care of clearing caches of querying processes that
+ // are not longer alive, so we do not waste memory.
+ private final LongSparseArray<AccessibilityNodeInfoCache> mAccessibilityNodeInfoCaches =
+ new LongSparseArray<AccessibilityNodeInfoCache>();
+
+ private AccessibilityNodeInfoCache getCacheForInterrogatingPid(long interrogatingPid) {
+ AccessibilityNodeInfoCache cache = mAccessibilityNodeInfoCaches.get(interrogatingPid);
+ if (cache == null) {
+ cache = AccessibilityNodeInfoCache.newAccessibilityNodeInfoCache();
+ mAccessibilityNodeInfoCaches.put(interrogatingPid, cache);
+ }
+ return cache;
+ }
+
+ public void onAccessibilityEvent(AccessibilityEvent event) {
+ final int cacheCount = mAccessibilityNodeInfoCaches.size();
+ for (int i = 0; i < cacheCount; i++) {
+ AccessibilityNodeInfoCache cache = mAccessibilityNodeInfoCaches.valueAt(i);
+ cache.onAccessibilityEvent(event);
+ }
+ }
+
+ public void prefetchAccessibilityNodeInfos(long interrogatingPid, View root,
+ List<AccessibilityNodeInfo> outInfos) {
+ addAndCacheNotCachedNodeInfo(interrogatingPid, root, outInfos);
+ addAndCacheNotCachedPredecessorInfos(interrogatingPid, root, outInfos);
+ addAndCacheNotCachedDescendantInfos(interrogatingPid, root, outInfos);
+ }
+
+ private void addAndCacheNotCachedNodeInfo(long interrogatingPid,
+ View view, List<AccessibilityNodeInfo> outInfos) {
+ final long accessibilityNodeId = AccessibilityNodeInfo.makeNodeId(
+ view.getAccessibilityViewId(), View.NO_ID);
+ AccessibilityNodeInfoCache cache = getCacheForInterrogatingPid(interrogatingPid);
+ if (!cache.containsKey(accessibilityNodeId)) {
+ // Account for the ids of the fetched infos. The infos will be
+ // cached in the window querying process. We just need to know
+ // which infos are cached to avoid fetching a cached one again.
+ cache.put(accessibilityNodeId, null);
+ outInfos.add(view.createAccessibilityNodeInfo());
+ }
+ }
+
+ private void addAndCacheNotCachedPredecessorInfos(long interrogatingPid, View view,
+ List<AccessibilityNodeInfo> outInfos) {
+ ViewParent predecessor = view.getParent();
+ while (predecessor instanceof View
+ && outInfos.size() < MAX_ACCESSIBILITY_NODE_INFO_BATCH_SIZE) {
+ View predecessorView = (View) predecessor;
+ addAndCacheNotCachedNodeInfo(interrogatingPid, predecessorView, outInfos);
+ predecessor = predecessor.getParent();
+ }
+ }
+
+ private void addAndCacheNotCachedDescendantInfos(long interrogatingPid, View view,
+ List<AccessibilityNodeInfo> outInfos) {
+ if (outInfos.size() > MAX_ACCESSIBILITY_NODE_INFO_BATCH_SIZE
+ || view.getAccessibilityNodeProvider() != null) {
+ return;
+ }
+ addAndCacheNotCachedNodeInfo(interrogatingPid, view, outInfos);
+ if (view instanceof ViewGroup) {
+ ViewGroup rootGroup = (ViewGroup) view;
+ final int childCount = rootGroup.getChildCount();
+ for (int i = 0; i < childCount; i++) {
+ View child = rootGroup.getChildAt(i);
+ addAndCacheNotCachedDescendantInfos(interrogatingPid, child, outInfos);
+ }
+ }
+ }
+ }
}
diff --git a/core/java/android/view/ViewTreeObserver.java b/core/java/android/view/ViewTreeObserver.java
index c53fc6b..7fd3389 100644
--- a/core/java/android/view/ViewTreeObserver.java
+++ b/core/java/android/view/ViewTreeObserver.java
@@ -185,7 +185,8 @@
mTouchableInsets = TOUCHABLE_INSETS_FRAME;
}
- @Override public boolean equals(Object o) {
+ @Override
+ public boolean equals(Object o) {
try {
if (o == null) {
return false;
@@ -357,10 +358,26 @@
* @param victim The callback to remove
*
* @throws IllegalStateException If {@link #isAlive()} returns false
+ *
+ * @deprecated Use #removeOnGlobalLayoutListener instead
*
* @see #addOnGlobalLayoutListener(OnGlobalLayoutListener)
*/
+ @Deprecated
public void removeGlobalOnLayoutListener(OnGlobalLayoutListener victim) {
+ removeOnGlobalLayoutListener(victim);
+ }
+
+ /**
+ * Remove a previously installed global layout callback
+ *
+ * @param victim The callback to remove
+ *
+ * @throws IllegalStateException If {@link #isAlive()} returns false
+ *
+ * @see #addOnGlobalLayoutListener(OnGlobalLayoutListener)
+ */
+ public void removeOnGlobalLayoutListener(OnGlobalLayoutListener victim) {
checkIsAlive();
if (mOnGlobalLayoutListeners == null) {
return;
diff --git a/core/java/android/view/WindowManagerImpl.java b/core/java/android/view/WindowManagerImpl.java
index d7113374..6bdc4e8 100644
--- a/core/java/android/view/WindowManagerImpl.java
+++ b/core/java/android/view/WindowManagerImpl.java
@@ -490,7 +490,7 @@
for (int i = 0; i < count; i++) {
ViewRootImpl root = mRoots[i];
- root.dumpGfxInfo(pw, info);
+ root.dumpGfxInfo(info);
String name = root.getClass().getName() + '@' +
Integer.toHexString(hashCode());
diff --git a/core/java/android/view/WindowManagerPolicy.java b/core/java/android/view/WindowManagerPolicy.java
index 994565a..6ec2e8d 100644
--- a/core/java/android/view/WindowManagerPolicy.java
+++ b/core/java/android/view/WindowManagerPolicy.java
@@ -1029,6 +1029,11 @@
public boolean hasNavigationBar();
/**
+ * Lock the device now.
+ */
+ public void lockNow();
+
+ /**
* Print the WindowManagerPolicy's state into the given stream.
*
* @param prefix Text to print at the front of each line.
diff --git a/core/java/android/view/accessibility/AccessibilityInteractionClient.java b/core/java/android/view/accessibility/AccessibilityInteractionClient.java
index 95c070c..072fdd8 100644
--- a/core/java/android/view/accessibility/AccessibilityInteractionClient.java
+++ b/core/java/android/view/accessibility/AccessibilityInteractionClient.java
@@ -24,7 +24,9 @@
import android.util.Log;
import android.util.LongSparseArray;
import android.util.SparseArray;
+import android.view.AccessibilityNodeInfoCache;
+import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;
@@ -97,6 +99,11 @@
private static final SparseArray<IAccessibilityServiceConnection> sConnectionCache =
new SparseArray<IAccessibilityServiceConnection>();
+ // The connection cache is shared between all interrogating threads since
+ // at any given time there is only one window allowing querying.
+ private static final AccessibilityNodeInfoCache sAccessibilityNodeInfoCache =
+ AccessibilityNodeInfoCache.newSynchronizedAccessibilityNodeInfoCache();
+
/**
* @return The client for the current thread.
*/
@@ -145,7 +152,9 @@
* Finds an {@link AccessibilityNodeInfo} by accessibility id.
*
* @param connectionId The id of a connection for interacting with the system.
- * @param accessibilityWindowId A unique window id.
+ * @param accessibilityWindowId A unique window id. Use
+ * {@link com.android.server.accessibility.AccessibilityManagerService#ACTIVE_WINDOW_ID}
+ * to query the currently active window.
* @param accessibilityNodeId A unique node accessibility id
* (accessibility view and virtual descendant id).
* @return An {@link AccessibilityNodeInfo} if found, null otherwise.
@@ -155,16 +164,22 @@
try {
IAccessibilityServiceConnection connection = getConnection(connectionId);
if (connection != null) {
+ AccessibilityNodeInfo cachedInfo = sAccessibilityNodeInfoCache.get(accessibilityNodeId);
+ if (cachedInfo != null) {
+ return cachedInfo;
+ }
final int interactionId = mInteractionIdCounter.getAndIncrement();
final float windowScale = connection.findAccessibilityNodeInfoByAccessibilityId(
accessibilityWindowId, accessibilityNodeId, interactionId, this,
Thread.currentThread().getId());
// If the scale is zero the call has failed.
if (windowScale > 0) {
- AccessibilityNodeInfo info = getFindAccessibilityNodeInfoResultAndClear(
+ List<AccessibilityNodeInfo> infos = getFindAccessibilityNodeInfosResultAndClear(
interactionId);
- finalizeAccessibilityNodeInfo(info, connectionId, windowScale);
- return info;
+ finalizeAccessibilityNodeInfos(infos, connectionId, windowScale);
+ if (infos != null && !infos.isEmpty()) {
+ return infos.get(0);
+ }
}
} else {
if (DEBUG) {
@@ -181,22 +196,30 @@
}
/**
- * Finds an {@link AccessibilityNodeInfo} by View id. The search is performed
- * in the currently active window and starts from the root View in the window.
+ * Finds an {@link AccessibilityNodeInfo} by View id. The search is performed in
+ * the window whose id is specified and starts from the node whose accessibility
+ * id is specified.
*
* @param connectionId The id of a connection for interacting with the system.
+ * @param accessibilityWindowId A unique window id. Use
+ * {@link com.android.server.accessibility.AccessibilityManagerService#ACTIVE_WINDOW_ID}
+ * to query the currently active window.
+ * @param accessibilityNodeId A unique view id from where to start the search. Use
+ * {@link com.android.server.accessibility.AccessibilityManagerService#ROOT_NODE_ID}
+ * to start from the root.
* @param viewId The id of the view.
* @return An {@link AccessibilityNodeInfo} if found, null otherwise.
*/
- public AccessibilityNodeInfo findAccessibilityNodeInfoByViewIdInActiveWindow(int connectionId,
- int viewId) {
+ public AccessibilityNodeInfo findAccessibilityNodeInfoByViewId(int connectionId,
+ int accessibilityWindowId, long accessibilityNodeId, int viewId) {
try {
IAccessibilityServiceConnection connection = getConnection(connectionId);
if (connection != null) {
final int interactionId = mInteractionIdCounter.getAndIncrement();
final float windowScale =
- connection.findAccessibilityNodeInfoByViewIdInActiveWindow(viewId,
- interactionId, this, Thread.currentThread().getId());
+ connection.findAccessibilityNodeInfoByViewId(accessibilityWindowId,
+ accessibilityNodeId, viewId, interactionId, this,
+ Thread.currentThread().getId());
// If the scale is zero the call has failed.
if (windowScale > 0) {
AccessibilityNodeInfo info = getFindAccessibilityNodeInfoResultAndClear(
@@ -220,64 +243,27 @@
/**
* Finds {@link AccessibilityNodeInfo}s by View text. The match is case
- * insensitive containment. The search is performed in the currently
- * active window and starts from the root View in the window.
- *
- * @param connectionId The id of a connection for interacting with the system.
- * @param text The searched text.
- * @return A list of found {@link AccessibilityNodeInfo}s.
- */
- public List<AccessibilityNodeInfo> findAccessibilityNodeInfosByTextInActiveWindow(
- int connectionId, String text) {
- try {
- IAccessibilityServiceConnection connection = getConnection(connectionId);
- if (connection != null) {
- final int interactionId = mInteractionIdCounter.getAndIncrement();
- final float windowScale =
- connection.findAccessibilityNodeInfosByTextInActiveWindow(text,
- interactionId, this, Thread.currentThread().getId());
- // If the scale is zero the call has failed.
- if (windowScale > 0) {
- List<AccessibilityNodeInfo> infos = getFindAccessibilityNodeInfosResultAndClear(
- interactionId);
- finalizeAccessibilityNodeInfos(infos, connectionId, windowScale);
- return infos;
- }
- } else {
- if (DEBUG) {
- Log.w(LOG_TAG, "No connection for connection id: " + connectionId);
- }
- }
- } catch (RemoteException re) {
- if (DEBUG) {
- Log.w(LOG_TAG, "Error while calling remote"
- + " findAccessibilityNodeInfosByViewTextInActiveWindow", re);
- }
- }
- return null;
- }
-
- /**
- * Finds {@link AccessibilityNodeInfo}s by View text. The match is case
* insensitive containment. The search is performed in the window whose
- * id is specified and starts from the View whose accessibility id is
+ * id is specified and starts from the node whose accessibility id is
* specified.
*
* @param connectionId The id of a connection for interacting with the system.
+ * @param accessibilityWindowId A unique window id. Use
+ * {@link com.android.server.accessibility.AccessibilityManagerService#ACTIVE_WINDOW_ID}
+ * to query the currently active window.
+ * @param accessibilityNodeId A unique view id from where to start the search. Use
+ * {@link com.android.server.accessibility.AccessibilityManagerService#ROOT_NODE_ID}
* @param text The searched text.
- * @param accessibilityWindowId A unique window id.
- * @param accessibilityNodeId A unique node id (accessibility and virtual descendant id) from
- * where to start the search. Use {@link android.view.View#NO_ID} to start from the root.
* @return A list of found {@link AccessibilityNodeInfo}s.
*/
public List<AccessibilityNodeInfo> findAccessibilityNodeInfosByText(int connectionId,
- String text, int accessibilityWindowId, long accessibilityNodeId) {
+ int accessibilityWindowId, long accessibilityNodeId, String text) {
try {
IAccessibilityServiceConnection connection = getConnection(connectionId);
if (connection != null) {
final int interactionId = mInteractionIdCounter.getAndIncrement();
- final float windowScale = connection.findAccessibilityNodeInfosByText(text,
- accessibilityWindowId, accessibilityNodeId, interactionId, this,
+ final float windowScale = connection.findAccessibilityNodeInfosByText(
+ accessibilityWindowId, accessibilityNodeId, text, interactionId, this,
Thread.currentThread().getId());
// If the scale is zero the call has failed.
if (windowScale > 0) {
@@ -304,7 +290,9 @@
* Performs an accessibility action on an {@link AccessibilityNodeInfo}.
*
* @param connectionId The id of a connection for interacting with the system.
- * @param accessibilityWindowId The id of the window.
+ * @param accessibilityWindowId A unique window id. Use
+ * {@link com.android.server.accessibility.AccessibilityManagerService#ACTIVE_WINDOW_ID}
+ * to query the currently active window.
* @param accessibilityNodeId A unique node id (accessibility and virtual descendant id).
* @param action The action to perform.
* @return Whether the action was performed.
@@ -319,7 +307,7 @@
accessibilityWindowId, accessibilityNodeId, action, interactionId, this,
Thread.currentThread().getId());
if (success) {
- return getPerformAccessibilityActionResult(interactionId);
+ return getPerformAccessibilityActionResultAndClear(interactionId);
}
} else {
if (DEBUG) {
@@ -334,6 +322,24 @@
return false;
}
+ public void clearCache() {
+ if (DEBUG) {
+ Log.w(LOG_TAG, "clearCache()");
+ }
+ sAccessibilityNodeInfoCache.clear();
+ }
+
+ public void removeCachedNode(long accessibilityNodeId) {
+ if (DEBUG) {
+ Log.w(LOG_TAG, "removeCachedNode(" + accessibilityNodeId +")");
+ }
+ sAccessibilityNodeInfoCache.remove(accessibilityNodeId);
+ }
+
+ public void onAccessibilityEvent(AccessibilityEvent event) {
+ sAccessibilityNodeInfoCache.onAccessibilityEvent(event);
+ }
+
/**
* Gets the the result of an async request that returns an {@link AccessibilityNodeInfo}.
*
@@ -358,6 +364,9 @@
if (interactionId > mInteractionId) {
mFindAccessibilityNodeInfoResult = info;
mInteractionId = interactionId;
+ if (info != null) {
+ sAccessibilityNodeInfoCache.put(info.getSourceNodeId(), info);
+ }
}
mInstanceLock.notifyAll();
}
@@ -386,8 +395,20 @@
int interactionId) {
synchronized (mInstanceLock) {
if (interactionId > mInteractionId) {
- mFindAccessibilityNodeInfosResult = infos;
+ // If the call is not an IPC, i.e. it is made from the same process, we need to
+ // instantiate new result list to avoid passing internal instances to clients.
+ final boolean isIpcCall = (queryLocalInterface(getInterfaceDescriptor()) == null);
+ if (!isIpcCall) {
+ mFindAccessibilityNodeInfosResult = new ArrayList<AccessibilityNodeInfo>(infos);
+ } else {
+ mFindAccessibilityNodeInfosResult = infos;
+ }
mInteractionId = interactionId;
+ final int infoCount = infos.size();
+ for (int i = 0; i < infoCount; i ++) {
+ AccessibilityNodeInfo info = infos.get(i);
+ sAccessibilityNodeInfoCache.put(info.getSourceNodeId(), info);
+ }
}
mInstanceLock.notifyAll();
}
@@ -399,7 +420,7 @@
* @param interactionId The interaction id to match the result with the request.
* @return Whether the action was performed.
*/
- private boolean getPerformAccessibilityActionResult(int interactionId) {
+ private boolean getPerformAccessibilityActionResultAndClear(int interactionId) {
synchronized (mInstanceLock) {
final boolean success = waitForResultTimedLocked(interactionId);
final boolean result = success ? mPerformAccessibilityActionResult : false;
diff --git a/core/java/android/view/accessibility/AccessibilityNodeInfo.java b/core/java/android/view/accessibility/AccessibilityNodeInfo.java
index 6939c2c..d7d6792 100644
--- a/core/java/android/view/accessibility/AccessibilityNodeInfo.java
+++ b/core/java/android/view/accessibility/AccessibilityNodeInfo.java
@@ -380,8 +380,8 @@
return Collections.emptyList();
}
AccessibilityInteractionClient client = AccessibilityInteractionClient.getInstance();
- return client.findAccessibilityNodeInfosByText(mConnectionId, text, mWindowId,
- mSourceNodeId);
+ return client.findAccessibilityNodeInfosByText(mConnectionId, mWindowId, mSourceNodeId,
+ text);
}
/**
@@ -903,6 +903,17 @@
}
/**
+ * Gets the id of the source node.
+ *
+ * @return The id.
+ *
+ * @hide
+ */
+ public long getSourceNodeId() {
+ return mSourceNodeId;
+ }
+
+ /**
* Sets if this instance is sealed.
*
* @param sealed Whether is sealed.
diff --git a/core/java/android/view/accessibility/AccessibilityRecord.java b/core/java/android/view/accessibility/AccessibilityRecord.java
index 07aeb9a..b60f50e 100644
--- a/core/java/android/view/accessibility/AccessibilityRecord.java
+++ b/core/java/android/view/accessibility/AccessibilityRecord.java
@@ -564,6 +564,17 @@
}
/**
+ * Gets the id of the source node.
+ *
+ * @return The id.
+ *
+ * @hide
+ */
+ public long getSourceNodeId() {
+ return mSourceNodeId;
+ }
+
+ /**
* Sets the unique id of the IAccessibilityServiceConnection over which
* this instance can send requests to the system.
*
diff --git a/core/java/android/view/accessibility/IAccessibilityInteractionConnection.aidl b/core/java/android/view/accessibility/IAccessibilityInteractionConnection.aidl
index a90c427..ae6869c 100644
--- a/core/java/android/view/accessibility/IAccessibilityInteractionConnection.aidl
+++ b/core/java/android/view/accessibility/IAccessibilityInteractionConnection.aidl
@@ -31,13 +31,13 @@
IAccessibilityInteractionConnectionCallback callback,
int interrogatingPid, long interrogatingTid);
- void findAccessibilityNodeInfoByViewId(int id, int interactionId,
+ void findAccessibilityNodeInfoByViewId(long accessibilityNodeId, int id, int interactionId,
IAccessibilityInteractionConnectionCallback callback,
int interrogatingPid, long interrogatingTid);
- void findAccessibilityNodeInfosByText(String text, long accessibilityNodeId,
- int interactionId, IAccessibilityInteractionConnectionCallback callback,
- int interrogatingPid, long interrogatingTid);
+ void findAccessibilityNodeInfosByText(long accessibilityNodeId, String text, int interactionId,
+ IAccessibilityInteractionConnectionCallback callback, int interrogatingPid,
+ long interrogatingTid);
void performAccessibilityAction(long accessibilityNodeId, int action, int interactionId,
IAccessibilityInteractionConnectionCallback callback, int interrogatingPid,
diff --git a/core/java/android/view/accessibility/IAccessibilityManager.aidl b/core/java/android/view/accessibility/IAccessibilityManager.aidl
index c3794be..320c75d 100644
--- a/core/java/android/view/accessibility/IAccessibilityManager.aidl
+++ b/core/java/android/view/accessibility/IAccessibilityManager.aidl
@@ -49,5 +49,7 @@
void removeAccessibilityInteractionConnection(IWindow windowToken);
- void registerEventListener(IEventListener client);
+ void registerUiTestAutomationService(IEventListener listener, in AccessibilityServiceInfo info);
+
+ void unregisterUiTestAutomationService(IEventListener listener);
}
diff --git a/core/java/android/view/inputmethod/BaseInputConnection.java b/core/java/android/view/inputmethod/BaseInputConnection.java
index 5ec1ec3..bd02d62 100644
--- a/core/java/android/view/inputmethod/BaseInputConnection.java
+++ b/core/java/android/view/inputmethod/BaseInputConnection.java
@@ -193,10 +193,12 @@
/**
* The default implementation performs the deletion around the current
* selection position of the editable text.
+ * @param beforeLength
+ * @param afterLength
*/
- public boolean deleteSurroundingText(int leftLength, int rightLength) {
- if (DEBUG) Log.v(TAG, "deleteSurroundingText " + leftLength
- + " / " + rightLength);
+ public boolean deleteSurroundingText(int beforeLength, int afterLength) {
+ if (DEBUG) Log.v(TAG, "deleteSurroundingText " + beforeLength
+ + " / " + afterLength);
final Editable content = getEditable();
if (content == null) return false;
@@ -226,17 +228,17 @@
int deleted = 0;
- if (leftLength > 0) {
- int start = a - leftLength;
+ if (beforeLength > 0) {
+ int start = a - beforeLength;
if (start < 0) start = 0;
content.delete(start, a);
deleted = a - start;
}
- if (rightLength > 0) {
+ if (afterLength > 0) {
b = b - deleted;
- int end = b + rightLength;
+ int end = b + afterLength;
if (end > content.length()) end = content.length();
content.delete(b, end);
diff --git a/core/java/android/view/inputmethod/InputConnection.java b/core/java/android/view/inputmethod/InputConnection.java
index a6639d1..3563d4d 100644
--- a/core/java/android/view/inputmethod/InputConnection.java
+++ b/core/java/android/view/inputmethod/InputConnection.java
@@ -138,19 +138,21 @@
int flags);
/**
- * Delete <var>leftLength</var> characters of text before the current cursor
- * position, and delete <var>rightLength</var> characters of text after the
- * current cursor position, excluding composing text.
+ * Delete <var>beforeLength</var> characters of text before the current cursor
+ * position, and delete <var>afterLength</var> characters of text after the
+ * current cursor position, excluding composing text. Before and after refer
+ * to the order of the characters in the string, not to their visual representation.
*
- * @param leftLength The number of characters to be deleted before the
+ *
+ * @param beforeLength The number of characters to be deleted before the
* current cursor position.
- * @param rightLength The number of characters to be deleted after the
+ * @param afterLength The number of characters to be deleted after the
* current cursor position.
- *
+ *
* @return Returns true on success, false if the input connection is no longer
* valid.
*/
- public boolean deleteSurroundingText(int leftLength, int rightLength);
+ public boolean deleteSurroundingText(int beforeLength, int afterLength);
/**
* Set composing text around the current cursor position with the given text,
diff --git a/core/java/android/view/inputmethod/InputConnectionWrapper.java b/core/java/android/view/inputmethod/InputConnectionWrapper.java
index 690ea85..a48473e 100644
--- a/core/java/android/view/inputmethod/InputConnectionWrapper.java
+++ b/core/java/android/view/inputmethod/InputConnectionWrapper.java
@@ -62,8 +62,8 @@
return mTarget.getExtractedText(request, flags);
}
- public boolean deleteSurroundingText(int leftLength, int rightLength) {
- return mTarget.deleteSurroundingText(leftLength, rightLength);
+ public boolean deleteSurroundingText(int beforeLength, int afterLength) {
+ return mTarget.deleteSurroundingText(beforeLength, afterLength);
}
public boolean setComposingText(CharSequence text, int newCursorPosition) {
diff --git a/core/java/android/view/inputmethod/InputMethodManager.java b/core/java/android/view/inputmethod/InputMethodManager.java
index b41e6f5..0985e14 100644
--- a/core/java/android/view/inputmethod/InputMethodManager.java
+++ b/core/java/android/view/inputmethod/InputMethodManager.java
@@ -651,19 +651,7 @@
}
}
- if (mServedInputConnection != null) {
- // We need to tell the previously served view that it is no
- // longer the input target, so it can reset its state. Schedule
- // this call on its window's Handler so it will be on the correct
- // thread and outside of our lock.
- Handler vh = mServedView.getHandler();
- if (vh != null) {
- // This will result in a call to reportFinishInputConnection()
- // below.
- vh.sendMessage(vh.obtainMessage(ViewRootImpl.FINISH_INPUT_CONNECTION,
- mServedInputConnection));
- }
- }
+ notifyInputConnectionFinished();
mServedView = null;
mCompletions = null;
@@ -671,7 +659,25 @@
clearConnectionLocked();
}
}
-
+
+ /**
+ * Notifies the served view that the current InputConnection will no longer be used.
+ */
+ private void notifyInputConnectionFinished() {
+ if (mServedView != null && mServedInputConnection != null) {
+ // We need to tell the previously served view that it is no
+ // longer the input target, so it can reset its state. Schedule
+ // this call on its window's Handler so it will be on the correct
+ // thread and outside of our lock.
+ Handler vh = mServedView.getHandler();
+ if (vh != null) {
+ // This will result in a call to reportFinishInputConnection() below.
+ vh.sendMessage(vh.obtainMessage(ViewRootImpl.FINISH_INPUT_CONNECTION,
+ mServedInputConnection));
+ }
+ }
+ }
+
/**
* Called from the FINISH_INPUT_CONNECTION message above.
* @hide
@@ -681,7 +687,7 @@
ic.finishComposingText();
}
}
-
+
public void displayCompletions(View view, CompletionInfo[] completions) {
checkFocus();
synchronized (mH) {
@@ -831,7 +837,7 @@
* shown with {@link #SHOW_FORCED}.
*/
public static final int HIDE_NOT_ALWAYS = 0x0002;
-
+
/**
* Synonym for {@link #hideSoftInputFromWindow(IBinder, int, ResultReceiver)}
* without a result: request to hide the soft input window from the
@@ -993,7 +999,7 @@
tba.fieldId = view.getId();
InputConnection ic = view.onCreateInputConnection(tba);
if (DEBUG) Log.v(TAG, "Starting input: tba=" + tba + " ic=" + ic);
-
+
synchronized (mH) {
// Now that we are locked again, validate that our state hasn't
// changed.
@@ -1012,6 +1018,8 @@
// Hook 'em up and let 'er rip.
mCurrentTextBoxAttribute = tba;
mServedConnecting = false;
+ // Notify the served view that its previous input connection is finished
+ notifyInputConnectionFinished();
mServedInputConnection = ic;
IInputContext servedContext;
if (ic != null) {
@@ -1115,7 +1123,7 @@
}
}
- void scheduleCheckFocusLocked(View view) {
+ static void scheduleCheckFocusLocked(View view) {
Handler vh = view.getHandler();
if (vh != null && !vh.hasMessages(ViewRootImpl.CHECK_FOCUS)) {
// This will result in a call to checkFocus() below.
diff --git a/core/java/android/webkit/Network.java b/core/java/android/webkit/Network.java
index 30bbb04..ee9b949 100644
--- a/core/java/android/webkit/Network.java
+++ b/core/java/android/webkit/Network.java
@@ -169,7 +169,9 @@
if (!ConnectivityManager.CONNECTIVITY_ACTION.equals(intent.getAction()))
return;
- NetworkInfo info = (NetworkInfo)intent.getParcelableExtra(ConnectivityManager.EXTRA_NETWORK_INFO);
+ final ConnectivityManager connManager = (ConnectivityManager) context
+ .getSystemService(Context.CONNECTIVITY_SERVICE);
+ final NetworkInfo info = connManager.getActiveNetworkInfo();
if (info != null)
mRoaming = info.isRoaming();
};
diff --git a/core/java/android/webkit/SelectActionModeCallback.java b/core/java/android/webkit/SelectActionModeCallback.java
index 8c174aa..cdf20f6 100644
--- a/core/java/android/webkit/SelectActionModeCallback.java
+++ b/core/java/android/webkit/SelectActionModeCallback.java
@@ -17,6 +17,7 @@
package android.webkit;
import android.app.SearchManager;
+import android.content.ClipboardManager;
import android.content.Context;
import android.content.Intent;
import android.provider.Browser;
@@ -27,11 +28,16 @@
class SelectActionModeCallback implements ActionMode.Callback {
private WebView mWebView;
private ActionMode mActionMode;
+ private boolean mIsTextSelected = true;
void setWebView(WebView webView) {
mWebView = webView;
}
+ void setTextSelected(boolean isTextSelected) {
+ mIsTextSelected = isTextSelected;
+ }
+
void finish() {
// It is possible that onCreateActionMode was never called, in the case
// where there is no ActionBar, for example.
@@ -52,17 +58,25 @@
mode.setTitle(allowText ?
context.getString(com.android.internal.R.string.textSelectionCABTitle) : null);
- if (!mode.isUiFocusable()) {
- // If the action mode UI we're running in isn't capable of taking window focus
- // the user won't be able to type into the find on page UI. Disable this functionality.
- // (Note that this should only happen in floating dialog windows.)
- // This can be removed once we can handle multiple focusable windows at a time
- // in a better way.
- final MenuItem findOnPageItem = menu.findItem(com.android.internal.R.id.find);
- if (findOnPageItem != null) {
- findOnPageItem.setVisible(false);
- }
- }
+ // If the action mode UI we're running in isn't capable of taking window focus
+ // the user won't be able to type into the find on page UI. Disable this functionality.
+ // (Note that this should only happen in floating dialog windows.)
+ // This can be removed once we can handle multiple focusable windows at a time
+ // in a better way.
+ ClipboardManager cm = (ClipboardManager)(context
+ .getSystemService(Context.CLIPBOARD_SERVICE));
+ boolean isFocusable = mode.isUiFocusable();
+ boolean isEditable = mWebView.focusCandidateIsEditableText();
+ boolean canPaste = isEditable && cm.hasPrimaryClip() && isFocusable;
+ boolean canFind = !isEditable && isFocusable;
+ boolean canCut = isEditable && mIsTextSelected && isFocusable;
+ boolean canCopy = mIsTextSelected;
+ boolean canWebSearch = mIsTextSelected;
+ setMenuVisibility(menu, canFind, com.android.internal.R.id.find);
+ setMenuVisibility(menu, canPaste, com.android.internal.R.id.paste);
+ setMenuVisibility(menu, canCut, com.android.internal.R.id.cut);
+ setMenuVisibility(menu, canCopy, com.android.internal.R.id.copy);
+ setMenuVisibility(menu, canWebSearch, com.android.internal.R.id.websearch);
mActionMode = mode;
return true;
}
@@ -75,11 +89,21 @@
@Override
public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
switch(item.getItemId()) {
+ case android.R.id.cut:
+ mWebView.cutSelection();
+ mode.finish();
+ break;
+
case android.R.id.copy:
mWebView.copySelection();
mode.finish();
break;
+ case android.R.id.paste:
+ mWebView.pasteFromClipboard();
+ mode.finish();
+ break;
+
case com.android.internal.R.id.share:
String selection = mWebView.getSelection();
Browser.sendString(mWebView.getContext(), selection);
@@ -113,4 +137,11 @@
public void onDestroyActionMode(ActionMode mode) {
mWebView.selectionDone();
}
+
+ private void setMenuVisibility(Menu menu, boolean visible, int resourceId) {
+ final MenuItem item = menu.findItem(resourceId);
+ if (item != null) {
+ item.setVisible(visible);
+ }
+ }
}
diff --git a/core/java/android/webkit/WebCoreThreadWatchdog.java b/core/java/android/webkit/WebCoreThreadWatchdog.java
index d100260..0541d5d 100644
--- a/core/java/android/webkit/WebCoreThreadWatchdog.java
+++ b/core/java/android/webkit/WebCoreThreadWatchdog.java
@@ -40,9 +40,6 @@
// WebCore thread unresponsive.
private static final int TIMED_OUT = 101;
- // Message to tell the Watchdog thread to terminate.
- private static final int QUIT = 102;
-
// Wait 10s after hearing back from the WebCore thread before checking it's still alive.
private static final int HEARTBEAT_PERIOD = 10 * 1000;
@@ -57,7 +54,6 @@
private Handler mWebCoreThreadHandler;
private Handler mHandler;
private boolean mPaused;
- private boolean mPendingQuit;
private static WebCoreThreadWatchdog sInstance;
@@ -88,12 +84,6 @@
}
}
- public synchronized static void quit() {
- if (sInstance != null) {
- sInstance.quitWatchdog();
- }
- }
-
private void setContext(Context context) {
mContext = context;
}
@@ -103,19 +93,6 @@
mWebCoreThreadHandler = webCoreThreadHandler;
}
- private void quitWatchdog() {
- if (mHandler == null) {
- // The thread hasn't started yet, so set a flag to stop it starting.
- mPendingQuit = true;
- return;
- }
- // Clear any pending messages, and then post a quit to the WatchDog handler.
- mHandler.removeMessages(TIMED_OUT);
- mHandler.removeMessages(IS_ALIVE);
- mWebCoreThreadHandler.removeMessages(EventHub.HEARTBEAT);
- mHandler.obtainMessage(QUIT).sendToTarget();
- }
-
private void pauseWatchdog() {
mPaused = true;
@@ -146,12 +123,8 @@
mHandler.sendMessageDelayed(mHandler.obtainMessage(TIMED_OUT), TIMEOUT_PERIOD);
}
- private boolean createHandler() {
+ private void createHandler() {
synchronized (WebCoreThreadWatchdog.class) {
- if (mPendingQuit) {
- return false;
- }
-
mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
@@ -206,15 +179,9 @@
.setIcon(android.R.drawable.ic_dialog_alert)
.show();
break;
-
- case QUIT:
- Looper.myLooper().quit();
- break;
}
}
};
-
- return true;
}
}
@@ -222,9 +189,7 @@
public void run() {
Looper.prepare();
- if (!createHandler()) {
- return;
- }
+ createHandler();
// Send the initial control to WebViewCore and start the timeout timer as long as we aren't
// paused.
diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java
index 69c15a6..4a42e92 100644
--- a/core/java/android/webkit/WebView.java
+++ b/core/java/android/webkit/WebView.java
@@ -20,6 +20,7 @@
import android.app.ActivityManager;
import android.app.AlertDialog;
import android.content.BroadcastReceiver;
+import android.content.ClipData;
import android.content.ClipboardManager;
import android.content.ComponentCallbacks2;
import android.content.Context;
@@ -59,6 +60,10 @@
import android.os.SystemClock;
import android.provider.Settings;
import android.speech.tts.TextToSpeech;
+import android.text.Editable;
+import android.text.InputType;
+import android.text.Selection;
+import android.text.TextUtils;
import android.util.AttributeSet;
import android.util.EventLog;
import android.util.Log;
@@ -124,12 +129,6 @@
import java.util.regex.Matcher;
import java.util.regex.Pattern;
-import javax.microedition.khronos.egl.EGL10;
-import javax.microedition.khronos.egl.EGLContext;
-import javax.microedition.khronos.egl.EGLDisplay;
-
-import static javax.microedition.khronos.egl.EGL10.EGL_DEFAULT_DISPLAY;
-
/**
* <p>A View that displays web pages. This class is the basis upon which you
* can roll your own web browser or simply display some online content within your Activity.
@@ -362,39 +361,126 @@
}
/**
- * InputConnection used for ContentEditable. This captures the 'delete'
- * commands and sends delete key presses.
+ * InputConnection used for ContentEditable. This captures changes
+ * to the text and sends them either as key strokes or text changes.
*/
private class WebViewInputConnection extends BaseInputConnection {
+ // Used for mapping characters to keys typed.
+ private KeyCharacterMap mKeyCharacterMap;
+
public WebViewInputConnection() {
- super(WebView.this, false);
+ super(WebView.this, true);
}
- private void sendKeyPress(int keyCode) {
- long eventTime = SystemClock.uptimeMillis();
- sendKeyEvent(new KeyEvent(eventTime, eventTime,
- KeyEvent.ACTION_DOWN, keyCode, 0, 0,
- KeyCharacterMap.VIRTUAL_KEYBOARD, 0,
- KeyEvent.FLAG_SOFT_KEYBOARD));
- sendKeyEvent(new KeyEvent(SystemClock.uptimeMillis(), eventTime,
- KeyEvent.ACTION_UP, keyCode, 0, 0,
- KeyCharacterMap.VIRTUAL_KEYBOARD, 0,
- KeyEvent.FLAG_SOFT_KEYBOARD));
+ @Override
+ public boolean setComposingText(CharSequence text, int newCursorPosition) {
+ Editable editable = getEditable();
+ int start = getComposingSpanStart(editable);
+ int end = getComposingSpanEnd(editable);
+ if (start < 0 || end < 0) {
+ start = Selection.getSelectionStart(editable);
+ end = Selection.getSelectionEnd(editable);
+ }
+ if (end < start) {
+ int temp = end;
+ end = start;
+ start = temp;
+ }
+ setNewText(start, end, text);
+ return super.setComposingText(text, newCursorPosition);
+ }
+
+ @Override
+ public boolean commitText(CharSequence text, int newCursorPosition) {
+ setComposingText(text, newCursorPosition);
+ finishComposingText();
+ return true;
}
@Override
public boolean deleteSurroundingText(int leftLength, int rightLength) {
- // Look for one-character delete and send it as a key press.
- if (leftLength == 1 && rightLength == 0) {
- sendKeyPress(KeyEvent.KEYCODE_DEL);
- } else if (leftLength == 0 && rightLength == 1){
- sendKeyPress(KeyEvent.KEYCODE_FORWARD_DEL);
- } else if (mWebViewCore != null) {
- mWebViewCore.sendMessage(EventHub.DELETE_SURROUNDING_TEXT,
- leftLength, rightLength);
- }
+ Editable editable = getEditable();
+ int cursorPosition = Selection.getSelectionEnd(editable);
+ int startDelete = Math.max(0, cursorPosition - leftLength);
+ int endDelete = Math.min(editable.length(),
+ cursorPosition + rightLength);
+ setNewText(startDelete, endDelete, "");
return super.deleteSurroundingText(leftLength, rightLength);
}
+
+ /**
+ * Sends a text change to webkit indirectly. If it is a single-
+ * character add or delete, it sends it as a key stroke. If it cannot
+ * be represented as a key stroke, it sends it as a field change.
+ * @param start The start offset (inclusive) of the text being changed.
+ * @param end The end offset (exclusive) of the text being changed.
+ * @param text The new text to replace the changed text.
+ */
+ private void setNewText(int start, int end, CharSequence text) {
+ Editable editable = getEditable();
+ CharSequence original = editable.subSequence(start, end);
+ boolean isCharacterAdd = false;
+ boolean isCharacterDelete = false;
+ int textLength = text.length();
+ int originalLength = original.length();
+ if (textLength > originalLength) {
+ isCharacterAdd = (textLength == originalLength + 1)
+ && TextUtils.regionMatches(text, 0, original, 0,
+ originalLength);
+ } else if (originalLength > textLength) {
+ isCharacterDelete = (textLength == originalLength - 1)
+ && TextUtils.regionMatches(text, 0, original, 0,
+ textLength);
+ }
+ if (isCharacterAdd) {
+ sendCharacter(text.charAt(textLength - 1));
+ mTextGeneration++;
+ } else if (isCharacterDelete) {
+ sendDeleteKey();
+ mTextGeneration++;
+ } else if (textLength != originalLength ||
+ !TextUtils.regionMatches(text, 0, original, 0,
+ textLength)) {
+ // Send a message so that key strokes and text replacement
+ // do not come out of order.
+ Message replaceMessage = mPrivateHandler.obtainMessage(
+ REPLACE_TEXT, start, end, text.toString());
+ mPrivateHandler.sendMessage(replaceMessage);
+ }
+ }
+
+ /**
+ * Send a single character to the WebView as a key down and up event.
+ * @param c The character to be sent.
+ */
+ private void sendCharacter(char c) {
+ if (mKeyCharacterMap == null) {
+ mKeyCharacterMap = KeyCharacterMap.load(KeyCharacterMap.VIRTUAL_KEYBOARD);
+ }
+ char[] chars = new char[1];
+ chars[0] = c;
+ KeyEvent[] events = mKeyCharacterMap.getEvents(chars);
+ if (events != null) {
+ for (KeyEvent event : events) {
+ sendKeyEvent(event);
+ }
+ }
+ }
+
+ /**
+ * Send the delete character as a key down and up event.
+ */
+ private void sendDeleteKey() {
+ long eventTime = SystemClock.uptimeMillis();
+ sendKeyEvent(new KeyEvent(eventTime, eventTime,
+ KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_DEL, 0, 0,
+ KeyCharacterMap.VIRTUAL_KEYBOARD, 0,
+ KeyEvent.FLAG_SOFT_KEYBOARD));
+ sendKeyEvent(new KeyEvent(SystemClock.uptimeMillis(), eventTime,
+ KeyEvent.ACTION_UP, KeyEvent.KEYCODE_DEL, 0, 0,
+ KeyCharacterMap.VIRTUAL_KEYBOARD, 0,
+ KeyEvent.FLAG_SOFT_KEYBOARD));
+ }
}
@@ -703,12 +789,18 @@
// know to handle Shift and arrows natively first
private boolean mAccessibilityScriptInjected;
- static final boolean USE_JAVA_TEXT_SELECTION = true;
- static final boolean DEBUG_TEXT_HANDLES = false;
- private Region mTextSelectionRegion = new Region();
- private Paint mTextSelectionPaint;
private Drawable mSelectHandleLeft;
private Drawable mSelectHandleRight;
+ private Rect mSelectCursorBase = new Rect();
+ private int mSelectCursorBaseLayerId;
+ private Rect mSelectCursorExtent = new Rect();
+ private int mSelectCursorExtentLayerId;
+ private Rect mSelectDraggingCursor;
+ private Point mSelectDraggingOffset = new Point();
+ static final int HANDLE_ID_START = 0;
+ static final int HANDLE_ID_END = 1;
+ static final int HANDLE_ID_BASE = 2;
+ static final int HANDLE_ID_EXTENT = 3;
static boolean sDisableNavcache = false;
// the color used to highlight the touch rectangles
@@ -797,6 +889,10 @@
static final int UPDATE_ZOOM_DENSITY = 139;
static final int EXIT_FULLSCREEN_VIDEO = 140;
+ static final int COPY_TO_CLIPBOARD = 141;
+ static final int INIT_EDIT_FIELD = 142;
+ static final int REPLACE_TEXT = 143;
+
private static final int FIRST_PACKAGE_MSG_ID = SCROLL_TO_MSG_ID;
private static final int LAST_PACKAGE_MSG_ID = HIT_TEST_RESULT;
@@ -973,9 +1069,6 @@
private Rect mScrollingLayerBounds = new Rect();
private boolean mSentAutoScrollMessage = false;
- // Temporary hack to work around the context removal upon memory pressure
- private static boolean mIncrementEGLContextHack = false;
-
// used for serializing asynchronously handled touch events.
private final TouchEventQueue mTouchEventQueue = new TouchEventQueue();
@@ -2569,12 +2662,6 @@
return mZoomManager.getScale();
}
- // Called by JNI. Returns the scale to apply to the text selection handles
- /* package */ float getTextHandleScale() {
- float density = mContext.getResources().getDisplayMetrics().density;
- return density / getScale();
- }
-
/**
* Compute the reading level scale of the WebView
* @param scale The current scale.
@@ -3765,6 +3852,16 @@
if (x == mScrollingLayerRect.left && y == mScrollingLayerRect.top) {
return;
}
+ if (mSelectingText) {
+ int dx = mScrollingLayerRect.left - x;
+ int dy = mScrollingLayerRect.top - y;
+ if (mSelectCursorBaseLayerId == mCurrentScrollingLayerId) {
+ mSelectCursorBase.offset(dx, dy);
+ }
+ if (mSelectCursorExtentLayerId == mCurrentScrollingLayerId) {
+ mSelectCursorExtent.offset(dx, dy);
+ }
+ }
nativeScrollLayer(mCurrentScrollingLayerId, x, y);
mScrollingLayerRect.left = x;
mScrollingLayerRect.top = y;
@@ -4382,13 +4479,6 @@
}
if (canvas.isHardwareAccelerated()) {
- if (mIncrementEGLContextHack == false) {
- mIncrementEGLContextHack = true;
- EGL10 egl = (EGL10) EGLContext.getEGL();
- EGLDisplay eglDisplay = egl.eglGetDisplay(EGL_DEFAULT_DISPLAY);
- int[] version = new int[2];
- egl.eglInitialize(eglDisplay, version);
- }
mZoomManager.setHardwareAccelerated();
}
@@ -4520,6 +4610,11 @@
final boolean isSelecting = selectText();
if (isSelecting) {
performHapticFeedback(HapticFeedbackConstants.LONG_PRESS);
+ } else if (focusCandidateIsEditableText()) {
+ mSelectCallback = new SelectActionModeCallback();
+ mSelectCallback.setWebView(this);
+ mSelectCallback.setTextSelected(false);
+ startActionMode(mSelectCallback);
}
return isSelecting;
}
@@ -4539,12 +4634,7 @@
* Select the word at the indicated content coordinates.
*/
boolean selectText(int x, int y) {
- if (!setUpSelect(true, x, y)) {
- return false;
- }
- nativeSetExtendSelection();
- mDrawSelectionPointer = false;
- mTouchMode = TOUCH_DRAG_MODE;
+ mWebViewCore.sendMessage(EventHub.SELECT_WORD_AT, x, y);
return true;
}
@@ -4745,11 +4835,8 @@
int extras = DRAW_EXTRAS_NONE;
if (mFindIsUp) {
extras = DRAW_EXTRAS_FIND;
- } else if (mSelectingText && (!USE_JAVA_TEXT_SELECTION || DEBUG_TEXT_HANDLES)) {
+ } else if (mSelectingText) {
extras = DRAW_EXTRAS_SELECTION;
- nativeSetSelectionPointer(mNativeClass,
- mDrawSelectionPointer,
- mZoomManager.getInvScale(), mSelectX, mSelectY - getTitleHeight());
} else if (drawCursorRing) {
extras = DRAW_EXTRAS_CURSOR_RING;
}
@@ -4794,7 +4881,7 @@
}
canvas.restoreToCount(saveCount);
- if (mSelectingText && USE_JAVA_TEXT_SELECTION) {
+ if (mSelectingText) {
drawTextSelectionHandles(canvas);
}
@@ -4816,30 +4903,12 @@
}
private void drawTextSelectionHandles(Canvas canvas) {
- if (mTextSelectionPaint == null) {
- mTextSelectionPaint = new Paint();
- mTextSelectionPaint.setColor(HIGHLIGHT_COLOR);
- }
- mTextSelectionRegion.setEmpty();
- nativeGetTextSelectionRegion(mNativeClass, mTextSelectionRegion);
- Rect r = new Rect();
- RegionIterator iter = new RegionIterator(mTextSelectionRegion);
- Rect clip = canvas.getClipBounds();
- while (iter.next(r)) {
- r.set(contentToViewDimension(r.left),
- contentToViewDimension(r.top),
- contentToViewDimension(r.right),
- contentToViewDimension(r.bottom));
- if (r.intersect(clip)) {
- canvas.drawRect(r, mTextSelectionPaint);
- }
- }
if (mSelectHandleLeft == null) {
mSelectHandleLeft = mContext.getResources().getDrawable(
com.android.internal.R.drawable.text_select_handle_left);
}
int[] handles = new int[4];
- nativeGetSelectionHandles(mNativeClass, handles);
+ getSelectionHandles(handles);
int start_x = contentToViewDimension(handles[0]);
int start_y = contentToViewDimension(handles[1]);
int end_x = contentToViewDimension(handles[2]);
@@ -4857,14 +4926,31 @@
mSelectHandleRight.setBounds(end_x, end_y,
end_x + mSelectHandleRight.getIntrinsicWidth(),
end_y + mSelectHandleRight.getIntrinsicHeight());
- if (DEBUG_TEXT_HANDLES) {
- mSelectHandleLeft.setAlpha(125);
- mSelectHandleRight.setAlpha(125);
- }
mSelectHandleLeft.draw(canvas);
mSelectHandleRight.draw(canvas);
}
+ /**
+ * Takes an int[4] array as an output param with the values being
+ * startX, startY, endX, endY
+ */
+ private void getSelectionHandles(int[] handles) {
+ handles[0] = mSelectCursorBase.right;
+ handles[1] = mSelectCursorBase.bottom -
+ (mSelectCursorBase.height() / 4);
+ handles[2] = mSelectCursorExtent.left;
+ handles[3] = mSelectCursorExtent.bottom
+ - (mSelectCursorExtent.height() / 4);
+ if (!nativeIsBaseFirst(mNativeClass)) {
+ int swap = handles[0];
+ handles[0] = handles[2];
+ handles[2] = swap;
+ swap = handles[1];
+ handles[1] = handles[3];
+ handles[3] = swap;
+ }
+ }
+
// draw history
private boolean mDrawHistory = false;
private Picture mHistoryPicture = null;
@@ -4924,7 +5010,7 @@
/* package */ void deleteSelection(int start, int end) {
mTextGeneration++;
WebViewCore.TextSelectionData data
- = new WebViewCore.TextSelectionData(start, end);
+ = new WebViewCore.TextSelectionData(start, end, 0);
mWebViewCore.sendMessage(EventHub.DELETE_SELECTION, mTextGeneration, 0,
data);
}
@@ -4943,12 +5029,18 @@
@Override
public InputConnection onCreateInputConnection(EditorInfo outAttrs) {
- outAttrs.imeOptions = EditorInfo.IME_FLAG_NO_FULLSCREEN
+ outAttrs.inputType = EditorInfo.IME_FLAG_NO_FULLSCREEN
| EditorInfo.TYPE_CLASS_TEXT
- | EditorInfo.TYPE_TEXT_VARIATION_NORMAL;
+ | EditorInfo.TYPE_TEXT_VARIATION_WEB_EDIT_TEXT
+ | EditorInfo.TYPE_TEXT_FLAG_MULTI_LINE
+ | EditorInfo.TYPE_TEXT_FLAG_AUTO_CORRECT
+ | EditorInfo.TYPE_TEXT_FLAG_CAP_SENTENCES;
+ outAttrs.imeOptions = EditorInfo.IME_ACTION_NONE;
+
if (mInputConnection == null) {
mInputConnection = new WebViewInputConnection();
}
+ outAttrs.initialCapsMode = mInputConnection.getCursorCapsMode(InputType.TYPE_CLASS_TEXT);
return mInputConnection;
}
@@ -5371,15 +5463,6 @@
return pinScrollTo(mContentWidth, mScrollY, true, 0);
}
}
- if (mSelectingText) {
- int xRate = keyCode == KeyEvent.KEYCODE_DPAD_LEFT
- ? -1 : keyCode == KeyEvent.KEYCODE_DPAD_RIGHT ? 1 : 0;
- int yRate = keyCode == KeyEvent.KEYCODE_DPAD_UP ?
- -1 : keyCode == KeyEvent.KEYCODE_DPAD_DOWN ? 1 : 0;
- int multiplier = event.getRepeatCount() + 1;
- moveSelection(xRate * multiplier, yRate * multiplier);
- return true;
- }
if (navHandledKey(keyCode, 1, false, event.getEventTime())) {
playSoundEffect(keyCodeToSoundsEffect(keyCode));
return true;
@@ -5532,14 +5615,8 @@
mGotCenterDown = false;
if (mSelectingText) {
- if (mExtendSelection) {
- copySelection();
- selectionDone();
- } else {
- mExtendSelection = true;
- nativeSetExtendSelection();
- invalidate(); // draw the i-beam instead of the arrow
- }
+ copySelection();
+ selectionDone();
return true; // discard press if copy in progress
}
@@ -5585,21 +5662,7 @@
return false;
}
- /*
- * Enter selecting text mode, and see if CAB should be shown.
- * Returns true if the WebView is now in
- * selecting text mode (including if it was already in that mode, and this
- * method did nothing).
- */
- private boolean setUpSelect(boolean selectWord, int x, int y) {
- if (0 == mNativeClass) return false; // client isn't initialized
- if (inFullScreenMode()) return false;
- if (mSelectingText) return true;
- nativeResetSelection();
- if (selectWord && !nativeWordSelection(x, y)) {
- selectionDone();
- return false;
- }
+ private boolean startSelectActionMode() {
mSelectCallback = new SelectActionModeCallback();
mSelectCallback.setWebView(this);
if (startActionMode(mSelectCallback) == null) {
@@ -5608,54 +5671,43 @@
selectionDone();
return false;
}
- mExtendSelection = false;
- mSelectingText = mDrawSelectionPointer = true;
- if (DEBUG_TEXT_HANDLES) {
- // Debugging text handles requires running in software mode
- setLayerType(LAYER_TYPE_SOFTWARE, null);
- }
- // don't let the picture change during text selection
- WebViewCore.pauseUpdatePicture(mWebViewCore);
- if (nativeHasCursorNode()) {
- Rect rect = nativeCursorNodeBounds();
- mSelectX = contentToViewX(rect.left);
- mSelectY = contentToViewY(rect.top);
- } else if (mLastTouchY > getVisibleTitleHeightImpl()) {
- mSelectX = mScrollX + mLastTouchX;
- mSelectY = mScrollY + mLastTouchY;
- } else {
- mSelectX = mScrollX + getViewWidth() / 2;
- mSelectY = mScrollY + getViewHeightWithTitle() / 2;
- }
- nativeHideCursor();
- mMinAutoScrollX = 0;
- mMaxAutoScrollX = getViewWidth();
- mMinAutoScrollY = 0;
- mMaxAutoScrollY = getViewHeightWithTitle();
- mCurrentScrollingLayerId = nativeScrollableLayer(viewToContentX(mSelectX),
- viewToContentY(mSelectY), mScrollingLayerRect,
- mScrollingLayerBounds);
- if (mCurrentScrollingLayerId != 0) {
- if (mScrollingLayerRect.left != mScrollingLayerRect.right) {
- mMinAutoScrollX = Math.max(mMinAutoScrollX,
- contentToViewX(mScrollingLayerBounds.left));
- mMaxAutoScrollX = Math.min(mMaxAutoScrollX,
- contentToViewX(mScrollingLayerBounds.right));
- }
- if (mScrollingLayerRect.top != mScrollingLayerRect.bottom) {
- mMinAutoScrollY = Math.max(mMinAutoScrollY,
- contentToViewY(mScrollingLayerBounds.top));
- mMaxAutoScrollY = Math.min(mMaxAutoScrollY,
- contentToViewY(mScrollingLayerBounds.bottom));
- }
- }
- mMinAutoScrollX += SELECT_SCROLL;
- mMaxAutoScrollX -= SELECT_SCROLL;
- mMinAutoScrollY += SELECT_SCROLL;
- mMaxAutoScrollY -= SELECT_SCROLL;
+ performHapticFeedback(HapticFeedbackConstants.LONG_PRESS);
return true;
}
+ private void syncSelectionCursors() {
+ mSelectCursorBaseLayerId =
+ nativeGetHandleLayerId(mNativeClass, HANDLE_ID_BASE, mSelectCursorBase);
+ mSelectCursorExtentLayerId =
+ nativeGetHandleLayerId(mNativeClass, HANDLE_ID_EXTENT, mSelectCursorExtent);
+ }
+
+ private boolean setupWebkitSelect() {
+ syncSelectionCursors();
+ if (!startSelectActionMode()) {
+ selectionDone();
+ return false;
+ }
+ mSelectingText = true;
+ mTouchMode = TOUCH_DRAG_MODE;
+ return true;
+ }
+
+ private void updateWebkitSelection() {
+ int[] handles = null;
+ if (mSelectingText) {
+ handles = new int[4];
+ handles[0] = mSelectCursorBase.centerX();
+ handles[1] = mSelectCursorBase.centerY();
+ handles[2] = mSelectCursorExtent.centerX();
+ handles[3] = mSelectCursorExtent.centerY();
+ } else {
+ nativeSetTextSelection(mNativeClass, 0);
+ }
+ mWebViewCore.removeMessages(EventHub.SELECT_TEXT);
+ mWebViewCore.sendMessageAtFrontOfQueue(EventHub.SELECT_TEXT, handles);
+ }
+
/**
* Use this method to put the WebView into text selection mode.
* Do not rely on this functionality; it will be deprecated in the future.
@@ -5664,7 +5716,6 @@
@Deprecated
public void emulateShiftHeld() {
checkThread();
- setUpSelect(false, 0, 0);
}
/**
@@ -5673,17 +5724,7 @@
* @hide This is an implementation detail.
*/
public void selectAll() {
- if (0 == mNativeClass) return; // client isn't initialized
- if (inFullScreenMode()) return;
- if (!mSelectingText) {
- // retrieve a point somewhere within the text
- Point select = nativeSelectableText();
- if (!selectText(select.x, select.y)) return;
- }
- nativeSelectAll();
- mDrawSelectionPointer = false;
- mExtendSelection = true;
- invalidate();
+ mWebViewCore.sendMessage(EventHub.SELECT_ALL);
}
/**
@@ -5692,17 +5733,11 @@
void selectionDone() {
if (mSelectingText) {
mSelectingText = false;
- if (DEBUG_TEXT_HANDLES) {
- // Debugging text handles required running in software mode, set
- // back to default now
- setLayerType(LAYER_TYPE_NONE, null);
- }
// finish is idempotent, so this is fine even if selectionDone was
// called by mSelectCallback.onDestroyActionMode
mSelectCallback.finish();
mSelectCallback = null;
- WebViewCore.resumePriority();
- WebViewCore.resumeUpdatePicture(mWebViewCore);
+ updateWebkitSelection();
invalidate(); // redraw without selection
mAutoScrollX = 0;
mAutoScrollY = 0;
@@ -5729,12 +5764,49 @@
ClipboardManager cm = (ClipboardManager)getContext()
.getSystemService(Context.CLIPBOARD_SERVICE);
cm.setText(selection);
+ int[] handles = new int[4];
+ getSelectionHandles(handles);
+ mWebViewCore.sendMessage(EventHub.COPY_TEXT, handles);
}
invalidate(); // remove selection region and pointer
return copiedSomething;
}
/**
+ * Cut the selected text into the clipboard
+ *
+ * @hide This is an implementation detail
+ */
+ public void cutSelection() {
+ copySelection();
+ int[] handles = new int[4];
+ getSelectionHandles(handles);
+ mWebViewCore.sendMessage(EventHub.DELETE_TEXT, handles);
+ }
+
+ /**
+ * Paste text from the clipboard to the cursor position.
+ *
+ * @hide This is an implementation detail
+ */
+ public void pasteFromClipboard() {
+ ClipboardManager cm = (ClipboardManager)getContext()
+ .getSystemService(Context.CLIPBOARD_SERVICE);
+ ClipData clipData = cm.getPrimaryClip();
+ if (clipData != null) {
+ ClipData.Item clipItem = clipData.getItemAt(0);
+ CharSequence pasteText = clipItem.getText();
+ if (pasteText != null) {
+ int[] handles = new int[4];
+ getSelectionHandles(handles);
+ mWebViewCore.sendMessage(EventHub.DELETE_TEXT, handles);
+ mWebViewCore.sendMessage(EventHub.INSERT_TEXT,
+ pasteText.toString());
+ }
+ }
+ }
+
+ /**
* @hide This is an implementation detail.
*/
public SearchBox getSearchBox() {
@@ -6278,13 +6350,28 @@
EventLog.writeEvent(EventLogTags.BROWSER_DOUBLE_TAP_DURATION,
(eventTime - mLastTouchUpTime), eventTime);
}
- if (mSelectingText) {
- mDrawSelectionPointer = false;
- mSelectionStarted = nativeStartSelection(contentX, contentY);
+ mSelectionStarted = false;
+ if (mSelectingText && mSelectHandleLeft != null
+ && mSelectHandleRight != null) {
+ int shiftedY = y - getTitleHeight() + mScrollY;
+ int shiftedX = x + mScrollX;
+ if (mSelectHandleLeft.getBounds()
+ .contains(shiftedX, shiftedY)) {
+ mSelectionStarted = true;
+ mSelectDraggingCursor = mSelectCursorBase;
+ } else if (mSelectHandleRight.getBounds()
+ .contains(shiftedX, shiftedY)) {
+ mSelectionStarted = true;
+ mSelectDraggingCursor = mSelectCursorExtent;
+ }
+ if (mSelectDraggingCursor != null) {
+ mSelectDraggingOffset.set(
+ mSelectDraggingCursor.left - contentX,
+ mSelectDraggingCursor.top - contentY);
+ }
if (DebugFlags.WEB_VIEW) {
Log.v(LOGTAG, "select=" + contentX + "," + contentY);
}
- invalidate();
}
}
// Trigger the link
@@ -6350,6 +6437,26 @@
removeTouchHighlight();
}
}
+ if (mSelectingText && mSelectionStarted) {
+ if (DebugFlags.WEB_VIEW) {
+ Log.v(LOGTAG, "extend=" + contentX + "," + contentY);
+ }
+ ViewParent parent = getParent();
+ if (parent != null) {
+ parent.requestDisallowInterceptTouchEvent(true);
+ }
+ if (deltaX != 0 || deltaY != 0) {
+ mSelectDraggingCursor.offsetTo(
+ contentX + mSelectDraggingOffset.x,
+ contentY + mSelectDraggingOffset.y);
+ updateWebkitSelection();
+ mLastTouchX = x;
+ mLastTouchY = y;
+ invalidate();
+ }
+ break;
+ }
+
// pass the touch events from UI thread to WebCore thread
if (shouldForwardTouchEvent() && mConfirmMove && (firstMove
|| eventTime - mLastSentTouchTime > mCurrentTouchInterval)) {
@@ -6392,30 +6499,6 @@
} else {
mVelocityTracker.addMovement(ev);
}
- if (mSelectingText && mSelectionStarted) {
- if (DebugFlags.WEB_VIEW) {
- Log.v(LOGTAG, "extend=" + contentX + "," + contentY);
- }
- ViewParent parent = getParent();
- if (parent != null) {
- parent.requestDisallowInterceptTouchEvent(true);
- }
- mAutoScrollX = x <= mMinAutoScrollX ? -SELECT_SCROLL
- : x >= mMaxAutoScrollX ? SELECT_SCROLL : 0;
- mAutoScrollY = y <= mMinAutoScrollY ? -SELECT_SCROLL
- : y >= mMaxAutoScrollY ? SELECT_SCROLL : 0;
- if ((mAutoScrollX != 0 || mAutoScrollY != 0)
- && !mSentAutoScrollMessage) {
- mSentAutoScrollMessage = true;
- mPrivateHandler.sendEmptyMessageDelayed(
- SCROLL_SELECT_TEXT, SELECT_SCROLL_INTERVAL);
- }
- if (deltaX != 0 || deltaY != 0) {
- nativeExtendSelection(contentX, contentY);
- invalidate();
- }
- break;
- }
if (mTouchMode != TOUCH_DRAG_MODE &&
mTouchMode != TOUCH_DRAG_LAYER_MODE) {
@@ -6630,7 +6713,7 @@
} else {
if (mSelectingText) {
// tapping on selection or controls does nothing
- if (!nativeHitSelection(contentX, contentY)) {
+ if (!mSelectionStarted) {
selectionDone();
}
break;
@@ -6927,6 +7010,12 @@
if (mOverScrollGlow != null) {
mOverScrollGlow.releaseAll();
}
+
+ if (mSelectingText) {
+ mSelectionStarted = false;
+ syncSelectionCursors();
+ invalidate();
+ }
}
private void cancelTouch() {
@@ -6991,8 +7080,6 @@
private int mTrackballYMove = 0;
private boolean mSelectingText = false;
private boolean mSelectionStarted = false;
- private boolean mExtendSelection = false;
- private boolean mDrawSelectionPointer = false;
private static final int TRACKBALL_KEY_TIMEOUT = 1000;
private static final int TRACKBALL_TIMEOUT = 200;
private static final int TRACKBALL_WAIT = 100;
@@ -7061,14 +7148,8 @@
mTrackballDown = false;
mTrackballUpTime = time;
if (mSelectingText) {
- if (mExtendSelection) {
- copySelection();
- selectionDone();
- } else {
- mExtendSelection = true;
- nativeSetExtendSelection();
- invalidate(); // draw the i-beam instead of the arrow
- }
+ copySelection();
+ selectionDone();
return true; // discard press if copy in progress
}
if (DebugFlags.WEB_VIEW) {
@@ -7111,42 +7192,6 @@
return true;
}
- void moveSelection(float xRate, float yRate) {
- if (mNativeClass == 0)
- return;
- int width = getViewWidth();
- int height = getViewHeight();
- mSelectX += xRate;
- mSelectY += yRate;
- int maxX = width + mScrollX;
- int maxY = height + mScrollY;
- mSelectX = Math.min(maxX, Math.max(mScrollX - SELECT_CURSOR_OFFSET
- , mSelectX));
- mSelectY = Math.min(maxY, Math.max(mScrollY - SELECT_CURSOR_OFFSET
- , mSelectY));
- if (DebugFlags.WEB_VIEW) {
- Log.v(LOGTAG, "moveSelection"
- + " mSelectX=" + mSelectX
- + " mSelectY=" + mSelectY
- + " mScrollX=" + mScrollX
- + " mScrollY=" + mScrollY
- + " xRate=" + xRate
- + " yRate=" + yRate
- );
- }
- nativeMoveSelection(viewToContentX(mSelectX), viewToContentY(mSelectY));
- int scrollX = mSelectX < mScrollX ? -SELECT_CURSOR_OFFSET
- : mSelectX > maxX - SELECT_CURSOR_OFFSET ? SELECT_CURSOR_OFFSET
- : 0;
- int scrollY = mSelectY < mScrollY ? -SELECT_CURSOR_OFFSET
- : mSelectY > maxY - SELECT_CURSOR_OFFSET ? SELECT_CURSOR_OFFSET
- : 0;
- pinScrollBy(scrollX, scrollY, true, 0);
- Rect select = new Rect(mSelectX, mSelectY, mSelectX + 1, mSelectY + 1);
- requestRectangleOnScreen(select);
- invalidate();
- }
-
private int scaleTrackballX(float xRate, int width) {
int xMove = (int) (xRate / TRACKBALL_SCALE * width);
int nextXMove = xMove;
@@ -7200,21 +7245,6 @@
float yRate = mTrackballRemainsY * 1000 / elapsed;
int viewWidth = getViewWidth();
int viewHeight = getViewHeight();
- if (mSelectingText) {
- if (!mDrawSelectionPointer) {
- // The last selection was made by touch, disabling drawing the
- // selection pointer. Allow the trackball to adjust the
- // position of the touch control.
- mSelectX = contentToViewX(nativeSelectionX());
- mSelectY = contentToViewY(nativeSelectionY());
- mDrawSelectionPointer = mExtendSelection = true;
- nativeSetExtendSelection();
- }
- moveSelection(scaleTrackballX(xRate, viewWidth),
- scaleTrackballY(yRate, viewHeight));
- mTrackballRemainsX = mTrackballRemainsY = 0;
- return;
- }
float ax = Math.abs(xRate);
float ay = Math.abs(yRate);
float maxA = Math.max(ax, ay);
@@ -8914,6 +8944,35 @@
nativeSelectAt(msg.arg1, msg.arg2);
break;
+ case COPY_TO_CLIPBOARD:
+ copyToClipboard((String) msg.obj);
+ break;
+
+ case INIT_EDIT_FIELD:
+ if (mInputConnection != null) {
+ mTextGeneration = 0;
+ String text = (String)msg.obj;
+ mInputConnection.beginBatchEdit();
+ Editable editable = mInputConnection.getEditable();
+ editable.replace(0, editable.length(), text);
+ int start = msg.arg1;
+ int end = msg.arg2;
+ mInputConnection.setComposingRegion(end, end);
+ mInputConnection.setSelection(start, end);
+ mInputConnection.endBatchEdit();
+ }
+ break;
+
+ case REPLACE_TEXT:{
+ String text = (String)msg.obj;
+ int start = msg.arg1;
+ int end = msg.arg2;
+ int cursorPosition = start + text.length();
+ replaceTextfieldText(start, end, text,
+ cursorPosition, cursorPosition);
+ break;
+ }
+
default:
super.handleMessage(msg);
break;
@@ -9039,11 +9098,26 @@
*/
private void updateTextSelectionFromMessage(int nodePointer,
int textGeneration, WebViewCore.TextSelectionData data) {
- if (inEditingMode()
- && mWebTextView.isSameTextField(nodePointer)
- && textGeneration == mTextGeneration) {
- mWebTextView.setSelectionFromWebKit(data.mStart, data.mEnd);
+ if (textGeneration == mTextGeneration) {
+ if (inEditingMode()
+ && mWebTextView.isSameTextField(nodePointer)) {
+ mWebTextView.setSelectionFromWebKit(data.mStart, data.mEnd);
+ } else if (mInputConnection != null){
+ mInputConnection.setSelection(data.mStart, data.mEnd);
+ }
}
+
+ nativeSetTextSelection(mNativeClass, data.mSelectTextPtr);
+ if (data.mSelectTextPtr != 0) {
+ if (!mSelectingText) {
+ setupWebkitSelect();
+ } else if (!mSelectionStarted) {
+ syncSelectionCursors();
+ }
+ } else {
+ selectionDone();
+ }
+ invalidate();
}
// Class used to use a dropdown for a <select> element
@@ -9592,6 +9666,18 @@
}
/**
+ * Copy text into the clipboard. This is called indirectly from
+ * WebViewCore.
+ * @param text The text to put into the clipboard.
+ */
+ private void copyToClipboard(String text) {
+ ClipboardManager cm = (ClipboardManager)getContext()
+ .getSystemService(Context.CLIPBOARD_SERVICE);
+ ClipData clip = ClipData.newPlainText(getTitle(), text);
+ cm.setPrimaryClip(clip);
+ }
+
+ /**
* Update our cache with updatedText.
* @param updatedText The new text to put in our cache.
* @hide
@@ -9677,6 +9763,23 @@
return nativeTileProfilingGetFloat(frame, tile, key);
}
+ /**
+ * Checks the focused content for an editable text field. This can be
+ * text input or ContentEditable.
+ * @return true if the focused item is an editable text field.
+ */
+ boolean focusCandidateIsEditableText() {
+ boolean isEditable = false;
+ // TODO: reverse sDisableNavcache so that its name is positive
+ boolean isNavcacheEnabled = !sDisableNavcache;
+ if (isNavcacheEnabled) {
+ isEditable = nativeFocusCandidateIsEditableText(mNativeClass);
+ } else if (mFocusedNode != null) {
+ isEditable = mFocusedNode.mEditable;
+ }
+ return isEditable;
+ }
+
private native int nativeCacheHitFramePointer();
private native boolean nativeCacheHitIsPlugin();
private native Rect nativeCacheHitNodeBounds();
@@ -9722,6 +9825,7 @@
/* package */ native boolean nativeFocusCandidateIsPassword();
private native boolean nativeFocusCandidateIsRtlText();
private native boolean nativeFocusCandidateIsTextInput();
+ private native boolean nativeFocusCandidateIsEditableText(int nativeClass);
/* package */ native int nativeFocusCandidateMaxLength();
/* package */ native boolean nativeFocusCandidateIsAutoComplete();
/* package */ native boolean nativeFocusCandidateIsSpellcheck();
@@ -9762,7 +9866,6 @@
private native boolean nativeMoveCursor(int keyCode, int count,
boolean noScroll);
private native int nativeMoveGeneration();
- private native void nativeMoveSelection(int x, int y);
/**
* @return true if the page should get the shift and arrow keys, rather
* than select text/navigation.
@@ -9772,15 +9875,8 @@
*/
private native boolean nativePageShouldHandleShiftAndArrows();
private native boolean nativePointInNavCache(int x, int y, int slop);
- // Like many other of our native methods, you must make sure that
- // mNativeClass is not null before calling this method.
- private native void nativeResetSelection();
- private native Point nativeSelectableText();
- private native void nativeSelectAll();
private native void nativeSelectBestAt(Rect rect);
private native void nativeSelectAt(int x, int y);
- private native int nativeSelectionX();
- private native int nativeSelectionY();
private native int nativeFindIndex();
private native void nativeSetExtendSelection();
private native void nativeSetFindIsEmpty();
@@ -9836,12 +9932,14 @@
private native int nativeGetBackgroundColor();
native boolean nativeSetProperty(String key, String value);
native String nativeGetProperty(String key);
- private native void nativeGetTextSelectionRegion(int instance, Region region);
- private native void nativeGetSelectionHandles(int instance, int[] handles);
/**
* See {@link ComponentCallbacks2} for the trim levels and descriptions
*/
private static native void nativeOnTrimMemory(int level);
private static native void nativeSetPauseDrawing(int instance, boolean pause);
private static native boolean nativeDisableNavcache();
+ private static native void nativeSetTextSelection(int instance, int selection);
+ private static native int nativeGetHandleLayerId(int instance, int handle,
+ Rect cursorLocation);
+ private static native boolean nativeIsBaseFirst(int instance);
}
diff --git a/core/java/android/webkit/WebViewCore.java b/core/java/android/webkit/WebViewCore.java
index c4981e1..395a638 100644
--- a/core/java/android/webkit/WebViewCore.java
+++ b/core/java/android/webkit/WebViewCore.java
@@ -647,18 +647,6 @@
int end, int textGeneration);
/**
- * Delete text near the cursor.
- * @param nativeClass The pointer to the native class (mNativeClass)
- * @param leftLength The number of characters to the left of the cursor to
- * delete
- * @param rightLength The number of characters to the right of the cursor
- * to delete.
- */
- private native void nativeDeleteSurroundingText(int nativeClass,
- int leftLength,
- int rightLength);
-
- /**
* Set the selection to (start, end) in the focused textfield. If start and
* end are out of order, swap them.
* @param nativeClass Pointer to the C++ WebViewCore object mNativeClass
@@ -847,12 +835,14 @@
}
static class TextSelectionData {
- public TextSelectionData(int start, int end) {
+ public TextSelectionData(int start, int end, int selectTextPtr) {
mStart = start;
mEnd = end;
+ mSelectTextPtr = selectTextPtr;
}
int mStart;
int mEnd;
+ int mSelectTextPtr;
}
static class TouchUpData {
@@ -1126,6 +1116,14 @@
// private message ids
private static final int DESTROY = 200;
+ // for cut & paste
+ static final int COPY_TEXT = 210;
+ static final int DELETE_TEXT = 211;
+ static final int INSERT_TEXT = 212;
+ static final int SELECT_TEXT = 213;
+ static final int SELECT_WORD_AT = 214;
+ static final int SELECT_ALL = 215;
+
// Private handler for WebCore messages.
private Handler mHandler;
// Message queue for containing messages before the WebCore thread is
@@ -1201,7 +1199,6 @@
mSettings.onDestroyed();
mNativeClass = 0;
mWebView = null;
- WebCoreThreadWatchdog.quit();
}
break;
@@ -1571,11 +1568,6 @@
deleteSelectionData.mStart, deleteSelectionData.mEnd, msg.arg1);
break;
- case DELETE_SURROUNDING_TEXT:
- nativeDeleteSurroundingText(mNativeClass,
- msg.arg1, msg.arg2);
- break;
-
case SET_SELECTION:
nativeSetSelection(mNativeClass, msg.arg1, msg.arg2);
break;
@@ -1737,6 +1729,47 @@
Rect rect = (Rect) msg.obj;
nativeScrollLayer(mNativeClass, nativeLayer,
rect);
+ break;
+
+ case DELETE_TEXT: {
+ int[] handles = (int[]) msg.obj;
+ nativeDeleteText(mNativeClass, handles[0],
+ handles[1], handles[2], handles[3]);
+ break;
+ }
+ case COPY_TEXT: {
+ int[] handles = (int[]) msg.obj;
+ String copiedText = nativeGetText(mNativeClass,
+ handles[0], handles[1], handles[2],
+ handles[3]);
+ if (copiedText != null) {
+ mWebView.mPrivateHandler.obtainMessage(WebView.COPY_TO_CLIPBOARD, copiedText)
+ .sendToTarget();
+ }
+ break;
+ }
+ case INSERT_TEXT:
+ nativeInsertText(mNativeClass, (String) msg.obj);
+ break;
+ case SELECT_TEXT: {
+ int[] args = (int[]) msg.obj;
+ if (args == null) {
+ nativeClearTextSelection(mNativeClass);
+ } else {
+ nativeSelectText(mNativeClass, args[0],
+ args[1], args[2], args[3]);
+ }
+ break;
+ }
+ case SELECT_WORD_AT: {
+ int x = msg.arg1;
+ int y = msg.arg2;
+ nativeSelectWordAt(mNativeClass, x, y);
+ break;
+ }
+ case SELECT_ALL:
+ nativeSelectAll(mNativeClass);
+ break;
}
}
};
@@ -2690,11 +2723,11 @@
// called by JNI
private void updateTextSelection(int pointer, int start, int end,
- int textGeneration) {
+ int textGeneration, int selectionPtr) {
if (mWebView != null) {
Message.obtain(mWebView.mPrivateHandler,
WebView.UPDATE_TEXT_SELECTION_MSG_ID, pointer, textGeneration,
- new TextSelectionData(start, end)).sendToTarget();
+ new TextSelectionData(start, end, selectionPtr)).sendToTarget();
}
}
@@ -2712,6 +2745,15 @@
WebView.FIND_AGAIN).sendToTarget();
}
+ // called by JNI
+ private void initEditField(String text, int start, int end) {
+ if (mWebView == null) {
+ return;
+ }
+ Message.obtain(mWebView.mPrivateHandler,
+ WebView.INIT_EDIT_FIELD, start, end, text).sendToTarget();
+ }
+
private native void nativeUpdateFrameCacheIfLoading(int nativeClass);
private native void nativeRevealSelection(int nativeClass);
private native String nativeRequestLabel(int nativeClass, int framePtr,
@@ -2752,7 +2794,7 @@
if (mWebView != null) {
Message.obtain(mWebView.mPrivateHandler,
WebView.REQUEST_KEYBOARD_WITH_SELECTION_MSG_ID, pointer,
- textGeneration, new TextSelectionData(selStart, selEnd))
+ textGeneration, new TextSelectionData(selStart, selEnd, 0))
.sendToTarget();
}
}
@@ -2976,4 +3018,40 @@
private native void nativeAutoFillForm(int nativeClass, int queryId);
private native void nativeScrollLayer(int nativeClass, int layer, Rect rect);
+
+ /**
+ * Deletes editable text between two points. Note that the selection may
+ * differ from the WebView's selection because the algorithms for selecting
+ * text differs for non-LTR text. Any text that isn't editable will be
+ * left unchanged.
+ * @param nativeClass The pointer to the native class (mNativeClass)
+ * @param startX The X position of the top-left selection point.
+ * @param startY The Y position of the top-left selection point.
+ * @param endX The X position of the bottom-right selection point.
+ * @param endY The Y position of the bottom-right selection point.
+ */
+ private native void nativeDeleteText(int nativeClass,
+ int startX, int startY, int endX, int endY);
+ /**
+ * Inserts text at the current cursor position. If the currently-focused
+ * node does not have a cursor position then this function does nothing.
+ */
+ private native void nativeInsertText(int nativeClass, String text);
+ /**
+ * Gets the text between two selection points. Note that the selection
+ * may differ from the WebView's selection because the algorithms for
+ * selecting text differs for non-LTR text.
+ * @param nativeClass The pointer to the native class (mNativeClass)
+ * @param startX The X position of the top-left selection point.
+ * @param startY The Y position of the top-left selection point.
+ * @param endX The X position of the bottom-right selection point.
+ * @param endY The Y position of the bottom-right selection point.
+ */
+ private native String nativeGetText(int nativeClass,
+ int startX, int startY, int endX, int endY);
+ private native void nativeSelectText(int nativeClass,
+ int startX, int startY, int endX, int endY);
+ private native void nativeClearTextSelection(int nativeClass);
+ private native void nativeSelectWordAt(int nativeClass, int x, int y);
+ private native void nativeSelectAll(int nativeClass);
}
diff --git a/core/java/android/widget/ActivityChooserView.java b/core/java/android/widget/ActivityChooserView.java
index 60b24bc..be6b4e2 100644
--- a/core/java/android/widget/ActivityChooserView.java
+++ b/core/java/android/widget/ActivityChooserView.java
@@ -33,8 +33,6 @@
import android.view.ViewGroup;
import android.view.ViewTreeObserver;
import android.view.ViewTreeObserver.OnGlobalLayoutListener;
-import android.view.accessibility.AccessibilityEvent;
-import android.view.accessibility.AccessibilityManager;
import android.widget.ActivityChooserModel.ActivityChooserModelClient;
/**
@@ -366,7 +364,7 @@
getListPopupWindow().dismiss();
ViewTreeObserver viewTreeObserver = getViewTreeObserver();
if (viewTreeObserver.isAlive()) {
- viewTreeObserver.removeGlobalOnLayoutListener(mOnGlobalLayoutListener);
+ viewTreeObserver.removeOnGlobalLayoutListener(mOnGlobalLayoutListener);
}
}
return true;
@@ -400,7 +398,7 @@
}
ViewTreeObserver viewTreeObserver = getViewTreeObserver();
if (viewTreeObserver.isAlive()) {
- viewTreeObserver.removeGlobalOnLayoutListener(mOnGlobalLayoutListener);
+ viewTreeObserver.removeOnGlobalLayoutListener(mOnGlobalLayoutListener);
}
mIsAttachedToWindow = false;
}
@@ -547,6 +545,7 @@
position = mAdapter.getShowDefaultActivity() ? position : position + 1;
Intent launchIntent = mAdapter.getDataModel().chooseActivity(position);
if (launchIntent != null) {
+ launchIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET);
mContext.startActivity(launchIntent);
}
}
@@ -564,6 +563,7 @@
final int index = mAdapter.getDataModel().getActivityIndex(defaultActivity);
Intent launchIntent = mAdapter.getDataModel().chooseActivity(index);
if (launchIntent != null) {
+ launchIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET);
mContext.startActivity(launchIntent);
}
} else if (view == mExpandActivityOverflowButton) {
diff --git a/core/java/android/widget/AdapterViewAnimator.java b/core/java/android/widget/AdapterViewAnimator.java
index e226d37..bb00049 100644
--- a/core/java/android/widget/AdapterViewAnimator.java
+++ b/core/java/android/widget/AdapterViewAnimator.java
@@ -558,7 +558,9 @@
mCurrentWindowEnd = newWindowEnd;
mCurrentWindowStartUnbounded = newWindowStartUnbounded;
if (mRemoteViewsAdapter != null) {
- mRemoteViewsAdapter.setVisibleRangeHint(mCurrentWindowStart, mCurrentWindowEnd);
+ int adapterStart = modulo(mCurrentWindowStart, adapterCount);
+ int adapterEnd = modulo(mCurrentWindowEnd, adapterCount);
+ mRemoteViewsAdapter.setVisibleRangeHint(adapterStart, adapterEnd);
}
}
requestLayout();
diff --git a/core/java/android/widget/GridLayout.java b/core/java/android/widget/GridLayout.java
index 7d58011..984ec79 100644
--- a/core/java/android/widget/GridLayout.java
+++ b/core/java/android/widget/GridLayout.java
@@ -842,9 +842,11 @@
* @hide
*/
@Override
- protected void onChildVisibilityChanged(View child, int visibility) {
- super.onChildVisibilityChanged(child, visibility);
- invalidateStructure();
+ protected void onChildVisibilityChanged(View child, int oldVisibility, int newVisibility) {
+ super.onChildVisibilityChanged(child, oldVisibility, newVisibility);
+ if (oldVisibility == GONE || newVisibility == GONE) {
+ invalidateStructure();
+ }
}
// Measurement
diff --git a/core/java/android/widget/ListView.java b/core/java/android/widget/ListView.java
index e20d12a..67fd059 100644
--- a/core/java/android/widget/ListView.java
+++ b/core/java/android/widget/ListView.java
@@ -1651,6 +1651,7 @@
// are focusable
if (mItemsCanFocus && hasFocus() && !sel.hasFocus()) {
final boolean focusWasTaken = (sel == focusLayoutRestoreDirectChild &&
+ focusLayoutRestoreView != null &&
focusLayoutRestoreView.requestFocus()) || sel.requestFocus();
if (!focusWasTaken) {
// selected item didn't take focus, fine, but still want
diff --git a/core/java/android/widget/NumberPicker.java b/core/java/android/widget/NumberPicker.java
index a210f0b..84e86af 100644
--- a/core/java/android/widget/NumberPicker.java
+++ b/core/java/android/widget/NumberPicker.java
@@ -55,14 +55,14 @@
/**
* A widget that enables the user to select a number form a predefined range.
- * The widget presents an input filed and up and down buttons for selecting the
- * current value. Pressing/long pressing the up and down buttons increments and
- * decrements the current value respectively. Touching the input filed shows a
- * scroll wheel, tapping on which while shown and not moving allows direct edit
- * of the current value. Sliding motions up or down hide the buttons and the
- * input filed, show the scroll wheel, and rotate the latter. Flinging is
+ * The widget presents an input field and up and down buttons for selecting the
+ * current value. Pressing/long-pressing the up and down buttons increments and
+ * decrements the current value respectively. Touching the input field shows a
+ * scroll wheel, which when touched allows direct edit
+ * of the current value. Sliding gestures up or down hide the buttons and the
+ * input filed, show and rotate the scroll wheel. Flinging is
* also supported. The widget enables mapping from positions to strings such
- * that instead the position index the corresponding string is displayed.
+ * that, instead of the position index, the corresponding string is displayed.
* <p>
* For an example of using this widget, see {@link android.widget.TimePicker}.
* </p>
@@ -71,6 +71,11 @@
public class NumberPicker extends LinearLayout {
/**
+ * The number of items show in the selector wheel.
+ */
+ public static final int SELECTOR_WHEEL_ITEM_COUNT = 5;
+
+ /**
* The default update interval during long press.
*/
private static final long DEFAULT_LONG_PRESS_UPDATE_INTERVAL = 300;
@@ -1137,14 +1142,17 @@
* items shown on the selector wheel) the selector wheel wrapping is
* enabled.
* </p>
- *
+ * <p>
+ * <strong>Note:</strong> If the number of items, i.e. the range
+ * ({@link #getMaxValue()} - {@link #getMinValue()}) is less than
+ * {@link #SELECTOR_WHEEL_ITEM_COUNT}, the selector wheel will not
+ * wrap. Hence, in such a case calling this method is a NOP.
+ * </p>
* @param wrapSelectorWheel Whether to wrap.
*/
public void setWrapSelectorWheel(boolean wrapSelectorWheel) {
- if (wrapSelectorWheel && (mMaxValue - mMinValue) < mSelectorIndices.length) {
- throw new IllegalStateException("Range less than selector items count.");
- }
- if (wrapSelectorWheel != mWrapSelectorWheel) {
+ final boolean wrappingAllowed = (mMaxValue - mMinValue) >= mSelectorIndices.length;
+ if ((!wrapSelectorWheel || wrappingAllowed) && wrapSelectorWheel != mWrapSelectorWheel) {
mWrapSelectorWheel = wrapSelectorWheel;
updateIncrementAndDecrementButtonsVisibilityState();
}
diff --git a/core/java/android/widget/ShareActionProvider.java b/core/java/android/widget/ShareActionProvider.java
index bb27b73..22e9ef1 100644
--- a/core/java/android/widget/ShareActionProvider.java
+++ b/core/java/android/widget/ShareActionProvider.java
@@ -279,6 +279,7 @@
final int itemId = item.getItemId();
Intent launchIntent = dataModel.chooseActivity(itemId);
if (launchIntent != null) {
+ launchIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET);
mContext.startActivity(launchIntent);
}
return true;
diff --git a/core/java/android/widget/SpellChecker.java b/core/java/android/widget/SpellChecker.java
index a106159..570f0f9 100644
--- a/core/java/android/widget/SpellChecker.java
+++ b/core/java/android/widget/SpellChecker.java
@@ -102,7 +102,8 @@
mTextServicesManager = (TextServicesManager) mTextView.getContext().
getSystemService(Context.TEXT_SERVICES_MANAGER_SERVICE);
- if (!mTextServicesManager.isSpellCheckerEnabled()) {
+ if (!mTextServicesManager.isSpellCheckerEnabled()
+ || mTextServicesManager.getCurrentSpellCheckerSubtype(true) == null) {
mSpellCheckerSession = null;
} else {
mSpellCheckerSession = mTextServicesManager.newSpellCheckerSession(
@@ -341,56 +342,15 @@
final int end = editable.getSpanEnd(spellCheckSpan);
if (start < 0 || end <= start) return; // span was removed in the meantime
- // Other suggestion spans may exist on that region, with identical suggestions, filter
- // them out to avoid duplicates.
- SuggestionSpan[] suggestionSpans = editable.getSpans(start, end, SuggestionSpan.class);
- final int length = suggestionSpans.length;
- for (int i = 0; i < length; i++) {
- final int spanStart = editable.getSpanStart(suggestionSpans[i]);
- final int spanEnd = editable.getSpanEnd(suggestionSpans[i]);
- if (spanStart != start || spanEnd != end) {
- // Nulled (to avoid new array allocation) if not on that exact same region
- suggestionSpans[i] = null;
- }
- }
-
final int suggestionsCount = suggestionsInfo.getSuggestionsCount();
- String[] suggestions;
if (suggestionsCount <= 0) {
// A negative suggestion count is possible
- suggestions = ArrayUtils.emptyArray(String.class);
- } else {
- int numberOfSuggestions = 0;
- suggestions = new String[suggestionsCount];
+ return;
+ }
- for (int i = 0; i < suggestionsCount; i++) {
- final String spellSuggestion = suggestionsInfo.getSuggestionAt(i);
- if (spellSuggestion == null) break;
- boolean suggestionFound = false;
-
- for (int j = 0; j < length && !suggestionFound; j++) {
- if (suggestionSpans[j] == null) break;
-
- String[] suggests = suggestionSpans[j].getSuggestions();
- for (int k = 0; k < suggests.length; k++) {
- if (spellSuggestion.equals(suggests[k])) {
- // The suggestion is already provided by an other SuggestionSpan
- suggestionFound = true;
- break;
- }
- }
- }
-
- if (!suggestionFound) {
- suggestions[numberOfSuggestions++] = spellSuggestion;
- }
- }
-
- if (numberOfSuggestions != suggestionsCount) {
- String[] newSuggestions = new String[numberOfSuggestions];
- System.arraycopy(suggestions, 0, newSuggestions, 0, numberOfSuggestions);
- suggestions = newSuggestions;
- }
+ String[] suggestions = new String[suggestionsCount];
+ for (int i = 0; i < suggestionsCount; i++) {
+ suggestions[i] = suggestionsInfo.getSuggestionAt(i);
}
SuggestionSpan suggestionSpan = new SuggestionSpan(mTextView.getContext(), suggestions,
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index f78c247..164bc64 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -256,10 +256,7 @@
private float mShadowRadius, mShadowDx, mShadowDy;
- private static final int PREDRAW_NOT_REGISTERED = 0;
- private static final int PREDRAW_PENDING = 1;
- private static final int PREDRAW_DONE = 2;
- private int mPreDrawState = PREDRAW_NOT_REGISTERED;
+ private boolean mPreDrawRegistered;
private TextUtils.TruncateAt mEllipsize = null;
@@ -342,6 +339,7 @@
private int mTextEditSuggestionItemLayout;
private SuggestionsPopupWindow mSuggestionsPopupWindow;
private SuggestionRangeSpan mSuggestionRangeSpan;
+ private Runnable mShowSuggestionRunnable;
private int mCursorDrawableRes;
private final Drawable[] mCursorDrawable = new Drawable[2];
@@ -364,8 +362,6 @@
private SpellChecker mSpellChecker;
- private boolean mSoftInputShownOnFocus = true;
-
// The alignment to pass to Layout, or null if not resolved.
private Layout.Alignment mLayoutAlignment;
@@ -2383,29 +2379,6 @@
}
/**
- * Sets whether the soft input method will be made visible when this
- * TextView gets focused. The default is true.
- *
- * @attr ref android.R.styleable#TextView_softInputShownOnFocus
- * @hide
- */
- @android.view.RemotableViewMethod
- public final void setSoftInputShownOnFocus(boolean show) {
- mSoftInputShownOnFocus = show;
- }
-
- /**
- * Returns whether the soft input method will be made visible when this
- * TextView gets focused. The default is true.
- *
- * @attr ref android.R.styleable#TextView_softInputShownOnFocus
- * @hide
- */
- public final boolean getSoftInputShownOnFocus() {
- return mSoftInputShownOnFocus;
- }
-
- /**
* Returns the list of URLSpans attached to the text
* (by {@link Linkify} or otherwise) if any. You can call
* {@link URLSpan#getURL} on them to find where they link to
@@ -4386,26 +4359,16 @@
}
private void registerForPreDraw() {
- final ViewTreeObserver observer = getViewTreeObserver();
-
- if (mPreDrawState == PREDRAW_NOT_REGISTERED) {
- observer.addOnPreDrawListener(this);
- mPreDrawState = PREDRAW_PENDING;
- } else if (mPreDrawState == PREDRAW_DONE) {
- mPreDrawState = PREDRAW_PENDING;
+ if (!mPreDrawRegistered) {
+ getViewTreeObserver().addOnPreDrawListener(this);
+ mPreDrawRegistered = true;
}
-
- // else state is PREDRAW_PENDING, so keep waiting.
}
/**
* {@inheritDoc}
*/
public boolean onPreDraw() {
- if (mPreDrawState != PREDRAW_PENDING) {
- return true;
- }
-
if (mLayout == null) {
assumeLayout();
}
@@ -4456,7 +4419,9 @@
startSelectionActionMode();
}
- mPreDrawState = PREDRAW_DONE;
+ getViewTreeObserver().removeOnPreDrawListener(this);
+ mPreDrawRegistered = false;
+
return !changed;
}
@@ -4491,10 +4456,9 @@
protected void onDetachedFromWindow() {
super.onDetachedFromWindow();
- final ViewTreeObserver observer = getViewTreeObserver();
- if (mPreDrawState != PREDRAW_NOT_REGISTERED) {
- observer.removeOnPreDrawListener(this);
- mPreDrawState = PREDRAW_NOT_REGISTERED;
+ if (mPreDrawRegistered) {
+ getViewTreeObserver().removeOnPreDrawListener(this);
+ mPreDrawRegistered = false;
}
if (mError != null) {
@@ -4513,6 +4477,10 @@
mSelectionModifierCursorController.onDetached();
}
+ if (mShowSuggestionRunnable != null) {
+ removeCallbacks(mShowSuggestionRunnable);
+ }
+
hideControllers();
resetResolvedDrawables();
@@ -4763,12 +4731,6 @@
@Override
protected void onDraw(Canvas canvas) {
- if (mPreDrawState == PREDRAW_DONE) {
- final ViewTreeObserver observer = getViewTreeObserver();
- observer.removeOnPreDrawListener(this);
- mPreDrawState = PREDRAW_NOT_REGISTERED;
- }
-
if (mCurrentAlpha <= ViewConfiguration.ALPHA_THRESHOLD_INT) return;
restartMarqueeIfNeeded();
@@ -5035,7 +4997,7 @@
if (mTextDisplayList == null || !mTextDisplayList.isValid() ||
!mTextDisplayListIsValid) {
if (mTextDisplayList == null) {
- mTextDisplayList = getHardwareRenderer().createDisplayList();
+ mTextDisplayList = getHardwareRenderer().createDisplayList("Text");
}
final HardwareCanvas hardwareCanvas = mTextDisplayList.start();
@@ -5534,7 +5496,7 @@
&& mLayout != null && onCheckIsTextEditor()) {
InputMethodManager imm = InputMethodManager.peekInstance();
viewClicked(imm);
- if (imm != null && mSoftInputShownOnFocus) {
+ if (imm != null) {
imm.showSoftInput(this, 0);
}
}
@@ -6790,6 +6752,12 @@
}
}
+ @Override
+ protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
+ super.onLayout(changed, left, top, right, bottom);
+ if (changed) mTextDisplayListIsValid = false;
+ }
+
/**
* Returns true if anything changed.
*/
@@ -8330,6 +8298,10 @@
getSelectionController().onTouchEvent(event);
}
+ if (mShowSuggestionRunnable != null) {
+ removeCallbacks(mShowSuggestionRunnable);
+ }
+
if (action == MotionEvent.ACTION_DOWN) {
mLastDownPositionX = event.getX();
mLastDownPositionY = event.getY();
@@ -8370,34 +8342,41 @@
ClickableSpan[] links = ((Spannable) mText).getSpans(getSelectionStart(),
getSelectionEnd(), ClickableSpan.class);
- if (links.length != 0) {
+ if (links.length > 0) {
links[0].onClick(this);
handled = true;
}
}
if (touchIsFinished && (isTextEditable() || mTextIsSelectable)) {
- // Move cursor
- final int offset = getOffsetForPosition(event.getX(), event.getY());
- Selection.setSelection((Spannable) mText, offset);
-
// Show the IME, except when selecting in read-only text.
final InputMethodManager imm = InputMethodManager.peekInstance();
viewClicked(imm);
- if (!mTextIsSelectable && mSoftInputShownOnFocus) {
+ if (!mTextIsSelectable) {
handled |= imm != null && imm.showSoftInput(this, 0);
}
boolean selectAllGotFocus = mSelectAllOnFocus && didTouchFocusSelect();
hideControllers();
if (!selectAllGotFocus && mText.length() > 0) {
+ // Move cursor
+ final int offset = getOffsetForPosition(event.getX(), event.getY());
+ Selection.setSelection((Spannable) mText, offset);
if (mSpellChecker != null) {
// When the cursor moves, the word that was typed may need spell check
mSpellChecker.onSelectionChanged();
}
if (!extractedTextModeWillBeStarted()) {
if (isCursorInsideEasyCorrectionSpan()) {
- showSuggestions();
+ if (mShowSuggestionRunnable == null) {
+ mShowSuggestionRunnable = new Runnable() {
+ public void run() {
+ showSuggestions();
+ }
+ };
+ }
+ postDelayed(mShowSuggestionRunnable,
+ ViewConfiguration.getDoubleTapTimeout());
} else if (hasInsertionController()) {
getInsertionController().show();
}
@@ -9732,11 +9711,12 @@
public void show() {
if (!(mText instanceof Editable)) return;
- updateSuggestions();
- mCursorWasVisibleBeforeSuggestions = mCursorVisible;
- setCursorVisible(false);
- mIsShowingUp = true;
- super.show();
+ if (updateSuggestions()) {
+ mCursorWasVisibleBeforeSuggestions = mCursorVisible;
+ setCursorVisible(false);
+ mIsShowingUp = true;
+ super.show();
+ }
}
@Override
@@ -9792,11 +9772,13 @@
super.hide();
}
- private void updateSuggestions() {
+ private boolean updateSuggestions() {
Spannable spannable = (Spannable) TextView.this.mText;
SuggestionSpan[] suggestionSpans = getSuggestionSpans();
final int nbSpans = suggestionSpans.length;
+ // Suggestions are shown after a delay: the underlying spans may have been removed
+ if (nbSpans == 0) return false;
mNumberOfSuggestions = 0;
int spanUnionStart = mText.length();
@@ -9822,17 +9804,34 @@
String[] suggestions = suggestionSpan.getSuggestions();
int nbSuggestions = suggestions.length;
for (int suggestionIndex = 0; suggestionIndex < nbSuggestions; suggestionIndex++) {
- SuggestionInfo suggestionInfo = mSuggestionInfos[mNumberOfSuggestions];
- suggestionInfo.suggestionSpan = suggestionSpan;
- suggestionInfo.suggestionIndex = suggestionIndex;
- suggestionInfo.text.replace(0, suggestionInfo.text.length(),
- suggestions[suggestionIndex]);
+ String suggestion = suggestions[suggestionIndex];
- mNumberOfSuggestions++;
- if (mNumberOfSuggestions == MAX_NUMBER_SUGGESTIONS) {
- // Also end outer for loop
- spanIndex = nbSpans;
- break;
+ boolean suggestionIsDuplicate = false;
+ for (int i = 0; i < mNumberOfSuggestions; i++) {
+ if (mSuggestionInfos[i].text.toString().equals(suggestion)) {
+ SuggestionSpan otherSuggestionSpan = mSuggestionInfos[i].suggestionSpan;
+ final int otherSpanStart = spannable.getSpanStart(otherSuggestionSpan);
+ final int otherSpanEnd = spannable.getSpanEnd(otherSuggestionSpan);
+ if (spanStart == otherSpanStart && spanEnd == otherSpanEnd) {
+ suggestionIsDuplicate = true;
+ break;
+ }
+ }
+ }
+
+ if (!suggestionIsDuplicate) {
+ SuggestionInfo suggestionInfo = mSuggestionInfos[mNumberOfSuggestions];
+ suggestionInfo.suggestionSpan = suggestionSpan;
+ suggestionInfo.suggestionIndex = suggestionIndex;
+ suggestionInfo.text.replace(0, suggestionInfo.text.length(), suggestion);
+
+ mNumberOfSuggestions++;
+
+ if (mNumberOfSuggestions == MAX_NUMBER_SUGGESTIONS) {
+ // Also end outer for loop
+ spanIndex = nbSpans;
+ break;
+ }
}
}
}
@@ -9841,7 +9840,7 @@
highlightTextDifferences(mSuggestionInfos[i], spanUnionStart, spanUnionEnd);
}
- // Add to dictionary item if there is a span with the misspelled flag
+ // Add "Add to dictionary" item if there is a span with the misspelled flag
if (misspelledSpan != null) {
final int misspelledStart = spannable.getSpanStart(misspelledSpan);
final int misspelledEnd = spannable.getSpanEnd(misspelledSpan);
@@ -9882,6 +9881,7 @@
Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
mSuggestionsAdapter.notifyDataSetChanged();
+ return true;
}
private void highlightTextDifferences(SuggestionInfo suggestionInfo, int unionStart,
@@ -9899,8 +9899,9 @@
suggestionInfo.text.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
// Add the text before and after the span.
- suggestionInfo.text.insert(0, mText.toString().substring(unionStart, spanStart));
- suggestionInfo.text.append(mText.toString().substring(spanEnd, unionEnd));
+ final String textAsString = text.toString();
+ suggestionInfo.text.insert(0, textAsString.substring(unionStart, spanStart));
+ suggestionInfo.text.append(textAsString.substring(spanEnd, unionEnd));
}
@Override
@@ -10146,7 +10147,7 @@
}
final boolean selectionStarted = mSelectionActionMode != null || willExtract;
- if (selectionStarted && !mTextIsSelectable && mSoftInputShownOnFocus) {
+ if (selectionStarted && !mTextIsSelectable) {
// Show the IME to be able to replace text, except when selecting non editable text.
final InputMethodManager imm = InputMethodManager.peekInstance();
if (imm != null) {
diff --git a/core/java/com/android/internal/os/ZygoteInit.java b/core/java/com/android/internal/os/ZygoteInit.java
index 9c45dc6..6a99a2b 100644
--- a/core/java/com/android/internal/os/ZygoteInit.java
+++ b/core/java/com/android/internal/os/ZygoteInit.java
@@ -243,7 +243,7 @@
private static void preloadClasses() {
final VMRuntime runtime = VMRuntime.getRuntime();
- InputStream is = ZygoteInit.class.getClassLoader().getResourceAsStream(
+ InputStream is = ClassLoader.getSystemClassLoader().getResourceAsStream(
PRELOADED_CLASSES);
if (is == null) {
Log.e(TAG, "Couldn't find " + PRELOADED_CLASSES + ".");
diff --git a/core/java/com/android/internal/util/ArrayUtils.java b/core/java/com/android/internal/util/ArrayUtils.java
index edeb2a8..d1aa1ce 100644
--- a/core/java/com/android/internal/util/ArrayUtils.java
+++ b/core/java/com/android/internal/util/ArrayUtils.java
@@ -142,6 +142,14 @@
return false;
}
+ public static long total(long[] array) {
+ long total = 0;
+ for (long value : array) {
+ total += value;
+ }
+ return total;
+ }
+
/**
* Appends an element to a copy of the array and returns the copy.
* @param array The original array, or null to represent an empty array.
diff --git a/core/java/com/android/internal/util/FastMath.java b/core/java/com/android/internal/util/FastMath.java
index efd0871..88a17e6 100644
--- a/core/java/com/android/internal/util/FastMath.java
+++ b/core/java/com/android/internal/util/FastMath.java
@@ -26,8 +26,8 @@
* thought it may return slightly different results. It does not try to
* handle (in any meaningful way) NaN or infinities.
*/
- public static int round(float x) {
- long lx = (long)(x * (65536 * 256f));
- return (int)((lx + 0x800000) >> 24);
+ public static int round(float value) {
+ long lx = (long) (value * (65536 * 256f));
+ return (int) ((lx + 0x800000) >> 24);
}
}
diff --git a/core/java/com/android/internal/util/FileRotator.java b/core/java/com/android/internal/util/FileRotator.java
index 3ce95e7..8a8f315 100644
--- a/core/java/com/android/internal/util/FileRotator.java
+++ b/core/java/com/android/internal/util/FileRotator.java
@@ -17,9 +17,9 @@
package com.android.internal.util;
import android.os.FileUtils;
+import android.util.Slog;
-import com.android.internal.util.FileRotator.Reader;
-import com.android.internal.util.FileRotator.Writer;
+import com.android.internal.util.FileRotator.Rewriter;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
@@ -41,12 +41,15 @@
* Instead of manipulating files directly, users implement interfaces that
* perform operations on {@link InputStream} and {@link OutputStream}. This
* enables atomic rewriting of file contents in
- * {@link #combineActive(Reader, Writer, long)}.
+ * {@link #rewriteActive(Rewriter, long)}.
* <p>
* Users must periodically call {@link #maybeRotate(long)} to perform actual
* rotation. Not inherently thread safe.
*/
public class FileRotator {
+ private static final String TAG = "FileRotator";
+ private static final boolean LOGD = true;
+
private final File mBasePath;
private final String mPrefix;
private final long mRotateAgeMillis;
@@ -73,6 +76,15 @@
}
/**
+ * External class that reads existing data from given {@link InputStream},
+ * then writes any modified data to {@link OutputStream}.
+ */
+ public interface Rewriter extends Reader, Writer {
+ public void reset();
+ public boolean shouldWrite();
+ }
+
+ /**
* Create a file rotator.
*
* @param basePath Directory under which all files will be placed.
@@ -96,6 +108,8 @@
if (!name.startsWith(mPrefix)) continue;
if (name.endsWith(SUFFIX_BACKUP)) {
+ if (LOGD) Slog.d(TAG, "recovering " + name);
+
final File backupFile = new File(mBasePath, name);
final File file = new File(
mBasePath, name.substring(0, name.length() - SUFFIX_BACKUP.length()));
@@ -104,6 +118,8 @@
backupFile.renameTo(file);
} else if (name.endsWith(SUFFIX_NO_BACKUP)) {
+ if (LOGD) Slog.d(TAG, "recovering " + name);
+
final File noBackupFile = new File(mBasePath, name);
final File file = new File(
mBasePath, name.substring(0, name.length() - SUFFIX_NO_BACKUP.length()));
@@ -116,26 +132,95 @@
}
/**
- * Atomically combine data with existing data in currently active file.
- * Maintains a backup during write, which is restored if the write fails.
+ * Delete all files managed by this rotator.
*/
- public void combineActive(Reader reader, Writer writer, long currentTimeMillis)
+ public void deleteAll() {
+ final FileInfo info = new FileInfo(mPrefix);
+ for (String name : mBasePath.list()) {
+ if (!info.parse(name)) continue;
+
+ // delete each file that matches parser
+ new File(mBasePath, name).delete();
+ }
+ }
+
+ /**
+ * Process currently active file, first reading any existing data, then
+ * writing modified data. Maintains a backup during write, which is restored
+ * if the write fails.
+ */
+ public void rewriteActive(Rewriter rewriter, long currentTimeMillis)
throws IOException {
final String activeName = getActiveName(currentTimeMillis);
+ rewriteSingle(rewriter, activeName);
+ }
- final File file = new File(mBasePath, activeName);
+ @Deprecated
+ public void combineActive(final Reader reader, final Writer writer, long currentTimeMillis)
+ throws IOException {
+ rewriteActive(new Rewriter() {
+ /** {@inheritDoc} */
+ public void reset() {
+ // ignored
+ }
+
+ /** {@inheritDoc} */
+ public void read(InputStream in) throws IOException {
+ reader.read(in);
+ }
+
+ /** {@inheritDoc} */
+ public boolean shouldWrite() {
+ return true;
+ }
+
+ /** {@inheritDoc} */
+ public void write(OutputStream out) throws IOException {
+ writer.write(out);
+ }
+ }, currentTimeMillis);
+ }
+
+ /**
+ * Process all files managed by this rotator, usually to rewrite historical
+ * data. Each file is processed atomically.
+ */
+ public void rewriteAll(Rewriter rewriter) throws IOException {
+ final FileInfo info = new FileInfo(mPrefix);
+ for (String name : mBasePath.list()) {
+ if (!info.parse(name)) continue;
+
+ // process each file that matches parser
+ rewriteSingle(rewriter, name);
+ }
+ }
+
+ /**
+ * Process a single file atomically, first reading any existing data, then
+ * writing modified data. Maintains a backup during write, which is restored
+ * if the write fails.
+ */
+ private void rewriteSingle(Rewriter rewriter, String name) throws IOException {
+ if (LOGD) Slog.d(TAG, "rewriting " + name);
+
+ final File file = new File(mBasePath, name);
final File backupFile;
+ rewriter.reset();
+
if (file.exists()) {
// read existing data
- readFile(file, reader);
+ readFile(file, rewriter);
+
+ // skip when rewriter has nothing to write
+ if (!rewriter.shouldWrite()) return;
// backup existing data during write
- backupFile = new File(mBasePath, activeName + SUFFIX_BACKUP);
+ backupFile = new File(mBasePath, name + SUFFIX_BACKUP);
file.renameTo(backupFile);
try {
- writeFile(file, writer);
+ writeFile(file, rewriter);
// write success, delete backup
backupFile.delete();
@@ -148,11 +233,11 @@
} else {
// create empty backup during write
- backupFile = new File(mBasePath, activeName + SUFFIX_NO_BACKUP);
+ backupFile = new File(mBasePath, name + SUFFIX_NO_BACKUP);
backupFile.createNewFile();
try {
- writeFile(file, writer);
+ writeFile(file, rewriter);
// write success, delete empty backup
backupFile.delete();
@@ -176,6 +261,8 @@
// read file when it overlaps
if (info.startMillis <= matchEndMillis && matchStartMillis <= info.endMillis) {
+ if (LOGD) Slog.d(TAG, "reading matching " + name);
+
final File file = new File(mBasePath, name);
readFile(file, reader);
}
@@ -224,16 +311,20 @@
if (!info.parse(name)) continue;
if (info.isActive()) {
- // found active file; rotate if old enough
- if (info.startMillis < rotateBefore) {
+ if (info.startMillis <= rotateBefore) {
+ // found active file; rotate if old enough
+ if (LOGD) Slog.d(TAG, "rotating " + name);
+
info.endMillis = currentTimeMillis;
final File file = new File(mBasePath, name);
final File destFile = new File(mBasePath, info.build());
file.renameTo(destFile);
}
- } else if (info.endMillis < deleteBefore) {
+ } else if (info.endMillis <= deleteBefore) {
// found rotated file; delete if old enough
+ if (LOGD) Slog.d(TAG, "deleting " + name);
+
final File file = new File(mBasePath, name);
file.delete();
}
diff --git a/core/java/com/android/internal/util/IndentingPrintWriter.java b/core/java/com/android/internal/util/IndentingPrintWriter.java
new file mode 100644
index 0000000..3dd2284
--- /dev/null
+++ b/core/java/com/android/internal/util/IndentingPrintWriter.java
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.util;
+
+import java.io.PrintWriter;
+import java.io.Writer;
+
+/**
+ * Lightweight wrapper around {@link PrintWriter} that automatically indents
+ * newlines based on internal state. Delays writing indent until first actual
+ * write on a newline, enabling indent modification after newline.
+ */
+public class IndentingPrintWriter extends PrintWriter {
+ private final String mIndent;
+
+ private StringBuilder mBuilder = new StringBuilder();
+ private String mCurrent = new String();
+ private boolean mEmptyLine = true;
+
+ public IndentingPrintWriter(Writer writer, String indent) {
+ super(writer);
+ mIndent = indent;
+ }
+
+ public void increaseIndent() {
+ mBuilder.append(mIndent);
+ mCurrent = mBuilder.toString();
+ }
+
+ public void decreaseIndent() {
+ mBuilder.delete(0, mIndent.length());
+ mCurrent = mBuilder.toString();
+ }
+
+ @Override
+ public void println() {
+ super.println();
+ mEmptyLine = true;
+ }
+
+ @Override
+ public void write(char[] buf, int offset, int count) {
+ if (mEmptyLine) {
+ mEmptyLine = false;
+ super.print(mCurrent);
+ }
+ super.write(buf, offset, count);
+ }
+}
diff --git a/core/java/com/android/internal/view/InputConnectionWrapper.java b/core/java/com/android/internal/view/InputConnectionWrapper.java
index a235d9a..9024d8d 100644
--- a/core/java/com/android/internal/view/InputConnectionWrapper.java
+++ b/core/java/com/android/internal/view/InputConnectionWrapper.java
@@ -387,9 +387,9 @@
}
}
- public boolean deleteSurroundingText(int leftLength, int rightLength) {
+ public boolean deleteSurroundingText(int beforeLength, int afterLength) {
try {
- mIInputContext.deleteSurroundingText(leftLength, rightLength);
+ mIInputContext.deleteSurroundingText(beforeLength, afterLength);
return true;
} catch (RemoteException e) {
return false;
diff --git a/core/java/com/android/internal/widget/DigitalClock.java b/core/java/com/android/internal/widget/DigitalClock.java
index daefc9a..af3fd42 100644
--- a/core/java/com/android/internal/widget/DigitalClock.java
+++ b/core/java/com/android/internal/widget/DigitalClock.java
@@ -228,7 +228,7 @@
updateTime();
}
- private void updateTime() {
+ public void updateTime() {
mCalendar.setTimeInMillis(System.currentTimeMillis());
CharSequence newTime = DateFormat.format(mFormat, mCalendar);
diff --git a/core/java/com/android/internal/widget/EditableInputConnection.java b/core/java/com/android/internal/widget/EditableInputConnection.java
index 32e733b..9579bce 100644
--- a/core/java/com/android/internal/widget/EditableInputConnection.java
+++ b/core/java/com/android/internal/widget/EditableInputConnection.java
@@ -35,6 +35,11 @@
private final TextView mTextView;
+ // Keeps track of nested begin/end batch edit to ensure this connection always has a
+ // balanced impact on its associated TextView.
+ // A negative value means that this connection has been finished by the InputMethodManager.
+ private int mBatchEditNesting;
+
public EditableInputConnection(TextView textview) {
super(textview, true);
mTextView = textview;
@@ -48,19 +53,35 @@
}
return null;
}
-
+
@Override
public boolean beginBatchEdit() {
- mTextView.beginBatchEdit();
- return true;
+ synchronized(this) {
+ if (mBatchEditNesting >= 0) {
+ mTextView.beginBatchEdit();
+ mBatchEditNesting++;
+ return true;
+ }
+ }
+ return false;
}
-
+
@Override
public boolean endBatchEdit() {
- mTextView.endBatchEdit();
- return true;
+ synchronized(this) {
+ if (mBatchEditNesting > 0) {
+ // When the connection is reset by the InputMethodManager and finishComposingText
+ // is called, some endBatchEdit calls may still be asynchronously received from the
+ // IME. Do not take these into account, thus ensuring that this IC's final
+ // contribution to mTextView's nested batch edit count is zero.
+ mTextView.endBatchEdit();
+ mBatchEditNesting--;
+ return true;
+ }
+ }
+ return false;
}
-
+
@Override
public boolean clearMetaKeyStates(int states) {
final Editable content = getEditable();
@@ -76,7 +97,24 @@
}
return true;
}
-
+
+ @Override
+ public boolean finishComposingText() {
+ final boolean superResult = super.finishComposingText();
+ synchronized(this) {
+ if (mBatchEditNesting < 0) {
+ // The connection was already finished
+ return false;
+ }
+ while (mBatchEditNesting > 0) {
+ endBatchEdit();
+ }
+ // Will prevent any further calls to begin or endBatchEdit
+ mBatchEditNesting = -1;
+ }
+ return superResult;
+ }
+
@Override
public boolean commitCompletion(CompletionInfo text) {
if (DEBUG) Log.v(TAG, "commitCompletion " + text);
diff --git a/core/java/com/android/internal/widget/LockPatternUtils.java b/core/java/com/android/internal/widget/LockPatternUtils.java
index 905a171..6893ffb 100644
--- a/core/java/com/android/internal/widget/LockPatternUtils.java
+++ b/core/java/com/android/internal/widget/LockPatternUtils.java
@@ -404,7 +404,7 @@
saveLockPassword(null, DevicePolicyManager.PASSWORD_QUALITY_SOMETHING);
setLockPatternEnabled(false);
saveLockPattern(null);
- setLong(PASSWORD_TYPE_KEY, DevicePolicyManager.PASSWORD_QUALITY_SOMETHING);
+ setLong(PASSWORD_TYPE_KEY, DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED);
setLong(PASSWORD_TYPE_ALTERNATE_KEY, DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED);
}
diff --git a/core/java/com/android/internal/widget/multiwaveview/MultiWaveView.java b/core/java/com/android/internal/widget/multiwaveview/MultiWaveView.java
index ebd355a..d51ced11 100644
--- a/core/java/com/android/internal/widget/multiwaveview/MultiWaveView.java
+++ b/core/java/com/android/internal/widget/multiwaveview/MultiWaveView.java
@@ -653,6 +653,7 @@
case MotionEvent.ACTION_CANCEL:
handleMove(event);
+ handleCancel(event);
handled = true;
break;
}
@@ -678,6 +679,12 @@
if (DEBUG && mDragging) Log.v(TAG, "** Handle RELEASE");
switchToState(STATE_FINISH, event.getX(), event.getY());
}
+
+ private void handleCancel(MotionEvent event) {
+ if (DEBUG && mDragging) Log.v(TAG, "** Handle CANCEL");
+ mActiveTarget = -1; // Drop the active target if canceled.
+ switchToState(STATE_FINISH, event.getX(), event.getY());
+ }
private void handleMove(MotionEvent event) {
if (!mDragging) {
diff --git a/core/jni/android/graphics/Canvas.cpp b/core/jni/android/graphics/Canvas.cpp
index 3e9ab86..23ee8f8 100644
--- a/core/jni/android/graphics/Canvas.cpp
+++ b/core/jni/android/graphics/Canvas.cpp
@@ -757,28 +757,16 @@
int start, int count, int contextCount,
jfloat x, jfloat y, int flags, SkPaint* paint) {
- sp<TextLayoutCacheValue> value;
-#if USE_TEXT_LAYOUT_CACHE
- value = TextLayoutCache::getInstance().getValue(paint, textArray, start, count,
- contextCount, flags);
+ sp<TextLayoutValue> value = TextLayoutEngine::getInstance().getValue(paint,
+ textArray, start, count, contextCount, flags);
if (value == NULL) {
- ALOGE("Cannot get TextLayoutCache value for text = '%s'",
- String8(textArray + start, count).string());
- return ;
+ return;
}
-#else
- value = new TextLayoutCacheValue(contextCount);
- TextLayoutEngine::getInstance().computeValues(value.get(), paint,
- reinterpret_cast<const UChar*>(textArray), start, count, contextCount, flags);
-#endif
doDrawGlyphs(canvas, value->getGlyphs(), 0, value->getGlyphsCount(), x, y, flags, paint);
}
static void doDrawGlyphs(SkCanvas* canvas, const jchar* glyphArray, int index, int count,
jfloat x, jfloat y, int flags, SkPaint* paint) {
- // TODO: need to suppress this code after the GL renderer is modified for not
- // copying the paint
-
// Beware: this needs Glyph encoding (already done on the Paint constructor)
canvas->drawText(glyphArray + index * 2, count * 2, x, y, *paint);
}
diff --git a/core/jni/android/graphics/Paint.cpp b/core/jni/android/graphics/Paint.cpp
index 9f3238ab..376c841 100644
--- a/core/jni/android/graphics/Paint.cpp
+++ b/core/jni/android/graphics/Paint.cpp
@@ -465,10 +465,10 @@
jchar* glyphsArray = env->GetCharArrayElements(glyphs, NULL);
- TextLayoutCacheValue value(contextCount);
- TextLayoutEngine::getInstance().computeValues(&value, paint, text, start, count, contextCount, flags);
- const jchar* shapedGlyphs = value.getGlyphs();
- size_t glyphsCount = value.getGlyphsCount();
+ sp<TextLayoutValue> value = TextLayoutEngine::getInstance().getValue(paint,
+ text, start, count, contextCount, flags);
+ const jchar* shapedGlyphs = value->getGlyphs();
+ size_t glyphsCount = value->getGlyphsCount();
memcpy(glyphsArray, shapedGlyphs, sizeof(jchar) * glyphsCount);
env->ReleaseCharArrayElements(glyphs, glyphsArray, JNI_ABORT);
@@ -673,13 +673,16 @@
}
}
- static int breakText(JNIEnv* env, const SkPaint& paint, const jchar text[],
+ static int breakText(JNIEnv* env, SkPaint& paint, const jchar text[],
int count, float maxWidth, jfloatArray jmeasured,
SkPaint::TextBufferDirection tbd) {
- SkASSERT(paint.getTextEncoding() == SkPaint::kUTF16_TextEncoding);
-
+ sp<TextLayoutValue> value = TextLayoutEngine::getInstance().getValue(&paint,
+ text, 0, count, count, paint.getFlags());
+ if (value == NULL) {
+ return 0;
+ }
SkScalar measured;
- size_t bytes = paint.breakText(text, count << 1,
+ size_t bytes = paint.breakText(value->getGlyphs(), value->getGlyphsCount() << 1,
SkFloatToScalar(maxWidth), &measured, tbd);
SkASSERT((bytes & 1) == 0);
@@ -743,7 +746,12 @@
SkRect r;
SkIRect ir;
- paint.measureText(text, count << 1, &r);
+ sp<TextLayoutValue> value = TextLayoutEngine::getInstance().getValue(&paint,
+ text, 0, count, count, paint.getFlags());
+ if (value == NULL) {
+ return;
+ }
+ paint.measureText(value->getGlyphs(), value->getGlyphsCount() << 1, &r);
r.roundOut(&ir);
GraphicsJNI::irect_to_jrect(ir, env, bounds);
}
diff --git a/core/jni/android/graphics/TextLayout.cpp b/core/jni/android/graphics/TextLayout.cpp
index 2d83851..2241f60 100644
--- a/core/jni/android/graphics/TextLayout.cpp
+++ b/core/jni/android/graphics/TextLayout.cpp
@@ -53,19 +53,9 @@
// a path representing the text that would have been drawn.
void TextLayout::handleText(SkPaint *paint, const jchar* text, jsize len,
jint bidiFlags, jfloat x, jfloat y, SkPath *path) {
- sp<TextLayoutCacheValue> value;
-#if USE_TEXT_LAYOUT_CACHE
- // Return advances from the cache. Compute them if needed
- value = TextLayoutCache::getInstance().getValue(paint, text, 0, len,
- len, bidiFlags);
-#else
- value = new TextLayoutCacheValue(len);
- TextLayoutEngine::getInstance().computeValues(value.get(), paint,
- reinterpret_cast<const UChar*>(text), 0, len, len, bidiFlags);
-#endif
+ sp<TextLayoutValue> value = TextLayoutEngine::getInstance().getValue(paint,
+ text, 0, len, len, bidiFlags);
if (value == NULL) {
- ALOGE("Cannot get TextLayoutCache value for text = '%s'",
- String8(text, len).string());
return ;
}
SkScalar x_ = SkFloatToScalar(x);
@@ -77,19 +67,9 @@
void TextLayout::getTextRunAdvances(SkPaint* paint, const jchar* chars, jint start,
jint count, jint contextCount, jint dirFlags,
jfloat* resultAdvances, jfloat* resultTotalAdvance) {
- sp<TextLayoutCacheValue> value;
-#if USE_TEXT_LAYOUT_CACHE
- // Return advances from the cache. Compute them if needed
- value = TextLayoutCache::getInstance().getValue(paint, chars, start, count,
- contextCount, dirFlags);
-#else
- value = new TextLayoutCacheValue(contextCount);
- TextLayoutEngine::getInstance().computeValues(value.get(), paint,
- reinterpret_cast<const UChar*>(chars), start, count, contextCount, dirFlags);
-#endif
+ sp<TextLayoutValue> value = TextLayoutEngine::getInstance().getValue(paint,
+ chars, start, count, contextCount, dirFlags);
if (value == NULL) {
- ALOGE("Cannot get TextLayoutCache value for text = '%s'",
- String8(chars + start, count).string());
return ;
}
if (resultAdvances) {
@@ -126,20 +106,12 @@
return;
}
- sp<TextLayoutCacheValue> value;
-#if USE_TEXT_LAYOUT_CACHE
- value = TextLayoutCache::getInstance().getValue(paint, text, 0, count,
- count, bidiFlags);
-#else
- value = new TextLayoutCacheValue(count);
- TextLayoutEngine::getInstance().computeValues(value.get(), paint,
- reinterpret_cast<const UChar*>(text), 0, count, count, bidiFlags);
-#endif
+ sp<TextLayoutValue> value = TextLayoutEngine::getInstance().getValue(paint,
+ text, 0, count, count, bidiFlags);
if (value == NULL) {
- ALOGE("Cannot get TextLayoutCache value for text = '%s'",
- String8(text, count).string());
- return ;
+ return;
}
+
// Beware: this needs Glyph encoding (already done on the Paint constructor)
canvas->drawTextOnPathHV(value->getGlyphs(), value->getGlyphsCount() * 2, *path, h_, v_, *paint);
}
diff --git a/core/jni/android/graphics/TextLayoutCache.cpp b/core/jni/android/graphics/TextLayoutCache.cpp
index d26f563..c797a73 100644
--- a/core/jni/android/graphics/TextLayoutCache.cpp
+++ b/core/jni/android/graphics/TextLayoutCache.cpp
@@ -35,18 +35,13 @@
#define TYPEFACE_BENGALI "/system/fonts/Lohit-Bengali.ttf"
#define TYPEFACE_THAI "/system/fonts/DroidSansThai.ttf"
-#if USE_TEXT_LAYOUT_CACHE
-
- ANDROID_SINGLETON_STATIC_INSTANCE(TextLayoutCache);
-
-#endif
-
- ANDROID_SINGLETON_STATIC_INSTANCE(TextLayoutEngine);
+ANDROID_SINGLETON_STATIC_INSTANCE(TextLayoutEngine);
//--------------------------------------------------------------------------------------------------
-TextLayoutCache::TextLayoutCache() :
- mCache(GenerationCache<TextLayoutCacheKey, sp<TextLayoutCacheValue> >::kUnlimitedCapacity),
+TextLayoutCache::TextLayoutCache(TextLayoutShaper* shaper) :
+ mShaper(shaper),
+ mCache(GenerationCache<TextLayoutCacheKey, sp<TextLayoutValue> >::kUnlimitedCapacity),
mSize(0), mMaxSize(MB(DEFAULT_TEXT_LAYOUT_CACHE_SIZE_IN_MB)),
mCacheHitCount(0), mNanosecondsSaved(0) {
init();
@@ -75,7 +70,7 @@
/**
* Callbacks
*/
-void TextLayoutCache::operator()(TextLayoutCacheKey& text, sp<TextLayoutCacheValue>& desc) {
+void TextLayoutCache::operator()(TextLayoutCacheKey& text, sp<TextLayoutValue>& desc) {
size_t totalSizeToDelete = text.getSize() + desc->getSize();
mSize -= totalSizeToDelete;
if (mDebugEnabled) {
@@ -93,7 +88,7 @@
/*
* Caching
*/
-sp<TextLayoutCacheValue> TextLayoutCache::getValue(SkPaint* paint,
+sp<TextLayoutValue> TextLayoutCache::getValue(const SkPaint* paint,
const jchar* text, jint start, jint count, jint contextCount, jint dirFlags) {
AutoMutex _l(mLock);
nsecs_t startTime = 0;
@@ -105,7 +100,7 @@
TextLayoutCacheKey key(paint, text, start, count, contextCount, dirFlags);
// Get value from cache if possible
- sp<TextLayoutCacheValue> value = mCache.get(key);
+ sp<TextLayoutValue> value = mCache.get(key);
// Value not found for the key, we need to add a new value in the cache
if (value == NULL) {
@@ -113,10 +108,10 @@
startTime = systemTime(SYSTEM_TIME_MONOTONIC);
}
- value = new TextLayoutCacheValue(contextCount);
+ value = new TextLayoutValue(contextCount);
// Compute advances and store them
- TextLayoutEngine::getInstance().computeValues(value.get(), paint,
+ mShaper->computeValues(value.get(), paint,
reinterpret_cast<const UChar*>(text), start, count,
size_t(contextCount), int(dirFlags));
@@ -312,31 +307,33 @@
/**
* TextLayoutCacheValue
*/
-TextLayoutCacheValue::TextLayoutCacheValue(size_t contextCount) :
+TextLayoutValue::TextLayoutValue(size_t contextCount) :
mTotalAdvance(0), mElapsedTime(0) {
// Give a hint for advances and glyphs vectors size
mAdvances.setCapacity(contextCount);
mGlyphs.setCapacity(contextCount);
}
-size_t TextLayoutCacheValue::getSize() const {
- return sizeof(TextLayoutCacheValue) + sizeof(jfloat) * mAdvances.capacity() +
+size_t TextLayoutValue::getSize() const {
+ return sizeof(TextLayoutValue) + sizeof(jfloat) * mAdvances.capacity() +
sizeof(jchar) * mGlyphs.capacity();
}
-void TextLayoutCacheValue::setElapsedTime(uint32_t time) {
+void TextLayoutValue::setElapsedTime(uint32_t time) {
mElapsedTime = time;
}
-uint32_t TextLayoutCacheValue::getElapsedTime() {
+uint32_t TextLayoutValue::getElapsedTime() {
return mElapsedTime;
}
-TextLayoutEngine::TextLayoutEngine() : mShaperItemGlyphArraySize(0) {
+TextLayoutShaper::TextLayoutShaper() : mShaperItemGlyphArraySize(0) {
mDefaultTypeface = SkFontHost::CreateTypeface(NULL, NULL, NULL, 0, SkTypeface::kNormal);
mArabicTypeface = NULL;
mHebrewRegularTypeface = NULL;
mHebrewBoldTypeface = NULL;
+ mBengaliTypeface = NULL;
+ mThaiTypeface = NULL;
mFontRec.klass = &harfbuzzSkiaClass;
mFontRec.userData = 0;
@@ -355,12 +352,17 @@
mShaperItem.font->userData = &mShapingPaint;
}
-TextLayoutEngine::~TextLayoutEngine() {
- // FIXME should free fonts and caches but since this class is a singleton,
- // we don't bother at the moment
+TextLayoutShaper::~TextLayoutShaper() {
+ SkSafeUnref(mDefaultTypeface);
+ SkSafeUnref(mArabicTypeface);
+ SkSafeUnref(mHebrewRegularTypeface);
+ SkSafeUnref(mHebrewBoldTypeface);
+ SkSafeUnref(mBengaliTypeface);
+ SkSafeUnref(mThaiTypeface);
+ deleteShaperItemGlyphArrays();
}
-void TextLayoutEngine::computeValues(TextLayoutCacheValue* value, SkPaint* paint, const UChar* chars,
+void TextLayoutShaper::computeValues(TextLayoutValue* value, const SkPaint* paint, const UChar* chars,
size_t start, size_t count, size_t contextCount, int dirFlags) {
computeValues(paint, chars, start, count, contextCount, dirFlags,
@@ -371,7 +373,7 @@
#endif
}
-void TextLayoutEngine::computeValues(SkPaint* paint, const UChar* chars,
+void TextLayoutShaper::computeValues(const SkPaint* paint, const UChar* chars,
size_t start, size_t count, size_t contextCount, int dirFlags,
Vector<jfloat>* const outAdvances, jfloat* outTotalAdvance,
Vector<jchar>* const outGlyphs) {
@@ -513,7 +515,7 @@
}
}
-void TextLayoutEngine::computeRunValues(SkPaint* paint, const UChar* chars,
+void TextLayoutShaper::computeRunValues(const SkPaint* paint, const UChar* chars,
size_t count, bool isRTL,
Vector<jfloat>* const outAdvances, jfloat* outTotalAdvance,
Vector<jchar>* const outGlyphs) {
@@ -719,7 +721,7 @@
}
-size_t TextLayoutEngine::shapeFontRun(SkPaint* paint, bool isRTL) {
+size_t TextLayoutShaper::shapeFontRun(const SkPaint* paint, bool isRTL) {
// Reset kerning
mShaperItem.kerning_applied = false;
@@ -811,7 +813,7 @@
case HB_Script_Hebrew:
case HB_Script_Bengali:
case HB_Script_Thai:{
- const uint16_t* text16 = (const uint16_t*)mShaperItem.string;
+ const uint16_t* text16 = (const uint16_t*)(mShaperItem.string + mShaperItem.item.pos);
SkUnichar firstUnichar = SkUTF16_NextUnichar(&text16);
baseGlyphCount = paint->getBaseGlyphCount(firstUnichar);
break;
@@ -833,14 +835,14 @@
return baseGlyphCount;
}
-void TextLayoutEngine::ensureShaperItemGlyphArrays(size_t size) {
+void TextLayoutShaper::ensureShaperItemGlyphArrays(size_t size) {
if (size > mShaperItemGlyphArraySize) {
deleteShaperItemGlyphArrays();
createShaperItemGlyphArrays(size);
}
}
-void TextLayoutEngine::createShaperItemGlyphArrays(size_t size) {
+void TextLayoutShaper::createShaperItemGlyphArrays(size_t size) {
#if DEBUG_GLYPHS
ALOGD("Creating Glyph Arrays with size = %d", size);
#endif
@@ -858,7 +860,7 @@
mShaperItem.log_clusters = new unsigned short[size];
}
-void TextLayoutEngine::deleteShaperItemGlyphArrays() {
+void TextLayoutShaper::deleteShaperItemGlyphArrays() {
delete[] mShaperItem.glyphs;
delete[] mShaperItem.attributes;
delete[] mShaperItem.advances;
@@ -866,7 +868,7 @@
delete[] mShaperItem.log_clusters;
}
-SkTypeface* TextLayoutEngine::getCachedTypeface(SkTypeface** typeface, const char path[]) {
+SkTypeface* TextLayoutShaper::getCachedTypeface(SkTypeface** typeface, const char path[]) {
if (!*typeface) {
*typeface = SkTypeface::CreateFromFile(path);
// CreateFromFile(path) can return NULL if the path is non existing
@@ -884,7 +886,7 @@
return *typeface;
}
-HB_Face TextLayoutEngine::getCachedHBFace(SkTypeface* typeface) {
+HB_Face TextLayoutShaper::getCachedHBFace(SkTypeface* typeface) {
SkFontID fontId = typeface->uniqueID();
ssize_t index = mCachedHBFaces.indexOfKey(fontId);
if (index >= 0) {
@@ -900,4 +902,36 @@
return face;
}
+TextLayoutEngine::TextLayoutEngine() {
+ mShaper = new TextLayoutShaper();
+#if USE_TEXT_LAYOUT_CACHE
+ mTextLayoutCache = new TextLayoutCache(mShaper);
+#else
+ mTextLayoutCache = NULL;
+#endif
+}
+
+TextLayoutEngine::~TextLayoutEngine() {
+ delete mTextLayoutCache;
+ delete mShaper;
+}
+
+sp<TextLayoutValue> TextLayoutEngine::getValue(const SkPaint* paint, const jchar* text,
+ jint start, jint count, jint contextCount, jint dirFlags) {
+ sp<TextLayoutValue> value;
+#if USE_TEXT_LAYOUT_CACHE
+ value = mTextLayoutCache->getValue(paint, text, start, count,
+ contextCount, dirFlags);
+ if (value == NULL) {
+ ALOGE("Cannot get TextLayoutCache value for text = '%s'",
+ String8(text + start, count).string());
+ }
+#else
+ value = new TextLayoutValue(count);
+ mShaper->computeValues(value.get(), paint,
+ reinterpret_cast<const UChar*>(text), start, count, contextCount, dirFlags);
+#endif
+ return value;
+}
+
} // namespace android
diff --git a/core/jni/android/graphics/TextLayoutCache.h b/core/jni/android/graphics/TextLayoutCache.h
index 510aa18..7ac2f18 100644
--- a/core/jni/android/graphics/TextLayoutCache.h
+++ b/core/jni/android/graphics/TextLayoutCache.h
@@ -115,11 +115,11 @@
}
/*
- * TextLayoutCacheValue is the Cache value
+ * TextLayoutValue is the Cache value
*/
-class TextLayoutCacheValue : public RefBase {
+class TextLayoutValue : public RefBase {
public:
- TextLayoutCacheValue(size_t contextCount);
+ TextLayoutValue(size_t contextCount);
void setElapsedTime(uint32_t time);
uint32_t getElapsedTime();
@@ -159,72 +159,14 @@
}; // TextLayoutCacheValue
/**
- * Cache of text layout information.
+ * The TextLayoutShaper is responsible for shaping (with the Harfbuzz library)
*/
-class TextLayoutCache : public OnEntryRemoved<TextLayoutCacheKey, sp<TextLayoutCacheValue> >,
- public Singleton<TextLayoutCache>
-{
+class TextLayoutShaper {
public:
- TextLayoutCache();
+ TextLayoutShaper();
+ virtual ~TextLayoutShaper();
- virtual ~TextLayoutCache();
-
- bool isInitialized() {
- return mInitialized;
- }
-
- /**
- * Used as a callback when an entry is removed from the cache
- * Do not invoke directly
- */
- void operator()(TextLayoutCacheKey& text, sp<TextLayoutCacheValue>& desc);
-
- sp<TextLayoutCacheValue> getValue(SkPaint* paint, const jchar* text, jint start, jint count,
- jint contextCount, jint dirFlags);
-
- /**
- * Clear the cache
- */
- void clear();
-
-private:
- Mutex mLock;
- bool mInitialized;
-
- GenerationCache<TextLayoutCacheKey, sp<TextLayoutCacheValue> > mCache;
-
- uint32_t mSize;
- uint32_t mMaxSize;
-
- uint32_t mCacheHitCount;
- uint64_t mNanosecondsSaved;
-
- uint64_t mCacheStartTime;
-
- RtlDebugLevel mDebugLevel;
- bool mDebugEnabled;
-
- /*
- * Class initialization
- */
- void init();
-
- /**
- * Dump Cache statistics
- */
- void dumpCacheStats();
-
-}; // TextLayoutCache
-
-/**
- * The TextLayoutEngine is responsible for shaping with Harfbuzz library
- */
-class TextLayoutEngine : public Singleton<TextLayoutEngine> {
-public:
- TextLayoutEngine();
- virtual ~TextLayoutEngine();
-
- void computeValues(TextLayoutCacheValue* value, SkPaint* paint, const UChar* chars,
+ void computeValues(TextLayoutValue* value, const SkPaint* paint, const UChar* chars,
size_t start, size_t count, size_t contextCount, int dirFlags);
private:
@@ -273,14 +215,14 @@
*/
UnicodeString mBuffer;
- size_t shapeFontRun(SkPaint* paint, bool isRTL);
+ size_t shapeFontRun(const SkPaint* paint, bool isRTL);
- void computeValues(SkPaint* paint, const UChar* chars,
+ void computeValues(const SkPaint* paint, const UChar* chars,
size_t start, size_t count, size_t contextCount, int dirFlags,
Vector<jfloat>* const outAdvances, jfloat* outTotalAdvance,
Vector<jchar>* const outGlyphs);
- void computeRunValues(SkPaint* paint, const UChar* chars,
+ void computeRunValues(const SkPaint* paint, const UChar* chars,
size_t count, bool isRTL,
Vector<jfloat>* const outAdvances, jfloat* outTotalAdvance,
Vector<jchar>* const outGlyphs);
@@ -292,8 +234,80 @@
void createShaperItemGlyphArrays(size_t size);
void deleteShaperItemGlyphArrays();
-}; // TextLayoutEngine
+}; // TextLayoutShaper
+/**
+ * Cache of text layout information.
+ */
+class TextLayoutCache : private OnEntryRemoved<TextLayoutCacheKey, sp<TextLayoutValue> >
+{
+public:
+ TextLayoutCache(TextLayoutShaper* shaper);
+
+ ~TextLayoutCache();
+
+ bool isInitialized() {
+ return mInitialized;
+ }
+
+ /**
+ * Used as a callback when an entry is removed from the cache
+ * Do not invoke directly
+ */
+ void operator()(TextLayoutCacheKey& text, sp<TextLayoutValue>& desc);
+
+ sp<TextLayoutValue> getValue(const SkPaint* paint, const jchar* text, jint start,
+ jint count, jint contextCount, jint dirFlags);
+
+ /**
+ * Clear the cache
+ */
+ void clear();
+
+private:
+ TextLayoutShaper* mShaper;
+ Mutex mLock;
+ bool mInitialized;
+
+ GenerationCache<TextLayoutCacheKey, sp<TextLayoutValue> > mCache;
+
+ uint32_t mSize;
+ uint32_t mMaxSize;
+
+ uint32_t mCacheHitCount;
+ uint64_t mNanosecondsSaved;
+
+ uint64_t mCacheStartTime;
+
+ RtlDebugLevel mDebugLevel;
+ bool mDebugEnabled;
+
+ /*
+ * Class initialization
+ */
+ void init();
+
+ /**
+ * Dump Cache statistics
+ */
+ void dumpCacheStats();
+
+}; // TextLayoutCache
+
+/**
+ * The TextLayoutEngine is reponsible for computing TextLayoutValues
+ */
+class TextLayoutEngine : public Singleton<TextLayoutEngine> {
+public:
+ TextLayoutEngine();
+ virtual ~TextLayoutEngine();
+
+ sp<TextLayoutValue> getValue(const SkPaint* paint, const jchar* text, jint start,
+ jint count, jint contextCount, jint dirFlags);
+private:
+ TextLayoutCache* mTextLayoutCache;
+ TextLayoutShaper* mShaper;
+}; // TextLayoutEngine
} // namespace android
#endif /* ANDROID_TEXT_LAYOUT_CACHE_H */
diff --git a/core/jni/android_database_SQLiteCommon.cpp b/core/jni/android_database_SQLiteCommon.cpp
index a94b9d2..3484467 100644
--- a/core/jni/android_database_SQLiteCommon.cpp
+++ b/core/jni/android_database_SQLiteCommon.cpp
@@ -68,50 +68,53 @@
exceptionClass = "android/database/sqlite/SQLiteDatabaseCorruptException";
break;
case SQLITE_CONSTRAINT:
- exceptionClass = "android/database/sqlite/SQLiteConstraintException";
- break;
+ exceptionClass = "android/database/sqlite/SQLiteConstraintException";
+ break;
case SQLITE_ABORT:
- exceptionClass = "android/database/sqlite/SQLiteAbortException";
- break;
+ exceptionClass = "android/database/sqlite/SQLiteAbortException";
+ break;
case SQLITE_DONE:
- exceptionClass = "android/database/sqlite/SQLiteDoneException";
- break;
+ exceptionClass = "android/database/sqlite/SQLiteDoneException";
+ break;
case SQLITE_FULL:
- exceptionClass = "android/database/sqlite/SQLiteFullException";
- break;
+ exceptionClass = "android/database/sqlite/SQLiteFullException";
+ break;
case SQLITE_MISUSE:
- exceptionClass = "android/database/sqlite/SQLiteMisuseException";
- break;
+ exceptionClass = "android/database/sqlite/SQLiteMisuseException";
+ break;
case SQLITE_PERM:
- exceptionClass = "android/database/sqlite/SQLiteAccessPermException";
- break;
+ exceptionClass = "android/database/sqlite/SQLiteAccessPermException";
+ break;
case SQLITE_BUSY:
- exceptionClass = "android/database/sqlite/SQLiteDatabaseLockedException";
- break;
+ exceptionClass = "android/database/sqlite/SQLiteDatabaseLockedException";
+ break;
case SQLITE_LOCKED:
- exceptionClass = "android/database/sqlite/SQLiteTableLockedException";
- break;
+ exceptionClass = "android/database/sqlite/SQLiteTableLockedException";
+ break;
case SQLITE_READONLY:
- exceptionClass = "android/database/sqlite/SQLiteReadOnlyDatabaseException";
- break;
+ exceptionClass = "android/database/sqlite/SQLiteReadOnlyDatabaseException";
+ break;
case SQLITE_CANTOPEN:
- exceptionClass = "android/database/sqlite/SQLiteCantOpenDatabaseException";
- break;
+ exceptionClass = "android/database/sqlite/SQLiteCantOpenDatabaseException";
+ break;
case SQLITE_TOOBIG:
- exceptionClass = "android/database/sqlite/SQLiteBlobTooBigException";
- break;
+ exceptionClass = "android/database/sqlite/SQLiteBlobTooBigException";
+ break;
case SQLITE_RANGE:
- exceptionClass = "android/database/sqlite/SQLiteBindOrColumnIndexOutOfRangeException";
- break;
+ exceptionClass = "android/database/sqlite/SQLiteBindOrColumnIndexOutOfRangeException";
+ break;
case SQLITE_NOMEM:
- exceptionClass = "android/database/sqlite/SQLiteOutOfMemoryException";
- break;
+ exceptionClass = "android/database/sqlite/SQLiteOutOfMemoryException";
+ break;
case SQLITE_MISMATCH:
- exceptionClass = "android/database/sqlite/SQLiteDatatypeMismatchException";
- break;
+ exceptionClass = "android/database/sqlite/SQLiteDatatypeMismatchException";
+ break;
+ case SQLITE_INTERRUPT:
+ exceptionClass = "android/content/OperationCanceledException";
+ break;
default:
- exceptionClass = "android/database/sqlite/SQLiteException";
- break;
+ exceptionClass = "android/database/sqlite/SQLiteException";
+ break;
}
if (sqlite3Message != NULL && message != NULL) {
diff --git a/core/jni/android_database_SQLiteConnection.cpp b/core/jni/android_database_SQLiteConnection.cpp
index d0d53f6..e061ac3 100644
--- a/core/jni/android_database_SQLiteConnection.cpp
+++ b/core/jni/android_database_SQLiteConnection.cpp
@@ -67,8 +67,10 @@
const String8 path;
const String8 label;
+ volatile bool canceled;
+
SQLiteConnection(sqlite3* db, int openFlags, const String8& path, const String8& label) :
- db(db), openFlags(openFlags), path(path), label(label) { }
+ db(db), openFlags(openFlags), path(path), label(label), canceled(false) { }
};
// Called each time a statement begins execution, when tracing is enabled.
@@ -85,6 +87,12 @@
connection->label.string(), sql, tm * 0.000001f);
}
+// Called after each SQLite VM instruction when cancelation is enabled.
+static int sqliteProgressHandlerCallback(void* data) {
+ SQLiteConnection* connection = static_cast<SQLiteConnection*>(data);
+ return connection->canceled;
+}
+
static jint nativeOpen(JNIEnv* env, jclass clazz, jstring pathStr, jint openFlags,
jstring labelStr, jboolean enableTrace, jboolean enableProfile) {
@@ -871,6 +879,24 @@
return cur;
}
+static void nativeCancel(JNIEnv* env, jobject clazz, jint connectionPtr) {
+ SQLiteConnection* connection = reinterpret_cast<SQLiteConnection*>(connectionPtr);
+ connection->canceled = true;
+}
+
+static void nativeResetCancel(JNIEnv* env, jobject clazz, jint connectionPtr,
+ jboolean cancelable) {
+ SQLiteConnection* connection = reinterpret_cast<SQLiteConnection*>(connectionPtr);
+ connection->canceled = false;
+
+ if (cancelable) {
+ sqlite3_progress_handler(connection->db, 4, sqliteProgressHandlerCallback,
+ connection);
+ } else {
+ sqlite3_progress_handler(connection->db, 0, NULL, NULL);
+ }
+}
+
static JNINativeMethod sMethods[] =
{
@@ -923,6 +949,10 @@
(void*)nativeExecuteForCursorWindow },
{ "nativeGetDbLookaside", "(I)I",
(void*)nativeGetDbLookaside },
+ { "nativeCancel", "(I)V",
+ (void*)nativeCancel },
+ { "nativeResetCancel", "(IZ)V",
+ (void*)nativeResetCancel },
};
#define FIND_CLASS(var, className) \
diff --git a/core/jni/android_media_AudioRecord.cpp b/core/jni/android_media_AudioRecord.cpp
index 3f1af86..547607e 100644
--- a/core/jni/android_media_AudioRecord.cpp
+++ b/core/jni/android_media_AudioRecord.cpp
@@ -157,7 +157,7 @@
int frameSize = nbChannels * bytesPerSample;
size_t frameCount = buffSizeInBytes / frameSize;
- if (source >= AUDIO_SOURCE_CNT) {
+ if (uint32_t(source) >= AUDIO_SOURCE_CNT) {
ALOGE("Error creating AudioRecord: unknown source.");
return AUDIORECORD_ERROR_SETUP_INVALIDSOURCE;
}
@@ -198,7 +198,7 @@
// we use a weak reference so the AudioRecord object can be garbage collected.
lpCallbackData->audioRecord_ref = env->NewGlobalRef(weak_this);
- lpRecorder->set(source,
+ lpRecorder->set((audio_source_t) source,
sampleRateInHertz,
format, // word length, PCM
channels,
diff --git a/core/jni/android_view_GLES20Canvas.cpp b/core/jni/android_view_GLES20Canvas.cpp
index 064dcac..e19bb38 100644
--- a/core/jni/android_view_GLES20Canvas.cpp
+++ b/core/jni/android_view_GLES20Canvas.cpp
@@ -188,6 +188,14 @@
renderer->finish();
}
+static jint android_view_GLES20Canvas_getStencilSize(JNIEnv* env, jobject clazz) {
+ return OpenGLRenderer::getStencilSize();
+}
+
+// ----------------------------------------------------------------------------
+// Functor
+// ----------------------------------------------------------------------------
+
static bool android_view_GLES20Canvas_callDrawGLFunction(JNIEnv* env, jobject clazz,
OpenGLRenderer* renderer, Functor *functor) {
android::uirenderer::Rect dirty;
@@ -483,24 +491,30 @@
}
// ----------------------------------------------------------------------------
+// Draw filters
+// ----------------------------------------------------------------------------
+
+static void android_view_GLES20Canvas_setupPaintFilter(JNIEnv* env, jobject clazz,
+ OpenGLRenderer* renderer, jint clearBits, jint setBits) {
+ renderer->setupPaintFilter(clearBits, setBits);
+}
+
+static void android_view_GLES20Canvas_resetPaintFilter(JNIEnv* env, jobject clazz,
+ OpenGLRenderer* renderer) {
+ renderer->resetPaintFilter();
+}
+
+// ----------------------------------------------------------------------------
// Text
// ----------------------------------------------------------------------------
static void renderText(OpenGLRenderer* renderer, const jchar* text, int count,
jfloat x, jfloat y, int flags, SkPaint* paint) {
- sp<TextLayoutCacheValue> value;
-#if USE_TEXT_LAYOUT_CACHE
- value = TextLayoutCache::getInstance().getValue(paint, text, 0, count, count, flags);
+ sp<TextLayoutValue> value = TextLayoutEngine::getInstance().getValue(paint,
+ text, 0, count, count, flags);
if (value == NULL) {
- ALOGE("Cannot get TextLayoutCache value for text = '%s'",
- String8(text, count).string());
return;
}
-#else
- value = new TextLayoutCacheValue(count);
- TextLayoutEngine::getInstance().computeValues(value.get(), paint,
- text, 0, count, count, flags);
-#endif
const jchar* glyphs = value->getGlyphs();
size_t glyphsCount = value->getGlyphsCount();
int bytesCount = glyphsCount * sizeof(jchar);
@@ -510,19 +524,11 @@
static void renderTextRun(OpenGLRenderer* renderer, const jchar* text,
jint start, jint count, jint contextCount, jfloat x, jfloat y,
int flags, SkPaint* paint) {
- sp<TextLayoutCacheValue> value;
-#if USE_TEXT_LAYOUT_CACHE
- value = TextLayoutCache::getInstance().getValue(paint, text, start, count, contextCount, flags);
+ sp<TextLayoutValue> value = TextLayoutEngine::getInstance().getValue(paint,
+ text, start, count, contextCount, flags);
if (value == NULL) {
- ALOGE("Cannot get TextLayoutCache value for text = '%s'",
- String8(text + start, count).string());
return;
}
-#else
- value = new TextLayoutCacheValue(count);
- TextLayoutEngine::getInstance().computeValues(value.get(), paint,
- text, start, count, contextCount, flags);
-#endif
const jchar* glyphs = value->getGlyphs();
size_t glyphsCount = value->getGlyphsCount();
int bytesCount = glyphsCount * sizeof(jchar);
@@ -569,20 +575,11 @@
static void renderPosText(OpenGLRenderer* renderer, const jchar* text, int count,
const jfloat* positions, jint dirFlags, SkPaint* paint) {
- sp<TextLayoutCacheValue> value;
-#if USE_TEXT_LAYOUT_CACHE
- value = TextLayoutCache::getInstance().getValue(paint, text, 0, count, count, dirFlags);
+ sp<TextLayoutValue> value = TextLayoutEngine::getInstance().getValue(paint,
+ text, 0, count, count, dirFlags);
if (value == NULL) {
- ALOGE("Cannot get TextLayoutCache value for text = '%s'",
- String8(text, count).string());
return;
}
-#else
- value = new TextLayoutCacheValue(count);
- TextLayoutEngine::getInstance().computeValues(value.get(), paint,
- text, 0, count, count, dirFlags);
-#endif
-
const jchar* glyphs = value->getGlyphs();
size_t glyphsCount = value->getGlyphsCount();
if (count < int(glyphsCount)) glyphsCount = count;
@@ -629,6 +626,15 @@
return displayList->getSize();
}
+static void android_view_GLES20Canvas_setDisplayListName(JNIEnv* env,
+ jobject clazz, DisplayList* displayList, jstring name) {
+ if (name != NULL) {
+ const char* textArray = env->GetStringUTFChars(name, NULL);
+ displayList->setName(textArray);
+ env->ReleaseStringUTFChars(name, textArray);
+ }
+}
+
static OpenGLRenderer* android_view_GLES20Canvas_createDisplayListRenderer(JNIEnv* env,
jobject clazz) {
return new DisplayListRenderer;
@@ -819,6 +825,8 @@
{ "nPrepareDirty", "(IIIIIZ)V", (void*) android_view_GLES20Canvas_prepareDirty },
{ "nFinish", "(I)V", (void*) android_view_GLES20Canvas_finish },
+ { "nGetStencilSize", "()I", (void*) android_view_GLES20Canvas_getStencilSize },
+
{ "nCallDrawGLFunction", "(II)Z",
(void*) android_view_GLES20Canvas_callDrawGLFunction },
@@ -870,6 +878,9 @@
{ "nSetupColorFilter", "(II)V", (void*) android_view_GLES20Canvas_setupColorFilter },
{ "nSetupShadow", "(IFFFI)V", (void*) android_view_GLES20Canvas_setupShadow },
+ { "nSetupPaintFilter", "(III)V", (void*) android_view_GLES20Canvas_setupPaintFilter },
+ { "nResetPaintFilter", "(I)V", (void*) android_view_GLES20Canvas_resetPaintFilter },
+
{ "nDrawText", "(I[CIIFFII)V", (void*) android_view_GLES20Canvas_drawTextArray },
{ "nDrawText", "(ILjava/lang/String;IIFFII)V",
(void*) android_view_GLES20Canvas_drawText },
@@ -888,10 +899,14 @@
{ "nGetDisplayList", "(II)I", (void*) android_view_GLES20Canvas_getDisplayList },
{ "nDestroyDisplayList", "(I)V", (void*) android_view_GLES20Canvas_destroyDisplayList },
{ "nGetDisplayListSize", "(I)I", (void*) android_view_GLES20Canvas_getDisplayListSize },
- { "nCreateDisplayListRenderer", "()I", (void*) android_view_GLES20Canvas_createDisplayListRenderer },
- { "nResetDisplayListRenderer", "(I)V", (void*) android_view_GLES20Canvas_resetDisplayListRenderer },
+ { "nSetDisplayListName", "(ILjava/lang/String;)V",
+ (void*) android_view_GLES20Canvas_setDisplayListName },
{ "nDrawDisplayList", "(IIIILandroid/graphics/Rect;)Z",
(void*) android_view_GLES20Canvas_drawDisplayList },
+
+ { "nCreateDisplayListRenderer", "()I", (void*) android_view_GLES20Canvas_createDisplayListRenderer },
+ { "nResetDisplayListRenderer", "(I)V", (void*) android_view_GLES20Canvas_resetDisplayListRenderer },
+
{ "nOutputDisplayList", "(II)V", (void*) android_view_GLES20Canvas_outputDisplayList },
{ "nInterrupt", "(I)V", (void*) android_view_GLES20Canvas_interrupt },
{ "nResume", "(I)V", (void*) android_view_GLES20Canvas_resume },
diff --git a/core/jni/android_view_HardwareRenderer.cpp b/core/jni/android_view_HardwareRenderer.cpp
index 09809ec..cdcde51 100644
--- a/core/jni/android_view_HardwareRenderer.cpp
+++ b/core/jni/android_view_HardwareRenderer.cpp
@@ -22,6 +22,8 @@
#include <EGL/egl_cache.h>
+EGLAPI void EGLAPIENTRY eglBeginFrame(EGLDisplay dpy, EGLSurface surface);
+
namespace android {
// ----------------------------------------------------------------------------
@@ -36,6 +38,12 @@
env->ReleaseStringUTFChars(diskCachePath, cacheArray);
}
+static void android_view_HardwareRenderer_beginFrame(JNIEnv* env, jobject clazz) {
+ EGLDisplay dpy = eglGetCurrentDisplay();
+ EGLSurface surf = eglGetCurrentSurface(EGL_DRAW);
+ eglBeginFrame(dpy, surf);
+}
+
// ----------------------------------------------------------------------------
// JNI Glue
// ----------------------------------------------------------------------------
@@ -45,6 +53,8 @@
static JNINativeMethod gMethods[] = {
{ "nSetupShadersDiskCache", "(Ljava/lang/String;)V",
(void*) android_view_HardwareRenderer_setupShadersDiskCache },
+ { "nBeginFrame", "()V",
+ (void*) android_view_HardwareRenderer_beginFrame },
};
int register_android_view_HardwareRenderer(JNIEnv* env) {
diff --git a/core/res/res/anim/screen_rotate_180_enter.xml b/core/res/res/anim/screen_rotate_180_enter.xml
index 95cc562..470416b 100644
--- a/core/res/res/anim/screen_rotate_180_enter.xml
+++ b/core/res/res/anim/screen_rotate_180_enter.xml
@@ -19,16 +19,10 @@
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:shareInterpolator="false">
- <scale android:fromXScale="1.0" android:toXScale="1.0"
- android:fromYScale=".9" android:toYScale="1.0"
- android:pivotX="50%p" android:pivotY="50%p"
- android:fillEnabled="true" android:fillBefore="true"
+ <rotate android:fromDegrees="180" android:toDegrees="0"
+ android:pivotX="50%" android:pivotY="50%"
android:interpolator="@interpolator/decelerate_quint"
- android:startOffset="160"
- android:duration="300" />
- <alpha android:fromAlpha="0" android:toAlpha="1.0"
- android:fillEnabled="true" android:fillBefore="true"
- android:interpolator="@interpolator/decelerate_quint"
- android:startOffset="160"
- android:duration="300"/>
+ android:fillEnabled="true"
+ android:fillBefore="true" android:fillAfter="true"
+ android:duration="@android:integer/config_mediumAnimTime" />
</set>
\ No newline at end of file
diff --git a/core/res/res/anim/screen_rotate_180_exit.xml b/core/res/res/anim/screen_rotate_180_exit.xml
index d3dd4c0..58a1868 100644
--- a/core/res/res/anim/screen_rotate_180_exit.xml
+++ b/core/res/res/anim/screen_rotate_180_exit.xml
@@ -19,12 +19,10 @@
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:shareInterpolator="false">
- <scale android:fromXScale="1.0" android:toXScale="1.0"
- android:fromYScale="1.0" android:toYScale="0.0"
- android:pivotX="50%p" android:pivotY="50%p"
- android:interpolator="@interpolator/accelerate_cubic"
- android:duration="160" />
- <alpha android:fromAlpha="1.0" android:toAlpha="0"
- android:interpolator="@interpolator/decelerate_cubic"
- android:duration="160"/>
+ <rotate android:fromDegrees="0" android:toDegrees="-180"
+ android:pivotX="50%" android:pivotY="50%"
+ android:interpolator="@interpolator/decelerate_quint"
+ android:fillEnabled="true"
+ android:fillBefore="true" android:fillAfter="true"
+ android:duration="@android:integer/config_mediumAnimTime" />
</set>
\ No newline at end of file
diff --git a/core/res/res/anim/screen_rotate_finish_enter.xml b/core/res/res/anim/screen_rotate_finish_enter.xml
new file mode 100644
index 0000000..849aa66
--- /dev/null
+++ b/core/res/res/anim/screen_rotate_finish_enter.xml
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** Copyright 2012, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<set xmlns:android="http://schemas.android.com/apk/res/android"
+ android:shareInterpolator="false">
+ <scale android:fromXScale="1.0" android:toXScale="1.25"
+ android:fromYScale="1.0" android:toYScale="1.25"
+ android:pivotX="50%" android:pivotY="50%"
+ android:interpolator="@interpolator/decelerate_quint"
+ android:fillEnabled="true"
+ android:fillBefore="true" android:fillAfter="true"
+ android:duration="@android:integer/config_mediumAnimTime"/>
+ <scale android:fromXScale="100%p" android:toXScale="100%"
+ android:fromYScale="100%p" android:toYScale="100%"
+ android:pivotX="50%" android:pivotY="50%"
+ android:interpolator="@interpolator/decelerate_quint"
+ android:fillEnabled="true"
+ android:fillBefore="true" android:fillAfter="true"
+ android:duration="@android:integer/config_mediumAnimTime" />
+</set>
diff --git a/core/res/res/anim/screen_rotate_finish_exit.xml b/core/res/res/anim/screen_rotate_finish_exit.xml
new file mode 100644
index 0000000..7f70dbc
--- /dev/null
+++ b/core/res/res/anim/screen_rotate_finish_exit.xml
@@ -0,0 +1,41 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** Copyright 2012, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<set xmlns:android="http://schemas.android.com/apk/res/android"
+ android:shareInterpolator="false">
+ <scale android:fromXScale="1.0" android:toXScale="1.25"
+ android:fromYScale="1.0" android:toYScale="1.25"
+ android:pivotX="50%" android:pivotY="50%"
+ android:interpolator="@interpolator/decelerate_quint"
+ android:fillEnabled="true"
+ android:fillBefore="false" android:fillAfter="true"
+ android:duration="@android:integer/config_mediumAnimTime"/>
+ <!--
+ <scale android:fromXScale="100%" android:toXScale="100%p"
+ android:fromYScale="100%" android:toYScale="100%p"
+ android:pivotX="50%" android:pivotY="50%"
+ android:interpolator="@interpolator/decelerate_quint"
+ android:duration="@android:integer/config_mediumAnimTime" />
+ -->
+ <alpha android:fromAlpha="1.0" android:toAlpha="0"
+ android:interpolator="@interpolator/decelerate_quint"
+ android:fillEnabled="true"
+ android:fillBefore="true" android:fillAfter="true"
+ android:duration="@android:integer/config_mediumAnimTime" />
+</set>
diff --git a/core/res/res/anim/screen_rotate_minus_90_enter.xml b/core/res/res/anim/screen_rotate_minus_90_enter.xml
index 61aa72a..d2aebc9 100644
--- a/core/res/res/anim/screen_rotate_minus_90_enter.xml
+++ b/core/res/res/anim/screen_rotate_minus_90_enter.xml
@@ -19,8 +19,44 @@
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:shareInterpolator="false">
+ <!--
+ <scale android:fromXScale="1.0" android:toXScale="0.565"
+ android:fromYScale="1.0" android:toYScale="0.565"
+ android:pivotX="50%" android:pivotY="50%"
+ android:interpolator="@interpolator/decelerate_quint"
+ android:fillEnabled="true"
+ android:fillBefore="false" android:fillAfter="true"
+ android:duration="@android:integer/config_mediumAnimTime"/>
+ <scale android:fromXScale="1.0" android:toXScale="1.777777777"
+ android:fromYScale="1.0" android:toYScale="1.777777777"
+ android:pivotX="50%" android:pivotY="50%"
+ android:interpolator="@interpolator/decelerate_quint"
+ android:fillEnabled="true"
+ android:fillBefore="false" android:fillAfter="true"
+ android:startOffset="@android:integer/config_longAnimTime"
+ android:duration="@android:integer/config_mediumAnimTime"/>
+ <scale android:fromXScale="100%p" android:toXScale="100%"
+ android:fromYScale="100%p" android:toYScale="100%"
+ android:pivotX="50%" android:pivotY="50%"
+ android:interpolator="@interpolator/decelerate_quint"
+ android:fillEnabled="true"
+ android:fillBefore="true" android:fillAfter="true"
+ android:startOffset="@android:integer/config_longAnimTime"
+ android:duration="@android:integer/config_mediumAnimTime" />
+ -->
+ <!--
+ <scale android:fromXScale="100%p" android:toXScale="100%"
+ android:fromYScale="100%p" android:toYScale="100%"
+ android:pivotX="50%" android:pivotY="50%"
+ android:interpolator="@interpolator/decelerate_quint"
+ android:fillEnabled="true"
+ android:fillBefore="true" android:fillAfter="true"
+ android:duration="@android:integer/config_mediumAnimTime" />
+ -->
<rotate android:fromDegrees="-90" android:toDegrees="0"
android:pivotX="50%" android:pivotY="50%"
android:interpolator="@interpolator/decelerate_quint"
+ android:fillEnabled="true"
+ android:fillBefore="true" android:fillAfter="true"
android:duration="@android:integer/config_mediumAnimTime" />
</set>
diff --git a/core/res/res/anim/screen_rotate_minus_90_exit.xml b/core/res/res/anim/screen_rotate_minus_90_exit.xml
index 65294f6..c7c38cd 100644
--- a/core/res/res/anim/screen_rotate_minus_90_exit.xml
+++ b/core/res/res/anim/screen_rotate_minus_90_exit.xml
@@ -19,16 +19,51 @@
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:shareInterpolator="false">
+ <!--
+ <scale android:fromXScale="1.0" android:toXScale="0.565"
+ android:fromYScale="1.0" android:toYScale="0.565"
+ android:pivotX="50%" android:pivotY="50%"
+ android:interpolator="@interpolator/decelerate_quint"
+ android:fillEnabled="true"
+ android:fillBefore="false" android:fillAfter="true"
+ android:duration="@android:integer/config_mediumAnimTime"/>
+ <scale android:fromXScale="1.0" android:toXScale="1.777777777"
+ android:fromYScale="1.0" android:toYScale="1.777777777"
+ android:pivotX="50%" android:pivotY="50%"
+ android:interpolator="@interpolator/decelerate_quint"
+ android:fillEnabled="true"
+ android:fillBefore="false" android:fillAfter="true"
+ android:startOffset="@android:integer/config_longAnimTime"
+ android:duration="@android:integer/config_mediumAnimTime"/>
+ <scale android:fromXScale="100%" android:toXScale="100%p"
+ android:fromYScale="100%" android:toYScale="100%p"
+ android:pivotX="50%" android:pivotY="50%"
+ android:interpolator="@interpolator/decelerate_quint"
+ android:startOffset="@android:integer/config_longAnimTime"
+ android:duration="@android:integer/config_mediumAnimTime" />
+ <alpha android:fromAlpha="1.0" android:toAlpha="0"
+ android:interpolator="@interpolator/decelerate_quint"
+ android:fillEnabled="true"
+ android:fillBefore="false" android:fillAfter="true"
+ android:startOffset="@android:integer/config_longAnimTime"
+ android:duration="@android:integer/config_mediumAnimTime" />
+ -->
+ <!--
<scale android:fromXScale="100%" android:toXScale="100%p"
android:fromYScale="100%" android:toYScale="100%p"
android:pivotX="50%" android:pivotY="50%"
android:interpolator="@interpolator/decelerate_quint"
android:duration="@android:integer/config_mediumAnimTime" />
+ <alpha android:fromAlpha="1.0" android:toAlpha="0"
+ android:interpolator="@interpolator/decelerate_quint"
+ android:fillEnabled="true"
+ android:fillBefore="false" android:fillAfter="true"
+ android:duration="@android:integer/config_mediumAnimTime" />
+ -->
<rotate android:fromDegrees="0" android:toDegrees="90"
android:pivotX="50%" android:pivotY="50%"
android:interpolator="@interpolator/decelerate_quint"
- android:duration="@android:integer/config_mediumAnimTime" />
- <alpha android:fromAlpha="1.0" android:toAlpha="0"
- android:interpolator="@interpolator/decelerate_quint"
+ android:fillEnabled="true"
+ android:fillBefore="true" android:fillAfter="true"
android:duration="@android:integer/config_mediumAnimTime" />
</set>
diff --git a/core/res/res/anim/screen_rotate_plus_90_enter.xml b/core/res/res/anim/screen_rotate_plus_90_enter.xml
index 53b0ccd..63d7043 100644
--- a/core/res/res/anim/screen_rotate_plus_90_enter.xml
+++ b/core/res/res/anim/screen_rotate_plus_90_enter.xml
@@ -19,8 +19,44 @@
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:shareInterpolator="false">
+ <!--
+ <scale android:fromXScale="1.0" android:toXScale="0.565"
+ android:fromYScale="1.0" android:toYScale="0.565"
+ android:pivotX="50%" android:pivotY="50%"
+ android:interpolator="@interpolator/decelerate_quint"
+ android:fillEnabled="true"
+ android:fillBefore="false" android:fillAfter="true"
+ android:duration="@android:integer/config_mediumAnimTime"/>
+ <scale android:fromXScale="1.0" android:toXScale="1.777777777"
+ android:fromYScale="1.0" android:toYScale="1.777777777"
+ android:pivotX="50%" android:pivotY="50%"
+ android:interpolator="@interpolator/decelerate_quint"
+ android:fillEnabled="true"
+ android:fillBefore="false" android:fillAfter="true"
+ android:startOffset="75"
+ android:duration="@android:integer/config_mediumAnimTime"/>
+ <scale android:fromXScale="100%p" android:toXScale="100%"
+ android:fromYScale="100%p" android:toYScale="100%"
+ android:pivotX="50%" android:pivotY="50%"
+ android:interpolator="@interpolator/decelerate_quint"
+ android:fillEnabled="true"
+ android:fillBefore="true" android:fillAfter="true"
+ android:startOffset="75"
+ android:duration="@android:integer/config_mediumAnimTime" />
+ -->
+ <!--
+ <scale android:fromXScale="100%p" android:toXScale="100%"
+ android:fromYScale="100%p" android:toYScale="100%"
+ android:pivotX="50%" android:pivotY="50%"
+ android:interpolator="@interpolator/decelerate_quint"
+ android:fillEnabled="true"
+ android:fillBefore="true" android:fillAfter="true"
+ android:duration="@android:integer/config_mediumAnimTime" />
+ -->
<rotate android:fromDegrees="90" android:toDegrees="0"
android:pivotX="50%" android:pivotY="50%"
android:interpolator="@interpolator/decelerate_quint"
+ android:fillEnabled="true"
+ android:fillBefore="true" android:fillAfter="true"
android:duration="@android:integer/config_mediumAnimTime" />
</set>
diff --git a/core/res/res/anim/screen_rotate_plus_90_exit.xml b/core/res/res/anim/screen_rotate_plus_90_exit.xml
index 63c0b09..ea48c81 100644
--- a/core/res/res/anim/screen_rotate_plus_90_exit.xml
+++ b/core/res/res/anim/screen_rotate_plus_90_exit.xml
@@ -19,16 +19,51 @@
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:shareInterpolator="false">
+ <!--
+ <scale android:fromXScale="1.0" android:toXScale="0.565"
+ android:fromYScale="1.0" android:toYScale="0.565"
+ android:pivotX="50%" android:pivotY="50%"
+ android:interpolator="@interpolator/decelerate_quint"
+ android:fillEnabled="true"
+ android:fillBefore="false" android:fillAfter="true"
+ android:duration="@android:integer/config_mediumAnimTime"/>
+ <scale android:fromXScale="1.0" android:toXScale="1.777777777"
+ android:fromYScale="1.0" android:toYScale="1.777777777"
+ android:pivotX="50%" android:pivotY="50%"
+ android:interpolator="@interpolator/decelerate_quint"
+ android:fillEnabled="true"
+ android:fillBefore="false" android:fillAfter="true"
+ android:startOffset="75"
+ android:duration="@android:integer/config_mediumAnimTime"/>
+ <scale android:fromXScale="100%" android:toXScale="100%p"
+ android:fromYScale="100%" android:toYScale="100%p"
+ android:pivotX="50%" android:pivotY="50%"
+ android:interpolator="@interpolator/decelerate_quint"
+ android:startOffset="75"
+ android:duration="@android:integer/config_mediumAnimTime" />
+ <alpha android:fromAlpha="1.0" android:toAlpha="0"
+ android:interpolator="@interpolator/decelerate_quint"
+ android:fillEnabled="true"
+ android:fillBefore="false" android:fillAfter="true"
+ android:startOffset="75"
+ android:duration="@android:integer/config_mediumAnimTime" />
+ -->
+ <!--
<scale android:fromXScale="100%" android:toXScale="100%p"
android:fromYScale="100%" android:toYScale="100%p"
android:pivotX="50%" android:pivotY="50%"
android:interpolator="@interpolator/decelerate_quint"
android:duration="@android:integer/config_mediumAnimTime" />
+ <alpha android:fromAlpha="1.0" android:toAlpha="0"
+ android:interpolator="@interpolator/decelerate_quint"
+ android:fillEnabled="true"
+ android:fillBefore="false" android:fillAfter="true"
+ android:duration="@android:integer/config_mediumAnimTime" />
+ -->
<rotate android:fromDegrees="0" android:toDegrees="-90"
android:pivotX="50%" android:pivotY="50%"
android:interpolator="@interpolator/decelerate_quint"
- android:duration="@android:integer/config_mediumAnimTime" />
- <alpha android:fromAlpha="1.0" android:toAlpha="0"
- android:interpolator="@interpolator/decelerate_quint"
+ android:fillEnabled="true"
+ android:fillBefore="true" android:fillAfter="true"
android:duration="@android:integer/config_mediumAnimTime" />
</set>
diff --git a/core/res/res/anim/screen_rotate_start_enter.xml b/core/res/res/anim/screen_rotate_start_enter.xml
new file mode 100644
index 0000000..e3f48e4d
--- /dev/null
+++ b/core/res/res/anim/screen_rotate_start_enter.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** Copyright 2012, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<set xmlns:android="http://schemas.android.com/apk/res/android"
+ android:shareInterpolator="false">
+ <scale android:fromXScale="1.0" android:toXScale="0.8"
+ android:fromYScale="1.0" android:toYScale="0.8"
+ android:pivotX="50%" android:pivotY="50%"
+ android:interpolator="@interpolator/decelerate_quint"
+ android:fillEnabled="true"
+ android:fillBefore="true" android:fillAfter="true"
+ android:duration="@android:integer/config_mediumAnimTime"/>
+</set>
diff --git a/core/res/res/anim/screen_rotate_start_exit.xml b/core/res/res/anim/screen_rotate_start_exit.xml
new file mode 100644
index 0000000..e3f48e4d
--- /dev/null
+++ b/core/res/res/anim/screen_rotate_start_exit.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** Copyright 2012, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<set xmlns:android="http://schemas.android.com/apk/res/android"
+ android:shareInterpolator="false">
+ <scale android:fromXScale="1.0" android:toXScale="0.8"
+ android:fromYScale="1.0" android:toYScale="0.8"
+ android:pivotX="50%" android:pivotY="50%"
+ android:interpolator="@interpolator/decelerate_quint"
+ android:fillEnabled="true"
+ android:fillBefore="true" android:fillAfter="true"
+ android:duration="@android:integer/config_mediumAnimTime"/>
+</set>
diff --git a/core/res/res/menu/webview_copy.xml b/core/res/res/menu/webview_copy.xml
index 31bcec5..6a1aa51 100644
--- a/core/res/res/menu/webview_copy.xml
+++ b/core/res/res/menu/webview_copy.xml
@@ -19,11 +19,21 @@
android:title="@string/selectAll"
android:showAsAction="ifRoom|withText"
/>
+ <item android:id="@+id/cut"
+ android:icon="?android:attr/actionModeCutDrawable"
+ android:title="@string/cut"
+ android:showAsAction="ifRoom|withText"
+ />
<item android:id="@+id/copy"
android:icon="?android:attr/actionModeCopyDrawable"
android:title="@string/copy"
android:showAsAction="ifRoom|withText"
/>
+ <item android:id="@+id/paste"
+ android:icon="?android:attr/actionModePasteDrawable"
+ android:title="@string/paste"
+ android:showAsAction="ifRoom|withText"
+ />
<item android:id="@+id/share"
android:icon="?android:attr/actionModeShareDrawable"
android:title="@string/share"
diff --git a/core/res/res/values-af/strings.xml b/core/res/res/values-af/strings.xml
index 6ffda04..f21c6b8 100644
--- a/core/res/res/values-af/strings.xml
+++ b/core/res/res/values-af/strings.xml
@@ -915,6 +915,7 @@
<string name="force_close" msgid="8346072094521265605">"OK"</string>
<string name="report" msgid="4060218260984795706">"Verslag"</string>
<string name="wait" msgid="7147118217226317732">"Wag"</string>
+ <string name="webpage_unresponsive" msgid="3272758351138122503">"Die bladsy reageer nie meer nie."\n\n"Wil jy dit toemaak?"</string>
<string name="launch_warning_title" msgid="1547997780506713581">"Program herlei"</string>
<string name="launch_warning_replace" msgid="6202498949970281412">"<xliff:g id="APP_NAME">%1$s</xliff:g> loop nou."</string>
<string name="launch_warning_original" msgid="188102023021668683">"<xliff:g id="APP_NAME">%1$s</xliff:g> is oorspronklik laat loop."</string>
diff --git a/core/res/res/values-am/strings.xml b/core/res/res/values-am/strings.xml
index 2452a4a..9b32c0d 100644
--- a/core/res/res/values-am/strings.xml
+++ b/core/res/res/values-am/strings.xml
@@ -915,6 +915,7 @@
<string name="force_close" msgid="8346072094521265605">"ይሁን"</string>
<string name="report" msgid="4060218260984795706">"ሪፖርት"</string>
<string name="wait" msgid="7147118217226317732">"ቆይ"</string>
+ <string name="webpage_unresponsive" msgid="3272758351138122503">"ገጹ ምላሽ የማይሰጥ ሆኗል።"\n\n"ልትዘጋው ትፈልጋለህ?"</string>
<string name="launch_warning_title" msgid="1547997780506713581">"መተግበሪያ አቅጣጫው ተቀይሯል"</string>
<string name="launch_warning_replace" msgid="6202498949970281412">"<xliff:g id="APP_NAME">%1$s</xliff:g> እየሄደ ነው።"</string>
<string name="launch_warning_original" msgid="188102023021668683">"<xliff:g id="APP_NAME">%1$s</xliff:g> በዋናነት የተነሳው።"</string>
diff --git a/core/res/res/values-ar/strings.xml b/core/res/res/values-ar/strings.xml
index 4c7a316..b8cd094 100644
--- a/core/res/res/values-ar/strings.xml
+++ b/core/res/res/values-ar/strings.xml
@@ -915,6 +915,7 @@
<string name="force_close" msgid="8346072094521265605">"موافق"</string>
<string name="report" msgid="4060218260984795706">"إرسال تقرير"</string>
<string name="wait" msgid="7147118217226317732">"انتظار"</string>
+ <string name="webpage_unresponsive" msgid="3272758351138122503">"أصبحت الصفحة لا تستجيب."\n\n"هل تريد إغلاقها؟"</string>
<string name="launch_warning_title" msgid="1547997780506713581">"تمت إعادة توجيه التطبيق"</string>
<string name="launch_warning_replace" msgid="6202498949970281412">"<xliff:g id="APP_NAME">%1$s</xliff:g> قيد التشغيل الآن."</string>
<string name="launch_warning_original" msgid="188102023021668683">"تم تشغيل <xliff:g id="APP_NAME">%1$s</xliff:g> من الأصل."</string>
diff --git a/core/res/res/values-be/strings.xml b/core/res/res/values-be/strings.xml
index 0b40992..8479324 100644
--- a/core/res/res/values-be/strings.xml
+++ b/core/res/res/values-be/strings.xml
@@ -27,7 +27,7 @@
<string name="terabyteShort" msgid="231613018159186962">"Тб"</string>
<string name="petabyteShort" msgid="5637816680144990219">"Пб"</string>
<string name="fileSizeSuffix" msgid="7670819340156489359">"запаўняльнік<xliff:g id="NUMBER">%1$s</xliff:g><xliff:g id="UNIT">%2$s</xliff:g>"</string>
- <!-- outdated translation 6071602020171759109 --> <string name="untitled" msgid="4638956954852782576">"Безназоўны"</string>
+ <string name="untitled" msgid="4638956954852782576">"<Без назвы>"</string>
<string name="ellipsis" msgid="7899829516048813237">"..."</string>
<string name="ellipsis_two_dots" msgid="1228078994866030736">".."</string>
<string name="emptyPhoneNumber" msgid="7694063042079676517">"(Няма нумара тэлефона)"</string>
@@ -43,9 +43,9 @@
<string name="serviceErased" msgid="1288584695297200972">"Паспяхова выдалена."</string>
<string name="passwordIncorrect" msgid="7612208839450128715">"Няправільны пароль."</string>
<string name="mmiComplete" msgid="8232527495411698359">"MMI завершаны."</string>
- <!-- outdated translation 5085454289896032547 --> <string name="badPin" msgid="9015277645546710014">"Стары PIN-код уведзены няправільна."</string>
- <!-- outdated translation 5702522162746042460 --> <string name="badPuk" msgid="5487257647081132201">"Няправiльны PUK-код."</string>
- <!-- outdated translation 3695902225843339274 --> <string name="mismatchPin" msgid="609379054496863419">"Уведзеныя PIN-коды не супадаюць."</string>
+ <string name="badPin" msgid="9015277645546710014">"Стары PIN-код уведзены няправільна."</string>
+ <string name="badPuk" msgid="5487257647081132201">"Няправільны PUK-код."</string>
+ <string name="mismatchPin" msgid="609379054496863419">"Уведзеныя PIN-коды не супадаюць."</string>
<string name="invalidPin" msgid="3850018445187475377">"Увядзіце PIN-код, які змяшчае ад 4 да 8 лічбаў."</string>
<string name="invalidPuk" msgid="8761456210898036513">"Увядзіце PUK з 8 лічбаў ці больш."</string>
<string name="needPuk" msgid="919668385956251611">"Ваша SIM-карта заблакавана PUK-кодам. Увядзіце PUK, каб разблакаваць карту."</string>
@@ -68,16 +68,16 @@
<string name="CLIRDefaultOffNextCallOn" msgid="6179425182856418465">"Па змаўчанні ідэнтыфікатар АВН не абмежаваны. Наступны выклік: абмежаваны"</string>
<string name="CLIRDefaultOffNextCallOff" msgid="2567998633124408552">"Налады ідэнтыфікатару АВН па змаўчанні: не абмяжавана. Наступны выклік: не абмежавана"</string>
<string name="serviceNotProvisioned" msgid="8614830180508686666">"Служба не прадастаўляецца."</string>
- <!-- outdated translation 5460892159398802465 --> <string name="CLIRPermanent" msgid="3377371145926835671">"Налада ідэнтыфікатару АВН не можа быць зменена."</string>
+ <string name="CLIRPermanent" msgid="3377371145926835671">"Вы не можаце змяніць налады ідэнтыфікатара абанента, якi тэлефануе."</string>
<string name="RestrictedChangedTitle" msgid="5592189398956187498">"Абмежаваны доступ змяніўся"</string>
<string name="RestrictedOnData" msgid="8653794784690065540">"Служба дадзеных блакуецца."</string>
<string name="RestrictedOnEmergency" msgid="6581163779072833665">"Аварыйная служба блакуецца."</string>
<string name="RestrictedOnNormal" msgid="4953867011389750673">"Галасавая служба заблакаваная."</string>
- <string name="RestrictedOnAllVoice" msgid="1459318899842232234">"Усе галасавыя службы заблакаваныя."</string>
+ <string name="RestrictedOnAllVoice" msgid="3396963652108151260">"Усе галасавыя службы заблакаваны."</string>
<string name="RestrictedOnSms" msgid="8314352327461638897">"Служба SMS заблакаваная."</string>
- <string name="RestrictedOnVoiceData" msgid="8244438624660371717">"Службы перадачы голаса і дадзеных заблакаваныя."</string>
+ <string name="RestrictedOnVoiceData" msgid="996636487106171320">"Службы перадачы голаса/дадзеных заблакаваны."</string>
<string name="RestrictedOnVoiceSms" msgid="1888588152792023873">"Службы перадачы голаса і SMS заблакаваныя."</string>
- <string name="RestrictedOnAll" msgid="2714924667937117304">"Усе службы дадзеных, галасавыя і SMS-службы заблакаваныя."</string>
+ <string name="RestrictedOnAll" msgid="5643028264466092821">"Усе службы перадачы дадзеных, галасавыя і SMS-службы заблакаваны."</string>
<string name="serviceClassVoice" msgid="1258393812335258019">"Голас"</string>
<string name="serviceClassData" msgid="872456782077937893">"Дадзеныя"</string>
<string name="serviceClassFAX" msgid="5566624998840486475">"Факс"</string>
@@ -108,27 +108,27 @@
<string name="fcComplete" msgid="3118848230966886575">"Код аб\'екта завершаны."</string>
<string name="fcError" msgid="3327560126588500777">"Праблема падлучэння ці няправільны код функцыі."</string>
<string name="httpErrorOk" msgid="1191919378083472204">"ОК"</string>
- <string name="httpError" msgid="6603022914760066338">"Памылка сеткі."</string>
- <string name="httpErrorLookup" msgid="4517085806977851374">"URL не знойдзены."</string>
- <!-- outdated translation 2781440683514730227 --> <string name="httpErrorUnsupportedAuthScheme" msgid="6299980280442076799">"Схема аўтэнтыфікацыі сайта не падтрымліваецца."</string>
- <string name="httpErrorAuth" msgid="7293960746955020542">"Няўдалая праверка на сапраўднасць."</string>
+ <string name="httpError" msgid="7956392511146698522">"Адбылася памылка сеткі."</string>
+ <string name="httpErrorLookup" msgid="4711687456111963163">"Не атрымалася знайсці URL."</string>
+ <string name="httpErrorUnsupportedAuthScheme" msgid="6299980280442076799">"Схема аўтэнтыфікацыі сайта не падтрымліваецца."</string>
+ <string name="httpErrorAuth" msgid="1435065629438044534">"Памылка аўтэнтыфікацыі."</string>
<string name="httpErrorProxyAuth" msgid="1788207010559081331">"Праверка сапраўднасці праз проксі-сервер скончылася няўдала."</string>
- <string name="httpErrorConnect" msgid="7623096283505770433">"Падключэнне да сервера не ўдалося."</string>
- <string name="httpErrorIO" msgid="4270874999047767599">"Сервер не можа ўсталяваць сувязь. Паспрабуйце пазней."</string>
+ <string name="httpErrorConnect" msgid="8714273236364640549">"Немагчыма падлучыцца да сервера."</string>
+ <string name="httpErrorIO" msgid="2340558197489302188">"Немагчыма звязацца з серверам. Паўтарыце спробу пазней."</string>
<string name="httpErrorTimeout" msgid="4743403703762883954">"Час чакання злучэння з серверам скончыўся."</string>
<string name="httpErrorRedirectLoop" msgid="8679596090392779516">"Старонка змяшчае зашмат перанакіраванняў сервера."</string>
- <!-- outdated translation 5257172771607996054 --> <string name="httpErrorUnsupportedScheme" msgid="5015730812906192208">"Пратакол не падтрымліваецца."</string>
- <string name="httpErrorFailedSslHandshake" msgid="3088290300440289771">"Бяспечнае злучэнне ўсталяваць не ўдалося."</string>
- <string name="httpErrorBadUrl" msgid="6088183159988619736">"Старонка не можа быць адкрыта: несапраўдны URL."</string>
- <string name="httpErrorFile" msgid="8250549644091165175">"Немагчыма атрымаць доступ да файла."</string>
- <string name="httpErrorFileNotFound" msgid="5588380756326017105">"Запатрабаваны файл не знойдзены."</string>
+ <string name="httpErrorUnsupportedScheme" msgid="5015730812906192208">"Пратакол не падтрымліваецца."</string>
+ <string name="httpErrorFailedSslHandshake" msgid="96549606000658641">"Немагчыма ўсталяваць бяспечнае злучэнне."</string>
+ <string name="httpErrorBadUrl" msgid="3636929722728881972">"Немагчыма адкрыць старонку, таму што URL несапраўдны."</string>
+ <string name="httpErrorFile" msgid="2170788515052558676">"Немагчыма атрымаць доступ да файла."</string>
+ <string name="httpErrorFileNotFound" msgid="6203856612042655084">"Немагчыма знайсці патрабаваны файл."</string>
<string name="httpErrorTooManyRequests" msgid="1235396927087188253">"Апрацоўваецца занадта шмат запытаў. Паспрабуйце яшчэ раз пазней."</string>
- <string name="notification_title" msgid="1259940370369187045">"Памылка ўваходу ў сістэму для ўліковага запісу <xliff:g id="ACCOUNT">%1$s</xliff:g>"</string>
+ <string name="notification_title" msgid="8967710025036163822">"Памылка ўваходу ва ўлiковы запiс <xliff:g id="ACCOUNT">%1$s</xliff:g>"</string>
<string name="contentServiceSync" msgid="8353523060269335667">"Сінхранізацыя"</string>
<string name="contentServiceSyncNotificationTitle" msgid="397743349191901458">"Сінхранізацыя"</string>
<string name="contentServiceTooManyDeletesNotificationDesc" msgid="8100981435080696431">"Занадта шмат выдаленняў <xliff:g id="CONTENT_TYPE">%s</xliff:g>."</string>
- <string name="low_memory" product="tablet" msgid="2292820184396262278">"Памяць планшэта поўная! Выдаліце некаторыя файлы, каб вызваліць месца."</string>
- <string name="low_memory" product="default" msgid="6632412458436461203">"Памяць тэлефона поўная! Выдаліце некаторыя файлы, каб вызваліць прастору."</string>
+ <string name="low_memory" product="tablet" msgid="6494019234102154896">"Памяць планшэта поўная. Выдаліце некаторыя файлы, каб вызваліць месца."</string>
+ <string name="low_memory" product="default" msgid="3475999286680000541">"Памяць тэлефона поўная. Выдаліце некаторыя файлы, каб вызваліць месца."</string>
<string name="me" msgid="6545696007631404292">"Я"</string>
<string name="power_dialog" product="tablet" msgid="8545351420865202853">"Параметры планшэта"</string>
<string name="power_dialog" product="default" msgid="1319919075463988638">"Параметры тэлефона"</string>
@@ -137,12 +137,15 @@
<string name="turn_off_radio" msgid="8198784949987062346">"Адключыць бесправадную сетку"</string>
<string name="screen_lock" msgid="799094655496098153">"Блакіроўка экрана"</string>
<string name="power_off" msgid="4266614107412865048">"Выключыць"</string>
+ <string name="silent_mode_silent" msgid="319298163018473078">"Званок выкл."</string>
+ <string name="silent_mode_vibrate" msgid="7072043388581551395">"Званок з вібрацыяй"</string>
+ <string name="silent_mode_ring" msgid="8592241816194074353">"Званок укл."</string>
<string name="shutdown_progress" msgid="2281079257329981203">"Выключэнне..."</string>
<string name="shutdown_confirm" product="tablet" msgid="3385745179555731470">"Планшэт будзе адключаны."</string>
<string name="shutdown_confirm" product="default" msgid="649792175242821353">"Ваш тэлефон будзе выключаны."</string>
- <!-- outdated translation 6656441286856415014 --> <string name="shutdown_confirm_question" msgid="2906544768881136183">"Адключыць прыладу?"</string>
+ <string name="shutdown_confirm_question" msgid="2906544768881136183">"Закрыць?"</string>
<string name="recent_tasks_title" msgid="3691764623638127888">"Апошнія"</string>
- <!-- outdated translation 279702952298056674 --> <string name="no_recent_tasks" msgid="8794906658732193473">"Няма апошніх прыкладанняў."</string>
+ <string name="no_recent_tasks" msgid="8794906658732193473">"Няма апошніх прыкладанняў."</string>
<string name="global_actions" product="tablet" msgid="408477140088053665">"Параметры планшэта"</string>
<string name="global_actions" product="default" msgid="2406416831541615258">"Параметры тэлефона"</string>
<string name="global_action_lock" msgid="2844945191792119712">"Блакіроўка экрана"</string>
@@ -157,16 +160,16 @@
<string name="safeMode" msgid="2788228061547930246">"Бяспечны рэжым"</string>
<string name="android_system_label" msgid="6577375335728551336">"Сістэма Android"</string>
<string name="permgrouplab_costMoney" msgid="5429808217861460401">"Платныя паслугі"</string>
- <!-- outdated translation 8193824940620517189 --> <string name="permgroupdesc_costMoney" msgid="8596717365335027057">"Дазволіць прыкладанням рабіць рэчы, якія могуць каштаваць вам грошай."</string>
+ <string name="permgroupdesc_costMoney" msgid="3293301903409869495">"Рабіць справы, якія могуць каштаваць вам грошай."</string>
<string name="permgrouplab_messages" msgid="7521249148445456662">"Вашыя паведамленні"</string>
- <!-- outdated translation 7045736972019211994 --> <string name="permgroupdesc_messages" msgid="7821999071003699236">"Чытайце і пішыце вашыя паведамленні электроннай пошты, SMS і г. д."</string>
+ <string name="permgroupdesc_messages" msgid="7821999071003699236">"Счытваць і запісваць вашы SMS-паведамленні, паведамленні электроннай пошты і іншыя паведамленні."</string>
<string name="permgrouplab_personalInfo" msgid="3519163141070533474">"Вашая персанальная інфармацыя"</string>
<string name="permgroupdesc_personalInfo" product="tablet" msgid="6975389054186265786">"Прамы доступ да кантактаў і календара, якія захоўваюцца на планшэце."</string>
<string name="permgroupdesc_personalInfo" product="default" msgid="5488050357388806068">"Прамы доступ да кантактаў і календара, захаваных на тэлефоне."</string>
<string name="permgrouplab_location" msgid="635149742436692049">"Ваша месцазнаходжанне"</string>
- <string name="permgroupdesc_location" msgid="2430258821648348660">"Кантралюйце сваё фізічнае месцазнаходжанне"</string>
+ <string name="permgroupdesc_location" msgid="5704679763124170100">"Кантраляваць сваё фізічнае месцазнаходжанне."</string>
<string name="permgrouplab_network" msgid="5808983377727109831">"Сеткавая сувязь"</string>
- <!-- outdated translation 5035763698958415998 --> <string name="permgroupdesc_network" msgid="4917593670797570584">"Дазволіць прыкладанням атрымліваць доступ да розных функцый сеткі."</string>
+ <string name="permgroupdesc_network" msgid="4478299413241861987">"Доступ да розных функцый сеткі."</string>
<string name="permgrouplab_accounts" msgid="3359646291125325519">"Вашыя ўліковыя запісы"</string>
<string name="permgroupdesc_accounts" msgid="4948732641827091312">"Доступ да дзеючых уліковых запісаў."</string>
<string name="permgrouplab_hardwareControls" msgid="7998214968791599326">"Кіраванне апаратным забеспячэннем"</string>
@@ -176,352 +179,358 @@
<string name="permgrouplab_systemTools" msgid="4652191644082714048">"Сістэмныя інструменты"</string>
<string name="permgroupdesc_systemTools" msgid="8162102602190734305">"Ніжні ўзровень доступу і кіравання сістэмай."</string>
<string name="permgrouplab_developmentTools" msgid="3446164584710596513">"Сродкі распрацоўкі"</string>
- <!-- outdated translation 9056431193893809814 --> <string name="permgroupdesc_developmentTools" msgid="7058828032358142018">"Функцыі, патрэбныя толькі для распрацоўшчыкаў прыкладанняў."</string>
+ <string name="permgroupdesc_developmentTools" msgid="7058828032358142018">"Функцыi, патрэбныя толькі для распрацоўшчыкаў прыкладанняў."</string>
<string name="permgrouplab_storage" msgid="1971118770546336966">"Сховішча"</string>
<string name="permgroupdesc_storage" product="nosdcard" msgid="7442318502446874999">"Атрымаць доступ да USB-назапашвальнiка."</string>
<string name="permgroupdesc_storage" product="default" msgid="9203302214915355774">"Доступ да SD-карты."</string>
<string name="permlab_statusBar" msgid="7417192629601890791">"адключаць ці змяняць радок стану"</string>
- <!-- outdated translation 1365473595331989732 --> <string name="permdesc_statusBar" msgid="8434669549504290975">"Дазваляе прыкладанням адключаць радок стану або дадаваць і выдаляць сістэмныя значкі."</string>
+ <string name="permdesc_statusBar" msgid="8434669549504290975">"Дазваляе прыкладанням адключаць радок стану або дадаваць і выдаляць сістэмныя значкі."</string>
<string name="permlab_statusBarService" msgid="7247281911387931485">"радок стану"</string>
- <!-- outdated translation 4097605867643520920 --> <string name="permdesc_statusBarService" msgid="716113660795976060">"Дазваляе прыкладанням быць радком стану."</string>
+ <string name="permdesc_statusBarService" msgid="716113660795976060">"Дазваляе прыкладанням быць радком стану."</string>
<string name="permlab_expandStatusBar" msgid="1148198785937489264">"разгарнуць/згарнуць радок стану"</string>
- <!-- outdated translation 7088604400110768665 --> <string name="permdesc_expandStatusBar" msgid="6917549437129401132">"Дазваляе прыкладанням разгортваць або згортваць панэль стану."</string>
+ <string name="permdesc_expandStatusBar" msgid="6917549437129401132">"Дазваляе прыкладанню разгортваць ці згортваць радок стану."</string>
<string name="permlab_processOutgoingCalls" msgid="1136262550878335980">"перахапляць выходныя выклікі"</string>
- <!-- outdated translation 2228988201852654461 --> <string name="permdesc_processOutgoingCalls" msgid="1152111671618301044">"Дазваляе прыкладанням апрацоўваць выходныя выклікі і змяняць набіраны нумар. Шкоднасныя прыкладанні могуць адсочваць, перанакіроўваць ці забараняць выходныя выклікі."</string>
+ <string name="permdesc_processOutgoingCalls" msgid="1152111671618301044">"Дазваляе прыкладанням апрацоўваць выходныя выклікі і змяняць набіраны нумар. Шкоднасныя прыкладаннi могуць адсочваць, перанакіроўваць ці прадухіляць выходныя выклікі."</string>
<string name="permlab_receiveSms" msgid="2697628268086208535">"атрымліваць SMS"</string>
- <!-- outdated translation 6298292335965966117 --> <string name="permdesc_receiveSms" msgid="8107887121893611793">"Дазваляе прыкладанням атрымліваць і апрацоўваць SMS. Шкоднасныя прыкладанні могуць адсочваць вашыя паведамленні або выдаляць іх, не паказваючы вам."</string>
+ <string name="permdesc_receiveSms" msgid="8107887121893611793">"Дазваляе прыкладанням атрымліваць і апрацоўваць SMS-паведамленні. Шкоднасныя прыкладанні могуць адсочваць вашыя паведамленні або выдаляць іх, не паказваючы вам."</string>
<string name="permlab_receiveMms" msgid="8894700916188083287">"атрымліваць MMS"</string>
- <!-- outdated translation 4563346832000174373 --> <string name="permdesc_receiveMms" msgid="1424805308566612086">"Дазваляе прыкладанням атрымліваць і апрацоўваць паведамленні MMS. Шкоднасныя прыкладанні могуць адсочваць вашыя паведамленні або выдаляць іх без вашага ведама."</string>
+ <string name="permdesc_receiveMms" msgid="1424805308566612086">"Дазваляе прыкладанням атрымліваць і апрацоўваць MMS-паведамленні. Шкоднасныя прыкладанні могуць адсочваць вашы паведамленні або выдаляць іх, не паказваючы вам."</string>
<string name="permlab_receiveEmergencyBroadcast" msgid="1803477660846288089">"атрымліваць экстраныя трансляцыі"</string>
- <!-- outdated translation 7118393393716546131 --> <string name="permdesc_receiveEmergencyBroadcast" msgid="848524070262431974">"Дазваляе прыкладанням атрымліваць і апрацоўваць экстраныя шырокавяшчальныя паведамленні. Гэты дазвол даступны толькі для сістэмных прыкладанняў."</string>
+ <string name="permdesc_receiveEmergencyBroadcast" msgid="848524070262431974">"Дазваляе прыкладанням атрымліваць і апрацоўваць экстраныя паведамленні. Гэты дазвол даступны толькі для сістэмных прыкладанняў."</string>
<string name="permlab_sendSms" msgid="5600830612147671529">"адпраўляць SMS"</string>
- <!-- outdated translation 1946540351763502120 --> <string name="permdesc_sendSms" msgid="906546667507626156">"Дазваляе прыкладанням адпраўляць SMS. Шкоднасныя прыкладанні могуць траціць вашыя грошы шляхам адпраўкі паведамленняў без пацверджання карыстальніка."</string>
+ <string name="permdesc_sendSms" msgid="906546667507626156">"Дазваляе прыкладанням дасылаць SMS-паведамленні. Шкоднасныя прыкладанні могуць каштаваць вам грошай з-за адпраўкі паведамленняў без вашага пацвярджэння."</string>
<string name="permlab_sendSmsNoConfirmation" msgid="4781483105951730228">"адпраўляць SMS-паведамленні без пацверджання"</string>
- <!-- outdated translation 4477752891276276168 --> <string name="permdesc_sendSmsNoConfirmation" msgid="3437759207020400204">"Дазваляе прыкладанням адпраўляць SMS. Шкоднасныя прыкладанні могуць спісваць вашыя грошы, адпраўляючы паведамленні без вашага пацверджання."</string>
+ <string name="permdesc_sendSmsNoConfirmation" msgid="3437759207020400204">"Дазваляе прыкладанню дасылаць SMS-паведамленні. Шкоднасныя прыкладанні могуць каштаваць вам грошай з-за адпраўкі паведамленняў без вашага пацверджання."</string>
<string name="permlab_readSms" msgid="4085333708122372256">"чытаць SMS або MMS"</string>
- <!-- outdated translation 5836710350295631545 --> <string name="permdesc_readSms" product="tablet" msgid="2341692916884515613">"Дазваляе прыкладанням чытаць SMS, якія захоўваюцца на планшэце ці на SIM-карце. Шкоднасныя прыкладанні могуць чытаць вашыя канфідэнцыйныя паведамленні."</string>
- <!-- outdated translation 5836710350295631545 --> <string name="permdesc_readSms" product="default" msgid="5653850482025875493">"Дазваляе прыкладанням чытаць SMS, якія захоўваюцца на планшэце ці на SIM-карце. Шкоднасныя прыкладанні могуць чытаць вашыя канфідэнцыйныя паведамленні."</string>
+ <string name="permdesc_readSms" product="tablet" msgid="2341692916884515613">"Дазваляе прыкладанням чытаць SMS-паведамленні, якія захоўваюцца на планшэце ці SIM-карце. Шкоднасныя прыкладанні могуць чытаць вашы канфідэнцыйныя паведамленні."</string>
+ <string name="permdesc_readSms" product="default" msgid="5653850482025875493">"Дазваляе прыкладанню счытваць SMS-паведамленні, якія захоўваюцца ў тэлефоне або на SIM-карце. Шкоднасныя прыкладанні могуць чытаць вашы канфідэнцыйныя паведамленні."</string>
<string name="permlab_writeSms" msgid="6881122575154940744">"рэдагаваць SMS ці MMS"</string>
- <!-- outdated translation 5332124772918835437 --> <string name="permdesc_writeSms" product="tablet" msgid="5160413947794501538">"Дазваляе прыкладанню запіс ў SMS паведамленнях, якія захоўваюцца на планшэце ці на SIM-карце. Шкоднасныя прыкладанні могуць выдаляць вашыя паведамленні."</string>
- <!-- outdated translation 5332124772918835437 --> <string name="permdesc_writeSms" product="default" msgid="7268668709052328567">"Дазваляе прыкладанню запіс ў SMS паведамленнях, якія захоўваюцца на планшэце ці на SIM-карце. Шкоднасныя прыкладанні могуць выдаляць вашыя паведамленні."</string>
+ <string name="permdesc_writeSms" product="tablet" msgid="5160413947794501538">"Дазваляе прыкладанню запісваць дадзеныя ў SMS-паведамленні, якія захоўваюцца на планшэце або на SIM-карце. Шкоднасныя прыкладанні могуць выдаляць вашы паведамленні."</string>
+ <string name="permdesc_writeSms" product="default" msgid="7268668709052328567">"Дазваляе прыкладанням запісваць дадзеныя ў SMS-паведамленні, якія захоўваюцца ў тэлефоне або на SIM-карце. Шкоднасныя прыкладанні могуць выдаляць вашы паведамленні."</string>
<string name="permlab_receiveWapPush" msgid="8258226427716551388">"атрымліваць WAP"</string>
- <!-- outdated translation 5979623826128082171 --> <string name="permdesc_receiveWapPush" msgid="7983455145335316872">"Дазваляе прыкладанням атрымліваць і апрацоўваць WAP-паведамленні. Шкоднасныя прыкладанні могуць адсочваць вашыя паведамленні або выдаляць іх, не паказваючы вам."</string>
- <!-- outdated translation 5005277531132573353 --> <string name="permlab_getTasks" msgid="6466095396623933906">"атрымліваць запушчаныя прыкладанні"</string>
- <!-- outdated translation 7048711358713443341 --> <string name="permdesc_getTasks" msgid="6608159250520381359">"Дазваляе прыкладанням атрымліваць інфармацыю аб бягучых і нядаўна запушчаных задачах. Можа дазволіць шкоднасным прыкладаннм выяўляць асабістую інфармацыю аб іншых прыкладаннях."</string>
- <!-- outdated translation 5669588525059921549 --> <string name="permlab_reorderTasks" msgid="2018575526934422779">"змяняць парадак запуску прыкладанняў"</string>
- <!-- outdated translation 126252774270522835 --> <string name="permdesc_reorderTasks" msgid="4175137612205663399">"Дазваляе прыкладанням перамяшчаць задачы на пярэдні план і ў фон. Шкоднасныя прыкладанні могуць прымусова перамясціць сябе на пярэдні план без вашага кантролю."</string>
- <!-- outdated translation 4802740047161700683 --> <string name="permlab_removeTasks" msgid="6821513401870377403">"спыненне запушчаных прыкладанняў"</string>
- <!-- outdated translation 2000332928514575461 --> <string name="permdesc_removeTasks" msgid="1000226123143185094">"Дазваляе прыкладанням выдаляць задачы і спыняць адпаведныя прыкладанні. Шкоднасныя прыкладаннi могуць паўплываць на функцыянаванне іншых прыкладанняў."</string>
- <!-- outdated translation 4339730312925176742 --> <string name="permlab_setDebugApp" msgid="3022107198686584052">"уключаць адладку прыкладанняў"</string>
- <!-- outdated translation 5584310661711990702 --> <string name="permdesc_setDebugApp" msgid="6215654419903651172">"Дазваляе прыкладанням уключаць адладку іншых прыкладанняў. Шкоднасныя прыкладаннi могуць карыстацца гэтым, каб спыняць іншыя прыкладанні."</string>
+ <string name="permdesc_receiveWapPush" msgid="7983455145335316872">"Дазваляе прыкладанням атрымліваць і апрацоўваць WAP-паведамленні. Шкоднасныя прыкладанні могуць адсочваць вашы паведамленні або выдаляць іх, не паказваючы вам."</string>
+ <string name="permlab_getTasks" msgid="6466095396623933906">"атрымаць запушчаныя прыкладанні"</string>
+ <string name="permdesc_getTasks" msgid="6608159250520381359">"Дазваляе прыкладанням атрымліваць інфармацыю пра бягучыя і нядаўна запушчаныя заданнi. Шкоднасныя прыкладанні могуць атрымліваць асабістую інфармацыю пра іншыя прыкладаннi."</string>
+ <string name="permlab_reorderTasks" msgid="2018575526934422779">"змяніць парадак запушчаных прыкладанняў"</string>
+ <string name="permdesc_reorderTasks" msgid="4175137612205663399">"Дазваляе прыкладанням перамяшчаць заданні на пярэдні план і фон. Шкоднасныя прыкладанні могуць прымусова рабіць сябе асноўнымі без вашага ведама."</string>
+ <string name="permlab_removeTasks" msgid="6821513401870377403">"спыніць запушчаныя прыкладанні"</string>
+ <string name="permdesc_removeTasks" msgid="1394714352062635493">"Дазваляе прыкладанням выдаляць заданні і спыняць прыкладанні, якія іх выкарыстоўваюць. Шкоднасныя прыкладаннi могуць перашкодзiць працы іншых прыкладанняў."</string>
+ <string name="permlab_setDebugApp" msgid="3022107198686584052">"уключыць адладку прыкладання"</string>
+ <string name="permdesc_setDebugApp" msgid="4474512416299013256">"Дазваляе прыкладанням уключаць адладку для іншага прыкладання. Шкоднасныя прыкладанні могуць выкарыстоўваць гэта, каб спыняць іншыя прыкладанні."</string>
<string name="permlab_changeConfiguration" msgid="8214475779521218295">"змяняць налады карыстальніцкага інтэрфейса"</string>
- <!-- outdated translation 3465121501528064399 --> <string name="permdesc_changeConfiguration" msgid="4104052649900380324">"Дазваляе прыкладанням змяняць бягучую канфігурацыю, напрыклад мову i агульны памер шрыфта."</string>
+ <string name="permdesc_changeConfiguration" msgid="4372223873154296076">"Дазваляе прыкладанням змяняць бягучую канфігурацыю, напрыклад мову цi агульны памер шрыфта."</string>
<string name="permlab_enableCarMode" msgid="5684504058192921098">"дазваляць рэжым \"У аўтамабілі\""</string>
- <!-- outdated translation 5673461159384850628 --> <string name="permdesc_enableCarMode" msgid="4853187425751419467">"Дазваляе прыкладанням уключаць рэжым \"У аўтамабілі\"."</string>
+ <string name="permdesc_enableCarMode" msgid="4853187425751419467">"Дазваляе прыкладанню ўключаць рэжым гучнай сувязi."</string>
<string name="permlab_killBackgroundProcesses" msgid="8373714752793061963">"выдаліць фонавыя працэсы"</string>
- <!-- outdated translation 2908829602869383753 --> <string name="permdesc_killBackgroundProcesses" msgid="931129103262126617">"Дазваляе прыкладанням спыняць фонавыя працэсы іншых прыкладанняў, нават калі памяці дастаткова."</string>
- <!-- outdated translation 1447830113260156236 --> <string name="permlab_forceStopPackages" msgid="2329627428832067700">"прымусова спыняць іншыя прыкладанні"</string>
- <!-- outdated translation 7263036616161367402 --> <string name="permdesc_forceStopPackages" msgid="5253157296183940812">"Дазваляе прыкладанню прымусова спыняць іншыя прыкладанні."</string>
- <!-- outdated translation 1804196839880393631 --> <string name="permlab_forceBack" msgid="652935204072584616">"прымусова закрываць прыкладанні"</string>
- <!-- outdated translation 6534109744159919013 --> <string name="permdesc_forceBack" msgid="3892295830419513623">"Дазваляе прыкладанням прымусова спыняць усе актыўныя працэсы і працягваць працу. Ніколі не патрабуецца для звычайных прыкладанняў."</string>
+ <string name="permdesc_killBackgroundProcesses" msgid="931129103262126617">"Дазваляе прыкладанням спыняць фонавыя працэсы іншых прыкладанняў, нават калі памяці дастаткова."</string>
+ <string name="permlab_forceStopPackages" msgid="2329627428832067700">"прымусова спыніць іншыя прыкладанні"</string>
+ <string name="permdesc_forceStopPackages" msgid="5253157296183940812">"Дазваляе прыкладанням прымусова спыняць іншыя прыкладанні."</string>
+ <string name="permlab_forceBack" msgid="652935204072584616">"прымусова закрыць прыкладанне"</string>
+ <string name="permdesc_forceBack" msgid="3892295830419513623">"Дазваляе прыкладанням прымусова закрываць любы асноўны працэс. Не патрабуецца для звычайных прыкладанняў."</string>
<string name="permlab_dump" msgid="1681799862438954752">"атрымліваць унутраны стан сістэмы"</string>
- <!-- outdated translation 2198776174276275220 --> <string name="permdesc_dump" msgid="1778299088692290329">"Дазваляе прыкладанням атрымліваць інфармацыю аб унутраным стане сістэмы. Шкодныя прыкладанні могуць атрымлiваць шырокі спектр прыватнай і абараняемай інфармацыі, якая звычайна ніколі ім не патрабуецца."</string>
+ <string name="permdesc_dump" msgid="1778299088692290329">"Дазваляе прыкладанням атрымліваць інфармацыю аб унутраным стане сістэмы. Шкоднасныя прыкладанні могуць атрымліваць шырокі спектр прыватных дадзеных і дадзеных, прызначаных для забеспячэння бяспекі інфармацыі, якія звычайна ім не патрэбны."</string>
<string name="permlab_retrieve_window_content" msgid="8022588608994589938">"атрыманне зместу экрана"</string>
- <!-- outdated translation 3390962289797156152 --> <string name="permdesc_retrieve_window_content" msgid="3193269069469700265">"Дазваляе прыкладанням атрымліваць змест актыўнага акна. Шкоднасныя прыкладаннi могуць атрымаць увесь змест акна і вывучыць увесь яго тэкст, акрамя пароляў."</string>
+ <string name="permdesc_retrieve_window_content" msgid="3193269069469700265">"Дазваляе прыкладанням атрымліваць змесціва актыўнага акна. Шкоднасныя прыкладанні могуць атрымліваць усё змесціва акна і разглядаць увесь яго тэкст, акрамя пароляў."</string>
<string name="permlab_shutdown" msgid="7185747824038909016">"частковае адключэнне"</string>
<string name="permdesc_shutdown" msgid="7046500838746291775">"Спыняе дзейнасць менеджэра. Не выконвае поўнае адключэнне."</string>
<string name="permlab_stopAppSwitches" msgid="4138608610717425573">"прадухіляць пераключэнне прыкладанняў"</string>
- <!-- outdated translation 3857886086919033794 --> <string name="permdesc_stopAppSwitches" msgid="8262195802582255021">"Прадухіляе карыстальнікаў ад пераходу на іншае прыкладанне."</string>
- <!-- outdated translation 7811586187574696296 --> <string name="permlab_runSetActivityWatcher" msgid="892239094867182656">"адсочваць усе запускі прыкладанняў і кіраваць iмi"</string>
- <!-- outdated translation 2149363027173451218 --> <string name="permdesc_runSetActivityWatcher" msgid="6003603162578577406">"Дазваляе прыкладанню сачыць за тым, як сістэма запускае працэсы, i кiраваць гэтым дзеяннем. Шкоднасныя прыкладанні могуць цалкам негатыўна паўсплываць на сістэму. Гэты дазвол неабходны толькі для распрацоўкі, не для звычайнага выкарыстання."</string>
+ <string name="permdesc_stopAppSwitches" msgid="8262195802582255021">"Не дазваляе карыстальніку пераходзіць да іншага прыкладання."</string>
+ <string name="permlab_runSetActivityWatcher" msgid="892239094867182656">"адсочваць і кантраляваць запуск усіх прыкладанняў"</string>
+ <string name="permdesc_runSetActivityWatcher" msgid="6003603162578577406">"Дазваляе прыкладанню сачыць і кантраляваць, як сістэма запускае працэсы. Шкоднасныя прыкладанні могуць цалкам парушыць працу сістэмы. Гэты дазвол патрэбны толькі для распрацоўкі, ніколі для звычайнага выкарыстання."</string>
<string name="permlab_broadcastPackageRemoved" msgid="2576333434893532475">"трансляваць паведамленні аб выдаленні пакетаў"</string>
- <!-- outdated translation 3453286591439891260 --> <string name="permdesc_broadcastPackageRemoved" msgid="6621901216207931089">"Дазваляе прыкладанням трансліраваць апавяшчэнне аб тым, што пакет прыкладання быў выдалены. Шкоднасныя прыкладанні могуць выкарыстоўваць гэта, каб спыніць любое іншае запушчанае прыкладанне."</string>
+ <string name="permdesc_broadcastPackageRemoved" msgid="6621901216207931089">"Дазваляе прыкладанням перадаваць апавяшчэнне, што пакет прыкладанняў быў выдалены. Шкоднасныя прыкладанні могуць выкарыстоўваць гэта, каб спыняць любыя іншыя запушчаныя прыкладанні."</string>
<string name="permlab_broadcastSmsReceived" msgid="5689095009030336593">"перасылаць трансляцыі, атрыманыя па SMS"</string>
- <!-- outdated translation 9122419277306740155 --> <string name="permdesc_broadcastSmsReceived" msgid="4152037720034365492">"Дазваляе прыкладанню трансляваць апавяшчэнне, што паведамленне SMS атрыманае. Шкоднасныя прыкладанні могуць выкарыстоўваць гэта, каб падрабляць уваходныя паведамленні SMS."</string>
+ <string name="permdesc_broadcastSmsReceived" msgid="4152037720034365492">"Дазваляе прыкладанням перадаваць апавяшчэнне пра атрыманне SMS-паведамлення. Шкоднасныя прыкладанні могуць выкарыстоўваць гэта, каб падрабляць уваходныя SMS-паведамленні."</string>
<string name="permlab_broadcastWapPush" msgid="3145347413028582371">"пасылаць сігнал WAP-PUSH-received"</string>
- <!-- outdated translation 3955303669461378091 --> <string name="permdesc_broadcastWapPush" msgid="4783402525039442729">"Дазваляе прыкладанням трансляваць апавяшчэнне аб атрыманні паведамлення WAP PUSH. Шкоднасныя прыкладаннi могуць карыстацца гэтым, каб падрабляць атрыманне MMS-паведамленняў ці моўчкі мяняць змест любых вэб-старонак на шкодны."</string>
+ <string name="permdesc_broadcastWapPush" msgid="4783402525039442729">"Дазваляе прыкладанням перадаваць апавяшчэнне, што паведамленне WAP PUSH не было атрымана. Шкоднасныя прыкладанні могуць выкарыстоўваць гэта, каб падрабляць атрыманне MMS-паведамлення або непрыкметна замяняць змесціва любой вэб-старонкі на шкоднасную версiю."</string>
<string name="permlab_setProcessLimit" msgid="2451873664363662666">"абмяжоўваць колькасць запушчаных працэсаў"</string>
- <!-- outdated translation 7824786028557379539 --> <string name="permdesc_setProcessLimit" msgid="7318061314040879542">"Дазваляе прыкладанням кантраляваць максімальную колькасць працэсаў, якія будуць працаваць. Ніколі не патрабуецца для звычайных прыкладанняў."</string>
- <!-- outdated translation 5342837862439543783 --> <string name="permlab_setAlwaysFinish" msgid="238828158465736054">"закрываць усе фонавыя прыкладанні"</string>
- <!-- outdated translation 8773936403987091620 --> <string name="permdesc_setAlwaysFinish" msgid="7471310652868841499">"Дазваляе прыкладанню кантраляваць завяршэнне дзеянняў падчас іх пераходу ў фон. Ніколі не патрабуецца для звычайных прыкладанняў."</string>
+ <string name="permdesc_setProcessLimit" msgid="7318061314040879542">"Дазваляе прыкладанням кантраляваць максімальную колькасць запушчаных працэсаў. Не патрабуецца для звычайных прыкладанняў."</string>
+ <string name="permlab_setAlwaysFinish" msgid="238828158465736054">"закрывае ўсе фонавыя прыкладанні"</string>
+ <string name="permdesc_setAlwaysFinish" msgid="7471310652868841499">"Дазваляе прыкладанням кантраляваць, ці будуць працэсы заўсёды завяршацца, як толькі яны пераходзяць у фонавы рэжым. Не патрабуецца для звычайных прыкладанняў."</string>
<string name="permlab_batteryStats" msgid="7863923071360031652">"змяняць статыстыку батарэі"</string>
- <!-- outdated translation 5847319823772230560 --> <string name="permdesc_batteryStats" msgid="6835186932305744068">"Дазваляе мяняць сабраную статыстыку акумулятара. Не выкарыстоўваецца звычайнымі прыкладаннямі."</string>
+ <string name="permdesc_batteryStats" msgid="6835186932305744068">"Дазваляе прыкладанням змяняць сабраную статыстыку акумулятара. Не для выкарыстання звычайнымі прыкладаннямі."</string>
<string name="permlab_backup" msgid="470013022865453920">"кантраляваць рэзервовае капіяванне і аднаўленне сістэмы"</string>
- <!-- outdated translation 4837493065154256525 --> <string name="permdesc_backup" msgid="6912230525140589891">"Дазваляе прыкладанням кантраляваць механізм рэзервовага капіявання і аднаўлення сістэмы. Не выкарыстоўваецца звычайнымі прыкладаннямі."</string>
+ <string name="permdesc_backup" msgid="6912230525140589891">"Дазваляе прыкладанням кантраляваць рэзервовае капіяванне сістэмы і механізм аднаўлення. Не патрабуецца для звычайных прыкладанняў."</string>
<string name="permlab_confirm_full_backup" msgid="5557071325804469102">"пацверджанне поўнага рэзервовага капіявання або аднаўлення"</string>
- <!-- outdated translation 9005017754175897954 --> <string name="permdesc_confirm_full_backup" msgid="1748762171637699562">"Дазваляе прыкладанням запускаць інтэрфейс пацверджання поўнага рэзервовага капіявання. Выкарыстоўваецца не ўсімі прыкладаннямі."</string>
+ <string name="permdesc_confirm_full_backup" msgid="1748762171637699562">"Дазваляе прыкладанням запускаць поўны інтэрфейс карыстальніка пацвярджэння рэзервавання. Не для выкарыстання звычайнымі прыкладаннямі."</string>
<string name="permlab_internalSystemWindow" msgid="2148563628140193231">"паказваць несанкцыянаваныя вокны"</string>
- <!-- outdated translation 5895082268284998469 --> <string name="permdesc_internalSystemWindow" msgid="6510907081810231374">"Дазваляе ствараць вокны, прызначаныя для ўнутранай сістэмы карыстальніцкага інтэрфейса. Не выкарыстоўваецца звычайнымі прыкладаннямі."</string>
+ <string name="permdesc_internalSystemWindow" msgid="7458387759461466397">"Дазваляе прыкладанням ствараць вокны, прызначаныя для выкарыстання ўнутраным інтэрфейсам карыстальніка сістэмы. Не для выкарыстання звычайнымі прыкладаннямі."</string>
<string name="permlab_systemAlertWindow" msgid="3372321942941168324">"паказваць абвесткі стану сістэмы"</string>
- <!-- outdated translation 2884149573672821318 --> <string name="permdesc_systemAlertWindow" msgid="8507863469978066409">"Дазваляе прыкладанню паказваць вокны сiстэмных паведамленняў. Шкоднасныя прыкладанні могуць заняць увесь экран."</string>
+ <string name="permdesc_systemAlertWindow" msgid="8507863469978066409">"Дазваляе прыкладанням паказваць вокны апавяшчэння сістэмы. Шкоднасныя прыкладанні могуць захоплiваць увесь экран."</string>
<string name="permlab_setAnimationScale" msgid="2805103241153907174">"зменяць агульную хуткасць анімацыі"</string>
- <!-- outdated translation 7181522138912391988 --> <string name="permdesc_setAnimationScale" msgid="6505093307223395456">"Дазваляе прыкладанням у любы час мяняць агульную хуткасць анімацыі (хутчэй ці павольней)."</string>
- <!-- outdated translation 17124341698093865 --> <string name="permlab_manageAppTokens" msgid="1286505717050121370">"кіраваць меткамі прыкладанняў"</string>
- <!-- outdated translation 977127907524195988 --> <string name="permdesc_manageAppTokens" msgid="8043431713014395671">"Дазваляе прыкладанням ствараць уласныя квіткі і кіраваць імі, у абыход нармальнага Z-упарадкавання. Не патрабуецца для звычайных прыкладанняў."</string>
+ <string name="permdesc_setAnimationScale" msgid="7690063428924343571">"Дазваляе прыкладанням у любы час змяняць агульную хуткасць анімацыі (хутчэй ці павольней)."</string>
+ <string name="permlab_manageAppTokens" msgid="1286505717050121370">"кіраваць ключамі прыкладання"</string>
+ <string name="permdesc_manageAppTokens" msgid="8043431713014395671">"Дазваляе прыкладанням ствараць сваімі ўласнымі ключамі, абыходзячы іх звычайны Z-парадак. Не патрабуецца для звычайных прыкладанняў."</string>
<string name="permlab_injectEvents" msgid="1378746584023586600">"націскаць клавішы і кнопкі кіравання"</string>
- <!-- outdated translation 7200014808195664505 --> <string name="permdesc_injectEvents" product="tablet" msgid="206352565599968632">"Дазваляе прыкладанням ажыццяўляць свае ўласныя працэсы ўводу (націску клавіш і г. д.) для іншых прыкладанняў. Шкоднасныя прыкладанні могуць выкарыстоўваць гэта, каб атрымаць кантроль над планшэтам."</string>
- <!-- outdated translation 7200014808195664505 --> <string name="permdesc_injectEvents" product="default" msgid="653128057572326253">"Дазваляе прыкладанням ажыццяўляць свае ўласныя працэсы ўводу (націску клавіш і г. д.) для іншых прыкладанняў. Шкоднасныя прыкладанні могуць выкарыстоўваць гэта, каб атрымаць кантроль над планшэтам."</string>
+ <string name="permdesc_injectEvents" product="tablet" msgid="206352565599968632">"Дазваляе прыкладанням ажыццяўляць свае ўласныя падзеі ўводу (націску клавіш і г.д.) для іншых прыкладанняў. Шкоднасныя прыкладанні могуць выкарыстоўваць гэта, каб захапіць кіраванне планшэтам."</string>
+ <string name="permdesc_injectEvents" product="default" msgid="653128057572326253">"Дазваляе прыкладанню ажыццяўляць свае ўласныя падзеі ўводу (націску клавіш і г. д.) для іншых прыкладанняў. Шкоднасныя прыкладанні могуць выкарыстоўваць гэта, каб захапіць кіраванне тэлефонам."</string>
<string name="permlab_readInputState" msgid="469428900041249234">"запісваць, што вы друкуеце, і дзеянні, якія вы прадпрымаеце"</string>
- <!-- outdated translation 5132879321450325445 --> <string name="permdesc_readInputState" msgid="8387754901688728043">"Дазваляе прыкладанням праглядаць клавішы, якія вы націскаеце, нават пры ўзаемадзеянні з іншым прыкладаннем (напрыклад, пры ўводзе пароля). Не патрабуецца для звычайных прыкладанняў."</string>
+ <string name="permdesc_readInputState" msgid="8387754901688728043">"Дазваляе прыкладанням адсочваць клавішы, якія вы націскаеце, нават падчас узаемадзеяння з іншым прыкладаннем (напрыклад, пры ўводзе пароля). Не патрабуецца для звычайных прыкладанняў."</string>
<string name="permlab_bindInputMethod" msgid="3360064620230515776">"звязацца з метадам уводу"</string>
- <!-- outdated translation 3734838321027317228 --> <string name="permdesc_bindInputMethod" msgid="3250440322807286331">"Дазваляе ўладальніку звязвацца з інтэрфейсам верхняга ўзроўню метадам уводу. Не патрабуецца для звычайных прыкладанняў."</string>
+ <string name="permdesc_bindInputMethod" msgid="3250440322807286331">"Дазваляе ўладальніку прывязвацца да інтэрфейсу верхняга ўзроўню метада ўводу. Не патрабуецца для звычайных прыкладанняў."</string>
<string name="permlab_bindTextService" msgid="7358378401915287938">"звязаць з тэкставай службай"</string>
- <!-- outdated translation 172508880651909350 --> <string name="permdesc_bindTextService" msgid="8151968910973998670">"Дазваляе ўладальніку звязвацца з інтэрфейсам верхняга ўзроўню тэкставай паслугі (напрыклад, SpellCheckerService). Ніколі не патрабуецца звычайным прыкладанням."</string>
+ <string name="permdesc_bindTextService" msgid="8151968910973998670">"Дазваляе ўладальніку прывязвацца да інтэрфейсу верхняга ўзроўню тэкставай паслугі (напрыклад, SpellCheckerService). Ніколі не патрабуецца для звычайных прыкладанняў."</string>
<string name="permlab_bindVpnService" msgid="4708596021161473255">"звязвацца з VPN сэрвісам"</string>
- <!-- outdated translation 6011554199384584151 --> <string name="permdesc_bindVpnService" msgid="2067845564581693905">"Дазваляе ўладальніку звязвацца з інтэрфейсам VPN службы вышэйшага ўзроўню. Не патрэбна для звычайных праграм."</string>
+ <string name="permdesc_bindVpnService" msgid="2067845564581693905">"Дазваляе ўладальніку звязвацца з інтэрфейсам службы VPN вышэйшага ўзроўню. Не патрэбна для звычайных прыкладанняў."</string>
<string name="permlab_bindWallpaper" msgid="8716400279937856462">"прывязаць да шпалер"</string>
- <!-- outdated translation 5287754520361915347 --> <string name="permdesc_bindWallpaper" msgid="7108428692595491668">"Дазваляе ўладальніку ўсталёўваць прывязку да інтэрфейсу шпалер верхняга ўзроўню. Не патрабуецца для звычайных прыкладанняў."</string>
+ <string name="permdesc_bindWallpaper" msgid="7108428692595491668">"Дазваляе ўладальніку ўсталёўваць прывязку да інтэрфейсу шпалер верхняга ўзроўню. Не патрабуецца для звычайных прыкладанняў."</string>
<string name="permlab_bindRemoteViews" msgid="5697987759897367099">"прывязаць да службы віджэту"</string>
- <!-- outdated translation 2930855984822926963 --> <string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Дазваляе ўладальніку прывязаць верхні ўзровень інтэрфейсу службы віджэта. Не патрабуецца для звычайных прыкладанняў."</string>
+ <string name="permdesc_bindRemoteViews" msgid="4717987810137692572">"Дазваляе ўладальніку прывязвацца да інтэрфейсу верхняга ўзроўню службы віджэта. Не патрабуецца для звычайных прыкладанняў."</string>
<string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"узаемадзейнічаць з адміністратарам прылады"</string>
- <!-- outdated translation 8714424333082216979 --> <string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"Дазваляе ўладальніку адпраўляць намеры да адміністратара прылады. Не патрабуецца для звычайных прыкладанняў."</string>
+ <string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"Дазваляе ўладальніку адпраўляць намеры да адміністратара прылады. Не патрабуецца для звычайных прыкладанняў."</string>
<string name="permlab_setOrientation" msgid="3365947717163866844">"змяняць арыентацыю экрана"</string>
- <!-- outdated translation 6335814461615851863 --> <string name="permdesc_setOrientation" msgid="3046126619316671476">"Дазваляе прыкладанням мяняць арыентацыю экрана ў любы час. Не патрабуецца для звычайных прыкладанняў."</string>
+ <string name="permdesc_setOrientation" msgid="3046126619316671476">"Дазваляе прыкладанням змяняць паварот экрана ў любы час. Не патрабуецца для звычайных прыкладанняў."</string>
<string name="permlab_setPointerSpeed" msgid="9175371613322562934">"змена хутк. перамяшч. ўказ."</string>
- <!-- outdated translation 137436038503379864 --> <string name="permdesc_setPointerSpeed" msgid="6866563234274104233">"Дазваляе прыкладанням у любы момант мяняць хуткасць перамяшчэння ўказальніка мышы ці трэкпаду. Не патрабуецца для звычайных прыкладанняў."</string>
- <!-- outdated translation 4255467255488653854 --> <string name="permlab_signalPersistentProcesses" msgid="4539002991947376659">"адпраўляць сігналы Linux да прыкладанняў"</string>
- <!-- outdated translation 3565530463215015289 --> <string name="permdesc_signalPersistentProcesses" msgid="4896992079182649141">"Дазваляе прыкладанням запытваць адпраўку прадстаўленага сігналу да ўсіх пастаянных працэсаў."</string>
- <!-- outdated translation 8659652042401085862 --> <string name="permlab_persistentActivity" msgid="8841113627955563938">"прымусіць прыкладанне працаваць заўсёды"</string>
- <!-- outdated translation 5037199778265006008 --> <string name="permdesc_persistentActivity" msgid="4909910271316074418">"Дазваляе прыкладанням рабіць свае часткі ўстойлівымі, каб сістэма не магла выкарыстоўваць іх для іншых прыкладанняў."</string>
- <!-- outdated translation 3343439331576348805 --> <string name="permlab_deletePackages" msgid="184385129537705938">"выдаляць прыкладанні"</string>
- <!-- outdated translation 3634943677518723314 --> <string name="permdesc_deletePackages" msgid="7411480275167205081">"Дазваляе прыкладанням выдаляць пакеты Android. Шкоднасныя прыкладанні могуць выкарыстоўваць гэта, каб выдаляць важныя прыкладанні."</string>
- <!-- outdated translation 2192134353540277878 --> <string name="permlab_clearAppUserData" msgid="274109191845842756">"выдаляць дадзеныя іншых прыкладанняў"</string>
- <!-- outdated translation 7546345080434325456 --> <string name="permdesc_clearAppUserData" msgid="4625323684125459488">"Дазваляе прыкладанням выдаляць дадзеныя карыстальніка."</string>
- <!-- outdated translation 1518556602634276725 --> <string name="permlab_deleteCacheFiles" msgid="3128665571837408675">"выдаляць кэш іншых прыкладанняў"</string>
- <!-- outdated translation 2283074077168165971 --> <string name="permdesc_deleteCacheFiles" msgid="3812998599006730196">"Дазваляе прыкладанням выдаляць файлы кэша."</string>
- <!-- outdated translation 4799785352306641460 --> <string name="permlab_getPackageSize" msgid="7472921768357981986">"мераць месца для захоўвання прыкладання"</string>
- <!-- outdated translation 5557253039670753437 --> <string name="permdesc_getPackageSize" msgid="3921068154420738296">"Дазваляе прыкладанням атрымліваць свой код, дадзеныя і аб\'ём кэш-памяці"</string>
- <!-- outdated translation 335800214119051089 --> <string name="permlab_installPackages" msgid="2199128482820306924">"непасрэдна ўсталёўваць прыкладанні"</string>
- <!-- outdated translation 526669220850066132 --> <string name="permdesc_installPackages" msgid="5628530972548071284">"Дазваляе прыкладанням усталёўваць новыя або абноўленыя пакеты Android. Шкоднасныя прыкладанні могуць выкарыстоўваць гэта, каб дадаваць новыя прыкладанні з дазволамі высокага ўзроўню."</string>
- <!-- outdated translation 4747698311163766540 --> <string name="permlab_clearAppCache" msgid="7487279391723526815">"выдаляць усе дадзеныя кэша прыкладання"</string>
- <!-- outdated translation 3097119797652477973 --> <string name="permdesc_clearAppCache" product="tablet" msgid="3523396284474042284">"Дазваляе прыкладанню вызваліць прастору на планшэце, выдаліўшы файлы з каталогу кэша прыкладання. Доступ да сістэмных працэсаў звычайна вельмі абмежаваны."</string>
- <!-- outdated translation 3097119797652477973 --> <string name="permdesc_clearAppCache" product="default" msgid="5067988373366292186">"Дазваляе прыкладанню вызваліць прастору на планшэце, выдаліўшы файлы з каталогу кэша прыкладання. Доступ да сістэмных працэсаў звычайна вельмі абмежаваны."</string>
- <!-- outdated translation 728454979946503926 --> <string name="permlab_movePackage" msgid="3289890271645921411">"Перамяшчэнне рэсурсаў прыкладання"</string>
- <!-- outdated translation 6323049291923925277 --> <string name="permdesc_movePackage" msgid="319562217778244524">"Дазваляе прыкладанню перамяшчаць рэсурсы прыкладання з унутранай памяці на знешні носьбіт і наадварот."</string>
+ <string name="permdesc_setPointerSpeed" msgid="6866563234274104233">"Дазваляе прыкладанням змяняць хуткасць курсору мышы або трэкпада ў любы час. Не патрабуецца для звычайных прыкладанняў."</string>
+ <string name="permlab_signalPersistentProcesses" msgid="4539002991947376659">"адправіць сігналы Linux да прыкладанняў"</string>
+ <string name="permdesc_signalPersistentProcesses" msgid="4896992079182649141">"Дазваляе прыкладанням запытваць адпраўку падаваемага сігнала для ўсiх пастаянных працэсаў."</string>
+ <string name="permlab_persistentActivity" msgid="8841113627955563938">"прымусіць прыкладанне працаваць заўсёды"</string>
+ <string name="permdesc_persistentActivity" msgid="4909910271316074418">"Дазваляе прыкладанням рабіць свае часткі пастаяннымі, каб сістэма не магла выкарыстоўваць iх для іншых прыкладанняў."</string>
+ <string name="permlab_deletePackages" msgid="184385129537705938">"выдаліць прыкладанні"</string>
+ <string name="permdesc_deletePackages" msgid="7411480275167205081">"Дазваляе прыкладанню выдаляць пакеты Android. Шкоднасныя прыкладанні могуць выкарыстоўваць гэта, каб выдаляць важныя прыкладанні."</string>
+ <string name="permlab_clearAppUserData" msgid="274109191845842756">"выдаліць дадзеныя іншых прыкладанняў"</string>
+ <string name="permdesc_clearAppUserData" msgid="4625323684125459488">"Дазваляе прыкладанням выдаляць дадзеныя карыстальніка."</string>
+ <string name="permlab_deleteCacheFiles" msgid="3128665571837408675">"выдаліць кэш-памяць іншых прыкладанняў"</string>
+ <string name="permdesc_deleteCacheFiles" msgid="3812998599006730196">"Дазваляе прыкладанню выдаляць файлы кэш-памяці."</string>
+ <string name="permlab_getPackageSize" msgid="7472921768357981986">"вымерыць прастору для захоўвання прыкладання"</string>
+ <string name="permdesc_getPackageSize" msgid="3921068154420738296">"Дазваляе прыкладанням атрымліваць яго код, дадзеныя і аб\'ём кэш-памяці"</string>
+ <string name="permlab_installPackages" msgid="2199128482820306924">"усталяваць прыкладанні непасрэдна"</string>
+ <string name="permdesc_installPackages" msgid="5628530972548071284">"Дазваляе прыкладанням ксталёўваць новыя або абноўленыя пакеты Android. Шкоднасныя прыкладанні могуць выкарыстоўваць гэта, каб дадаваць новыя прыкладаннi з дазволамі адвольнай ступені."</string>
+ <string name="permlab_clearAppCache" msgid="7487279391723526815">"выдаліць усе дадзеныя з кэш-памяці прыкладання"</string>
+ <string name="permdesc_clearAppCache" product="tablet" msgid="3523396284474042284">"Дазваляе прыкладанню вызваляць памяць планшэту, выдаляючы файлы ў каталогу кэш-памяці прыкладання. Як правіла, доступ да сістэмных працэсаў вельмі абмежаваны."</string>
+ <string name="permdesc_clearAppCache" product="default" msgid="5067988373366292186">"Дазваляе прыкладанням вызваляць памяць тэлефона, выдаляючы файлы з каталогу кэш-памяці прыкладання. Доступ да сістэмных працэсаў, як правіла, вельмі абмежаваны."</string>
+ <string name="permlab_movePackage" msgid="3289890271645921411">"перамясціць рэсурсы прыкладання"</string>
+ <string name="permdesc_movePackage" msgid="319562217778244524">"Дазваляе прыкладанням перамяшчаць рэсурсы прыкладання з унутраных на знешнія носьбіты і наадварот."</string>
<string name="permlab_readLogs" msgid="6615778543198967614">"чытаць канфідэнцыйныя дадзеныя дзённiка"</string>
- <!-- outdated translation 4077356893924755294 --> <string name="permdesc_readLogs" product="tablet" msgid="82061313293455151">"Дазваляе прыкладанням чытаць розныя файлы журналаў сістэмы. Такiм чынам можна выявiць агульную інфармацыю аб тым, што вы робіце з планшэтам, якая патэнцыйна змяшчае асабістыя або канфiдэнцыйныя звесткi."</string>
- <!-- outdated translation 4077356893924755294 --> <string name="permdesc_readLogs" product="default" msgid="2063438140241560443">"Дазваляе прыкладанням чытаць розныя файлы журналаў сістэмы. Такiм чынам можна выявiць агульную інфармацыю аб тым, што вы робіце з планшэтам, якая патэнцыйна змяшчае асабістыя або канфiдэнцыйныя звесткi."</string>
+ <string name="permdesc_readLogs" product="tablet" msgid="82061313293455151">"Дазваляе прыкладанням счытваць розныя файлы сiстэмнай гiсторыi. Такiм чынам, можна выявiць агульную інфармацыю пра тое, што вы робіце з планшэтам, у тым ліку, магчыма, асабістыя або канфiдэнцыйныя звесткi."</string>
+ <string name="permdesc_readLogs" product="default" msgid="2063438140241560443">"Дазваляе прыкладанню счытваць розныя сістэмныя файлы гiсторый. Гэта дазваляе атрымліваць агульную інфармацыю аб тым, як выкарыстоўваецца тэлефон, у тым ліку, магчыма, асабістую або прыватную інфармацыю."</string>
+ <string name="permlab_anyCodecForPlayback" msgid="715805555823881818">"для прайгравання выкарыстоўваць любы мультымедыйны дэкодэр"</string>
+ <string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"Дазваляе прыкладанням выкарыстоўваць любы ўсталяваны iнструмент для мультымедыйнага дэкадавання, каб прайграць."</string>
<string name="permlab_diagnostic" msgid="8076743953908000342">"чытаць/запісваць на дыягнастычныя рэсурсы"</string>
- <!-- outdated translation 3121238373951637049 --> <string name="permdesc_diagnostic" msgid="6608295692002452283">"Дазваляе прыкладанням счытваць і запісваць любы рэсурс, які належыць дыягнастычнай групе, напрыклад файлы распрацоўшчыка. Патэнцыйна гэта можа паўплываць на стабільнасць і бяспеку сістэмы. Гэта павінна выкарыстоўвацца ТОЛЬКІ для апаратнай дыягностыкі вытворцам або аператарам."</string>
- <!-- outdated translation 79425198834329406 --> <string name="permlab_changeComponentState" msgid="6335576775711095931">"уключаць або адключаць кампаненты прыкладання"</string>
- <!-- outdated translation 4647419365510068321 --> <string name="permdesc_changeComponentState" product="tablet" msgid="8887435740982237294">"Дазваляе прыкладанню ўключаць ці адключаць кампанент іншага прыкладання. Шкоднасныя прыкладанні могуць выкарыстоўваць гэта для адключэння важных магчымасцяў тэлефона. Трэба захоўваць асцярожнасць з гэтым дазволам, таму што гэта можа прывесці кампаненты прыкладання да непрыдатнасці, непаслядоўнасці або няўстойлівасці."</string>
- <!-- outdated translation 4647419365510068321 --> <string name="permdesc_changeComponentState" product="default" msgid="1827232484416505615">"Дазваляе прыкладанню ўключаць ці адключаць кампанент іншага прыкладання. Шкоднасныя прыкладанні могуць выкарыстоўваць гэта для адключэння важных магчымасцяў тэлефона. Трэба захоўваць асцярожнасць з гэтым дазволам, таму што гэта можа прывесці кампаненты прыкладання да непрыдатнасці, непаслядоўнасці або няўстойлівасці."</string>
- <!-- outdated translation 3393305202145172005 --> <string name="permlab_setPreferredApplications" msgid="8463181628695396391">"выбіраць пажаданыя праграмы"</string>
- <!-- outdated translation 760008293501937546 --> <string name="permdesc_setPreferredApplications" msgid="4973986762241783712">"Дазваляе прыкладанням змяняць вашы выбраныя прыкладанні. Гэта можа дазволіць шкоднасным прыкладанням незаўважна мяняць прыкладанні, якія запускаюцца, падмяняць існуючыя прыкладанні для збору вашых канфідэнцыйных дадзеных."</string>
+ <string name="permdesc_diagnostic" msgid="6608295692002452283">"Дазваляе прыкладанням счытваць і запісваць любы рэсурс, які належыць дыягнастычнай групе, напрыклад файлы распрацоўшчыка ў тэчцы /dev. Патэнцыйна гэта можа паўплываць на стабільнасць і бяспеку сістэмы. Гэта павінна выкарыстоўвацца ТОЛЬКІ для апаратнай дыягностыкі вытворцам або аператарам."</string>
+ <string name="permlab_changeComponentState" msgid="6335576775711095931">"уключыць або адключыць кампаненты прыкладання"</string>
+ <string name="permdesc_changeComponentState" product="tablet" msgid="8887435740982237294">"Дазваляе прыкладанням змяняць вызначэнне таго, будзе ўключаны кампанент іншага прыкладання ці не. Шкоднасныя прыкладанні могуць выкарыстоўваць гэта для адключэння важных магчымасцяў планшэта. З гэтым дазволам трэба быць уважлівым, бо можна прывесці кампаненты прыкладання ў непрыдатны, супярэчлівы або няўстойлівы стан."</string>
+ <string name="permdesc_changeComponentState" product="default" msgid="1827232484416505615">"Дазваляе прыкладанням змяняць вызначэнне таго, будзе ўключаны кампанент іншага прыкладання ці не. Шкоднасныя прыкладанні могуць выкарыстоўваць гэта для адключэння важных магчымасцяў тэлефона. З гэтым дазволам трэба быць уважлівым, бо можна прывесці кампаненты прыкладання ў непрыдатны, супярэчлівы або няўстойлівы стан."</string>
+ <string name="permlab_setPreferredApplications" msgid="8463181628695396391">"усталяваць пажаданыя прыкладанні"</string>
+ <string name="permdesc_setPreferredApplications" msgid="4973986762241783712">"Дазваляе прыкладанням змяняць вашы пажаданыя прыкладанні. Шкоднасныя прыкладанні могуць непрыкметна змяняць запушчаныя прыкладанні, падмяняючы існуючыя прыкладанні, каб збiраць вашы асабістыя дадзеныя."</string>
<string name="permlab_writeSettings" msgid="1365523497395143704">"змена глабальных параметраў сістэмы"</string>
- <!-- outdated translation 838789419871034696 --> <string name="permdesc_writeSettings" msgid="7775723441558907181">"Дазваляе прыкладанням змяняць налады сістэмы. Шкодныя прыкладанні могуць пашкодзіць канфігурацыю сістэмы."</string>
+ <string name="permdesc_writeSettings" msgid="7775723441558907181">"Дазваляе прыкладаннем змяняць дадзеныя налад сістэмы. Шкоднасныя прыкладанні могуць пашкодзіць канфігурацыю вашай сістэмы."</string>
<string name="permlab_writeSecureSettings" msgid="204676251876718288">"змяняць параметры бяспекі сістэмы"</string>
- <!-- outdated translation 5497873143539034724 --> <string name="permdesc_writeSecureSettings" msgid="8159535613020137391">"Дазваляе прыкладанням мяняць параметры бяспекі сістэмы. Не выкарыстоўваецца звычайнымі прыкладаннямі."</string>
+ <string name="permdesc_writeSecureSettings" msgid="8159535613020137391">"Дазваляе прыкладанням змяняць дадзеныя параметраў бяспекі сістэмы. Не для выкарыстання звычайнымі прыкладаннямі."</string>
<string name="permlab_writeGservices" msgid="2149426664226152185">"змяняць карту службаў Google"</string>
- <!-- outdated translation 6602362746516676175 --> <string name="permdesc_writeGservices" msgid="1287309437638380229">"Дазваляе прыкладанням змяняць карту службаў Google. Не для выкарыстання звычайнымі прыкладаннямі."</string>
+ <string name="permdesc_writeGservices" msgid="1287309437638380229">"Дазваляе прыкладанням змяняць карту службаў Google. Не для выкарыстання звычайнымі прыкладаннямі."</string>
<string name="permlab_receiveBootCompleted" msgid="7776779842866993377">"аўтаматычна запускаць пры загрузцы"</string>
- <!-- outdated translation 7530977064379338199 --> <string name="permdesc_receiveBootCompleted" product="tablet" msgid="7390304664116880704">"Дазваляе прыкладанням запускаць саміх сябе, як толькі сістэма цалкам загрузіцца. Гэта можа зрабіць загрузку планшэта больш павольнай і дазволіць прыкладанню запаволіць увесь планшэт, заўсёды працуючы."</string>
- <!-- outdated translation 7530977064379338199 --> <string name="permdesc_receiveBootCompleted" product="default" msgid="513950589102617504">"Дазваляе прыкладанням запускаць саміх сябе, як толькі сістэма цалкам загрузіцца. Гэта можа зрабіць загрузку планшэта больш павольнай і дазволіць прыкладанню запаволіць увесь планшэт, заўсёды працуючы."</string>
+ <string name="permdesc_receiveBootCompleted" product="tablet" msgid="7390304664116880704">"Дазваляе прыкладанню самастойна запускацца, як толькі сістэма будзе цалкам загружана. Гэта можа павялічыць час запуску планшэту і дазволіць прыкладанню запаволіць увесь планшэт, прымушаючы яго працаваць заўсёды."</string>
+ <string name="permdesc_receiveBootCompleted" product="default" msgid="513950589102617504">"Дазваляе прыкладанням самастойна запускацца, як толькі сістэма будзе цалкам запушчана. Гэта можа павялічыць час запуску тэлефону і дазволіць прыкладанню запаволіць увесь тэлефон, прымушаючы яго працаваць заўсёды."</string>
<string name="permlab_broadcastSticky" msgid="7919126372606881614">"адпраўляць нетэрмiновую рассылку"</string>
- <!-- outdated translation 6322249605930062595 --> <string name="permdesc_broadcastSticky" product="tablet" msgid="1181582512022829259">"Дазваляе прыкладанням адпраўляць прыдаткі да трансляцый, якія застаюцца пасля заканчэння трансляцыі. Шкоднасныя прыкладанні могуць зрабіць работу планшэта павольнай або нестабільнай, прымушаючы яго выкарыстоўваць занадта вялікі аб\'ём памяці."</string>
- <!-- outdated translation 6322249605930062595 --> <string name="permdesc_broadcastSticky" product="default" msgid="3287869131621514325">"Дазваляе прыкладанням адпраўляць прыдаткі да трансляцый, якія застаюцца пасля заканчэння трансляцыі. Шкоднасныя прыкладанні могуць зрабіць работу планшэта павольнай або нестабільнай, прымушаючы яго выкарыстоўваць занадта вялікі аб\'ём памяці."</string>
+ <string name="permdesc_broadcastSticky" product="tablet" msgid="1181582512022829259">"Дазваляе прыкладанням дасылаць далейшыя звязаныя перадачы, якія застаюцца пасля заканчэння асноўнай перадачы. Шкоднасныя прыкладанні могуць зрабіць працу планшэта павольнай або няўстойлівай, прымушаючы яго выкарыстоўваць занадта шмат памяці."</string>
+ <string name="permdesc_broadcastSticky" product="default" msgid="3287869131621514325">"Дазваляе прыкладанню дасылаць далейшыя звязаныя перадачы, якія застаюцца пасля заканчэння асноўнай перадачы. Шкоднасныя прыкладанні могуць зрабіць працу тэлефона павольнай або няўстойлівай, прымушаючы яго выкарыстоўваць занадта шмат памяці."</string>
<string name="permlab_readContacts" msgid="6219652189510218240">"чытаць кантактныя дадзеныя"</string>
- <!-- outdated translation 7596158687301157686 --> <string name="permdesc_readContacts" product="tablet" msgid="4028657556924039119">"Дазваляе прыкладанням счытваць усе кантакты (адрасы), якія захоўваюцца на планшэце. Шкоднасныя прыкладанні могуць выкарыстоўваць гэта, каб адпраўляць вашыя дадзеныя іншым асобам."</string>
- <!-- outdated translation 7596158687301157686 --> <string name="permdesc_readContacts" product="default" msgid="2032222056456498547">"Дазваляе прыкладанням счытваць усе кантакты (адрасы), якія захоўваюцца на планшэце. Шкоднасныя прыкладанні могуць выкарыстоўваць гэта, каб адпраўляць вашыя дадзеныя іншым асобам."</string>
+ <string name="permdesc_readContacts" product="tablet" msgid="4028657556924039119">"Дазваляе прыкладанням счытваць усе кантакты (адрасы), якія захоўваюцца на планшэце. Шкоднасныя прыкладанні могуць выкарыстоўваць гэта, каб адпраўляць дадзеныя іншым людзям."</string>
+ <string name="permdesc_readContacts" product="default" msgid="2032222056456498547">"Дазваляе прыкладанням счытваць усе кантакты (адрасы), якія захоўваюцца на вашым тэлефоне. Шкоднасныя прыкладанні могуць выкарыстоўваць гэта, каб адпраўляць дадзеныя іншым людзям."</string>
<string name="permlab_writeContacts" msgid="644616215860933284">"запісваць кантактныя дадзеныя"</string>
- <!-- outdated translation 7782689510038568495 --> <string name="permdesc_writeContacts" product="tablet" msgid="988969759110632978">"Дазваляе прыкладанням змяняць кантакты (адрасы), якія захоўваюцца на планшэце. Шкоднасныя прыкладанні могуць выкарыстоўваць гэта, каб сцерці або змяніць вашыя кантактныя дадзеныя."</string>
- <!-- outdated translation 7782689510038568495 --> <string name="permdesc_writeContacts" product="default" msgid="5075164818647934067">"Дазваляе прыкладанням змяняць кантакты (адрасы), якія захоўваюцца на планшэце. Шкоднасныя прыкладанні могуць выкарыстоўваць гэта, каб сцерці або змяніць вашыя кантактныя дадзеныя."</string>
+ <string name="permdesc_writeContacts" product="tablet" msgid="988969759110632978">"Дазваляе прыкладанням змяняць кантакты (адрасы), якія захоўваюцца на планшэце. Шкоднасныя прыкладанні могуць выкарыстоўваць гэтую магчымасць для выдалення або змены кантактных дадзеных."</string>
+ <string name="permdesc_writeContacts" product="default" msgid="5075164818647934067">"Дазваляе прыкладанням змяняць кантакты (адрасы), якія захоўваюцца на вашым тэлефоне. Шкоднасныя прыкладанні могуць выкарыстоўваць гэту магчымасць для выдалення або змены кантактных дадзеных."</string>
<string name="permlab_readProfile" msgid="6824681438529842282">"чытаць дадзеныя вашага профілю"</string>
- <!-- outdated translation 6335739730324727203 --> <string name="permdesc_readProfile" product="default" msgid="94520753797630679">"Дазваляе прыкладанням счытваць персанальныя дадзеныя профілю, якія захоўваюцца на вашай прыладзе (напрыклад, вашыя імя і кантактную інфармацыю). Гэта азначае, што прыкладанне можа ідэнтыфікаваць вас і адправіць інфармацыю аб вашым профілі іншым асобам."</string>
+ <string name="permdesc_readProfile" product="default" msgid="94520753797630679">"Дазваляе прыкладанням счытваць асабістую інфармацыю ў профілях, якая захоўваецца на вашай прыладзе, напрыклад, ваша імя і кантактную інфармацыю. Гэта азначае, што прыкладанне можа ідэнтыфікаваць вас і адправіць інфармацыю вашага профілю трэцім асобам."</string>
<string name="permlab_writeProfile" msgid="4679878325177177400">"увядзіце дадзеныя вашага профілю"</string>
- <!-- outdated translation 6431297330378229453 --> <string name="permdesc_writeProfile" product="default" msgid="4637366723793045603">"Дазваляе прыкладанням змяняць або дадаваць персанальныя дадзеныя профілю, якія захоўваюцца на вашай прыладзе (напрыклад, вашыя імя і кантактную інфармацыю). Гэта азначае, што іншыя прыкладанні могуць ідэнтыфікаваць вас і адправіць інфармацыю аб вашым профілі іншым асобам."</string>
+ <string name="permdesc_writeProfile" product="default" msgid="4637366723793045603">"Дазваляе прыкладанням змяняць ці дадаваць асабістую інфармацыю профіляў, захаваных на прыладзе, напрыклад ваша імя і кантактную інфармацыю. Такім чынам, іншыя прыкладанні могуць ідэнтыфікаваць вас і адпраўляць інфармацыю вашага профіля трэцім асобам."</string>
<string name="permlab_readSocialStream" product="default" msgid="1268920956152419170">"чытаць мой паток абнаўленняў"</string>
- <!-- outdated translation 1300659548047580769 --> <string name="permdesc_readSocialStream" product="default" msgid="3419050808547335320">"Дазваляе прыкладанням атрымліваць доступ да абнаўленняў вашых сяброў i сiнхранiзаваць гэтыя звесткi. З дапамогай шкоднасных прыкладанняў хтосьцi можа атрымаць доступ да вашай асабiстай перапiскi з сябрамi ў сацыяльных сетках."</string>
+ <string name="permdesc_readSocialStream" product="default" msgid="3419050808547335320">"Дазваляе прыкладанням атрымліваць доступ і сінхранізаваць абнаўленнi ад вас i вашых сяброў у сацыяльных сетках. З дапамогай шкоднасных прыкладанняў хтосьцi можа чытаць вашу асабiстую перапiску з сябрамі ў сацыяльных сетках."</string>
<string name="permlab_writeSocialStream" product="default" msgid="3504179222493235645">"запісаць у мой паток абнаўленняў"</string>
- <!-- outdated translation 8649864102944627446 --> <string name="permdesc_writeSocialStream" product="default" msgid="3496277176955721451">"Дазваляе прыкладанням публiкаваць абнаўленнi вашых сяброў з сацыяльных сетак. З дапамогай шкоднасных прыкладанняў хтосьцi можа падрабляць абнаўленнi ад вашых сяброў i, напрыклад, збiраць вашы канфiдэнцыйныя звесткi."</string>
+ <string name="permdesc_writeSocialStream" product="default" msgid="3496277176955721451">"Дазваляе прыкладанням адлюстроўваць абнаўленнi ад вашых сяброў у сацыяльных сетках. З дапамогай шкоднасных прыкладанняў хтосьцi можа прыкінуцца вашым сябрам, каб выкрасцi паролi i iншыя канфiдэнцыйныя звесткi."</string>
<string name="permlab_readCalendar" msgid="5972727560257612398">"чытаць падзеі календара, а таксама прыватную інфармацыю"</string>
- <!-- outdated translation 5665520896961671949 --> <string name="permdesc_readCalendar" product="tablet" msgid="2338414551004122687">"Дазваляе прыкладанням счытваць усе падзеі календара, захаваныя на планшэце, у тым ліку падзеі сяброў і калегаў. З дапамогай гэтага дазволу шкоднасныя прыкладанні могуць здабываць персанальную інфармацыю з гэтых календароў без ведама ўладальнікаў."</string>
- <!-- outdated translation 5665520896961671949 --> <string name="permdesc_readCalendar" product="default" msgid="5693933067751827753">"Дазваляе прыкладанням счытваць усе падзеі календара, захаваныя на планшэце, у тым ліку падзеі сяброў і калегаў. З дапамогай гэтага дазволу шкоднасныя прыкладанні могуць здабываць персанальную інфармацыю з гэтых календароў без ведама ўладальнікаў."</string>
+ <string name="permdesc_readCalendar" product="tablet" msgid="2338414551004122687">"Дазваляе прыкладанню счытваць усе мерапрыемствы календара, захаваныя на планшэце, у тым ліку мерапрыемствы сяброў і калег. Шкоднасныя прыкладанні могуць атрымліваць асабістую інфармацыю з гэтых календароў без ведама ўладальнікаў."</string>
+ <string name="permdesc_readCalendar" product="default" msgid="5693933067751827753">"Дазваляе прыкладанню счытваць усе мерапрыемствы календара, захаваныя на вашым тэлефоне, у тым ліку мерапрыемствы сяброў і калег. Шкоднасныя прыкладаннi могуць атрымліваць асабістую інфармацыю з гэтых календароў без ведама ўладальнікаў."</string>
<string name="permlab_writeCalendar" msgid="8438874755193825647">"дадаваць ці змяняць падзеі календара і адпраўляць электронную пошту да гасцей без ведама ўладальнікаў"</string>
- <!-- outdated translation 5368129321997977226 --> <string name="permdesc_writeCalendar" msgid="2243771395254848873">"Дазваляе прыкладанням адпраўляць запрашэнні на мерапрыемствы ад iмя ўладальніка календара і дадаваць, выдаляць, змяняць падзеі, якія можна змяняць на прыладзе, у тым ліку падзеі сяброў або калегаў. З дапамогай гэтага дазволу шкоднасныя прыкладанні могуць рассылаць спам , які выглядае як прыбыўшы ад уладальніка календара, змяняць падзеі без ведама ўладальнікаў або дадаваць падробленыя падзеі."</string>
+ <string name="permdesc_writeCalendar" msgid="2243771395254848873">"Дазваляе прыкладанням адпраўляць запрашэнні на мерапрыемствы ў якасці ўладальніка календара і дадаваць, выдаляць, рэдагаваць мерапрыемствы, якія можна змяняць на прыладзе, у тым ліку мерапрыемствы сяброў або калег. Шкоднасныя прыкладанні могуць адпраўляць паведамленні-спам, якія зыходзяць ад уладальніка календара, змяняць мерапрыемствы без ведама ўладальнікаў або дадаваць падробленыя мерапрыемствы."</string>
<string name="permlab_accessMockLocation" msgid="8688334974036823330">"макет крыніц месцазнаходжання для тэставання"</string>
- <!-- outdated translation 7648286063459727252 --> <string name="permdesc_accessMockLocation" msgid="7577931556422993949">"Стварыць макет крыніц месцазнаходжанняў для тэставання. Шкоднасныя прыкладанні могуць выкарыстоўваць гэта для змены месцазнаходжання і/або статусу, атрыманых з рэальных сістэм пазіцыявання, напрыклад з GPS або сеткі правайдэраў мабільнай сувязі."</string>
+ <string name="permdesc_accessMockLocation" msgid="7577931556422993949">"Дазваляе прыкладанням ствараць макет крыніц месцазнаходжання для тэставання. Шкоднасныя прыкладанні могуць выкарыстоўваць гэта, каб змяняць месцазнаходжанне і/або статус, паведамляемы рэальнымі крыніцамі месцазнаходжання, напрыклад, GPS або правайдэрамі сеткі."</string>
<string name="permlab_accessLocationExtraCommands" msgid="2836308076720553837">"доступ да дадатковых камандаў пастаўшчыка месцазнаходжання"</string>
- <!-- outdated translation 1948144701382451721 --> <string name="permdesc_accessLocationExtraCommands" msgid="6737736970602176133">"Доступ да дадатковых каманд пастаўшчыка месцазнаходжання. Шкоднасныя прыкладанні могуць карыстацца гэтым, каб умешвацца ў працу GPS і іншых крыніц месцазнаходжання."</string>
+ <string name="permdesc_accessLocationExtraCommands" msgid="6737736970602176133">"Дазваляе прыкладанням атрымліваць доступ да дадатковых каманд пастаўшчыка месца. Шкоднасныя прыкладанні могуць выкарыстоўваць гэта, каб умешвацца ў працу GPS або іншых крыніц месцазнаходжання."</string>
<string name="permlab_installLocationProvider" msgid="6578101199825193873">"дазвол на ўсталяванне пастаўшчыка месцазнаходжання"</string>
- <!-- outdated translation 5449175116732002106 --> <string name="permdesc_installLocationProvider" msgid="1742577679350078373">"Стварыць макет крыніц месца для тэставання. Шкоднае праграмнае забеспячэнне можа выкарыстаць гэта, каб змяніць месцазнаходжанне і/або статус, атрыманы з рэальных сістэм пазіцыянавання, напрыклад з GPS або сеткі правайдэраў мабільнай сувязі, або можа вызначаць ваша месцазнаходжанне і перадаваць звесткі на вонкавыя прылады."</string>
+ <string name="permdesc_installLocationProvider" msgid="1742577679350078373">"Стварае макет крыніц месцазнаходжання для тэставання. Шкоднасныя прыкладаннi могуць выкарыстоўваць гэта, каб змяняць месцазнаходжанне і/або статус, які перадаюць рэальныя крыніцы месцазнаходжання, напрыклад GPS або пастаўшчыкі паслуг сеткі, ці кантраляваць вашае месцазнаходжанне і перадаваць яго на знешнюю крыніцу."</string>
<string name="permlab_accessFineLocation" msgid="8116127007541369477">"дакладнае (GPS) месцазнаходжанне"</string>
- <!-- outdated translation 243973693233359681 --> <string name="permdesc_accessFineLocation" product="tablet" msgid="5326423948268164934">"Доступ да дакладных крыніц месцаў (напрыклад, да глабальнай сістэмы пазіцыянавання на планшэце), калі такія маюцца. Шкоднасныя прыкладанні могуць выкарыстоўваць гэта, каб вызначыць, дзе вы знаходзіцеся, і могуць спажываць дадатковую магутнасць батарэі."</string>
- <!-- outdated translation 243973693233359681 --> <string name="permdesc_accessFineLocation" product="default" msgid="7130267914433890869">"Доступ да дакладных крыніц месцаў (напрыклад, да глабальнай сістэмы пазіцыянавання на планшэце), калі такія маюцца. Шкоднасныя прыкладанні могуць выкарыстоўваць гэта, каб вызначыць, дзе вы знаходзіцеся, і могуць спажываць дадатковую магутнасць батарэі."</string>
+ <string name="permdesc_accessFineLocation" product="tablet" msgid="5326423948268164934">"Дазволіць доступ да сістэм дакладнага пазіцыянавання на планшэце, напрыклад да GPS, там, дзе гэта магчыма. Шкоднасныя прыкладаннi могуць выкарыстоўваць гэта для вызначэння вашага месцазнаходжання, а таксама могуць дадаткова спажываць магутнасць акумулятару."</string>
+ <string name="permdesc_accessFineLocation" product="default" msgid="7130267914433890869">"Дазволіць доступ да сістэм дакладнага пазіцыянавання на тэлефоне, напрыклад да GPS, там, дзе гэта магчыма. Шкоднасныя прыкладаннi могуць выкарыстоўваць гэта для вызначэння вашага месцазнаходжання, а таксама могуць дадаткова спажываць магутнасць акумулятару."</string>
<string name="permlab_accessCoarseLocation" msgid="4642255009181975828">"прыблізнае (заснаванае на дадзеных сеткі) месцазнаходжанне"</string>
- <!-- outdated translation 3704633168985466045 --> <string name="permdesc_accessCoarseLocation" product="tablet" msgid="5460726396318105483">"Доступ да грубых крыніц месца (напрыклад, да базы дадзеных сотавай сеткі), каб вызначыць прыблізнае месцазнаходжанне планшэту, калі такія маюцца. Шкоднасныя прыкладанні могуць выкарыстоўваць гэта, каб прыкладна вызначыць, дзе вы знаходзіцеся."</string>
- <!-- outdated translation 3704633168985466045 --> <string name="permdesc_accessCoarseLocation" product="default" msgid="8900795778057579522">"Доступ да грубых крыніц месца (напрыклад, да базы дадзеных сотавай сеткі), каб вызначыць прыблізнае месцазнаходжанне планшэту, калі такія маюцца. Шкоднасныя прыкладанні могуць выкарыстоўваць гэта, каб прыкладна вызначыць, дзе вы знаходзіцеся."</string>
+ <string name="permdesc_accessCoarseLocation" product="tablet" msgid="5460726396318105483">"Атрымаць доступ да прыблізных крыніц месцазнаходжання (напрыклад, да базы дадзеных сотавай сеткі), каб вызначыць прыблізнае месцазнаходжанне планшэта, калі такія маюцца. Шкоднасныя прыкладанні могуць выкарыстоўваць гэта, каб прыкладна вызначаць, дзе вы знаходзіцеся."</string>
+ <string name="permdesc_accessCoarseLocation" product="default" msgid="8900795778057579522">"Каб вызначыць прыблізнае месцазнаходжанне тэлефона, атрымайце доступ да прыблізных крыніц месцазнаходжання (напрыклад, да базы дадзеных сотавай сеткі), калі такія маюцца. Шкоднасныя прыкладанні могуць выкарыстоўваць гэта, каб прыкладна вызначаць, дзе вы."</string>
<string name="permlab_accessSurfaceFlinger" msgid="2363969641792388947">"доступ да SurfaceFlinger"</string>
- <!-- outdated translation 6805241830020733025 --> <string name="permdesc_accessSurfaceFlinger" msgid="1041619516733293551">"Дазваляе прыкладанням выкарыстоўваць нізкаўзроўневыя функцыі SurfaceFlinger."</string>
+ <string name="permdesc_accessSurfaceFlinger" msgid="1041619516733293551">"Дазваляе прыкладанням выкарыстоўваць нізкаўзроўневыя функцыі SurfaceFlinger."</string>
<string name="permlab_readFrameBuffer" msgid="6690504248178498136">"чытаць буфер кадраў"</string>
- <!-- outdated translation 7530020370469942528 --> <string name="permdesc_readFrameBuffer" msgid="4937405521809454680">"Дазваляе прыкладанню чытаць змесціва буфера кадраў."</string>
+ <string name="permdesc_readFrameBuffer" msgid="4937405521809454680">"Дазваляе прыкладанням счытваць змесціва буферу кадра."</string>
<string name="permlab_modifyAudioSettings" msgid="6095859937069146086">"змяняць налады аудыё"</string>
- <!-- outdated translation 5793461287365991922 --> <string name="permdesc_modifyAudioSettings" msgid="7343951185408396919">"Дазваляе прыкладанням змяняць глабальныя налады аудыё, напрыклад гучнасць і маршрутызацыю."</string>
+ <string name="permdesc_modifyAudioSettings" msgid="7343951185408396919">"Дазваляе прыкладанням змяняць глабальныя налады аудыё, напрыклад гук і маршрутызацыю."</string>
<string name="permlab_recordAudio" msgid="3876049771427466323">"запісваць аўдыё"</string>
- <!-- outdated translation 6493228261176552356 --> <string name="permdesc_recordAudio" msgid="2387462233976248635">"Дае прыкладанням доступ да шляха запісу аўдыё."</string>
+ <string name="permdesc_recordAudio" msgid="2387462233976248635">"Дазваляе прыкладанням атрымліваць доступ да шляху аудыёзапісу."</string>
<string name="permlab_camera" msgid="3616391919559751192">"рабіць фатаграфіі і відэа"</string>
- <!-- outdated translation 6004878235852154239 --> <string name="permdesc_camera" msgid="1507407407002492176">"Дазваляе прыкладанням здымаць фатаграфіі і відэа з дапамогай камеры. Гэта дазваляе прыкладанням ў любы час збіраць выявы, якія бачыць камера."</string>
+ <string name="permdesc_camera" msgid="1507407407002492176">"Дазваляе прыкладанням рабiць фатаграфіі і відэа з камеры. Гэта дазваляе прыкладанням у любы час збіраць выявы, якія \"бачыць\" камера."</string>
<string name="permlab_brick" product="tablet" msgid="2961292205764488304">"цалкам адключыць планшэт"</string>
<string name="permlab_brick" product="default" msgid="8337817093326370537">"цалкам адключаць тэлефон"</string>
- <!-- outdated translation 7379164636920817963 --> <string name="permdesc_brick" product="tablet" msgid="4334818808001699530">"Дазваляе прыкладанням цалкам адключаць планшэт. Гэта вельмі небяспечна."</string>
- <!-- outdated translation 7379164636920817963 --> <string name="permdesc_brick" product="default" msgid="5788903297627283099">"Дазваляе прыкладанням цалкам адключаць планшэт. Гэта вельмі небяспечна."</string>
+ <string name="permdesc_brick" product="tablet" msgid="4334818808001699530">"Дазваляе прыкладанням цалкам адключаць планшэт. Гэта вельмі небяспечна."</string>
+ <string name="permdesc_brick" product="default" msgid="5788903297627283099">"Дазваляе прыкладанням цалкам адключаць тэлефон. Гэта вельмі небяспечна."</string>
<string name="permlab_reboot" product="tablet" msgid="3436634972561795002">"прымусовая перазагрузка планшэта"</string>
<string name="permlab_reboot" product="default" msgid="2898560872462638242">"прымусова перазагружаць тэлефон"</string>
- <!-- outdated translation 4555793623560701557 --> <string name="permdesc_reboot" product="tablet" msgid="8172056180063700741">"Дазваляе прыкладанню прымусова перазагрузіць планшэт."</string>
- <!-- outdated translation 4555793623560701557 --> <string name="permdesc_reboot" product="default" msgid="5326008124289989969">"Дазваляе прыкладанню прымусова перазагрузіць планшэт."</string>
+ <string name="permdesc_reboot" product="tablet" msgid="8172056180063700741">"Дазваляе прыкладанням прымусова перазагружаць планшэт."</string>
+ <string name="permdesc_reboot" product="default" msgid="5326008124289989969">"Дазваляе прыкладанням прымусова перазагружаць тэлефон."</string>
<string name="permlab_mount_unmount_filesystems" msgid="1761023272170956541">"уключэнне і адключэнне файлавых сістэм"</string>
- <!-- outdated translation 6253263792535859767 --> <string name="permdesc_mount_unmount_filesystems" msgid="1829290701658992347">"Дазваляе прыкладанням уключаць і адключаць файлавыя сістэмы для падлучэння зменных назапашвальнікаў."</string>
+ <string name="permdesc_mount_unmount_filesystems" msgid="1829290701658992347">"Дазваляе прыкладанням падключаць і адключаць файлавыя сістэмы для здымных назапашвальнікаў."</string>
<string name="permlab_mount_format_filesystems" msgid="5523285143576718981">"фарматаваць знешнія назапашвальнікі"</string>
- <!-- outdated translation 574060044906047386 --> <string name="permdesc_mount_format_filesystems" msgid="8784268246779198627">"Дазваляе прыкладанням фарматаваць здымныя назапашвальнiкi."</string>
+ <string name="permdesc_mount_format_filesystems" msgid="8784268246779198627">"Дазваляе прыкладанням фарматаваць здымны назапашвальнiк."</string>
<string name="permlab_asec_access" msgid="3411338632002193846">"атрымаць інфармацыю аб унутранай памяці"</string>
- <!-- outdated translation 8820326551687285439 --> <string name="permdesc_asec_access" msgid="3094563844593878548">"Дазваляе прыкладанню атрымліваць інфармацыю аб унутранай памяці."</string>
+ <string name="permdesc_asec_access" msgid="3094563844593878548">"Дазваляе прыкладанню атрымліваць інфармацыю пра ўнутраную памяць."</string>
<string name="permlab_asec_create" msgid="6414757234789336327">"стварыць унутраную памяць"</string>
- <!-- outdated translation 2621346764995731250 --> <string name="permdesc_asec_create" msgid="4558869273585856876">"Дазваляе прыкладанню ствараць унутраную памяць."</string>
+ <string name="permdesc_asec_create" msgid="4558869273585856876">"Дазваляе прыкладанням ствараць унутраную памяць."</string>
<string name="permlab_asec_destroy" msgid="526928328301618022">"знішчыць унутраную памяць"</string>
- <!-- outdated translation 2746706889208066256 --> <string name="permdesc_asec_destroy" msgid="7218749286145526537">"Дазваляе прыкладанню знішчаць унутраную памяць."</string>
- <!-- outdated translation 2456287623689029744 --> <string name="permlab_asec_mount_unmount" msgid="8877998101944999386">"падключыць/адключыць унутраную памяць"</string>
- <!-- outdated translation 5934375590189368200 --> <string name="permdesc_asec_mount_unmount" msgid="3451360114902490929">"Дазваляе прыкладанню падключаць/адключаць унутраную памяць."</string>
+ <string name="permdesc_asec_destroy" msgid="7218749286145526537">"Дазваляе прыкладанням выдаляць унутраную памяць."</string>
+ <string name="permlab_asec_mount_unmount" msgid="8877998101944999386">"падключэнне/адключэнне ўнутранай памяці"</string>
+ <string name="permdesc_asec_mount_unmount" msgid="3451360114902490929">"Дазваляе прыкладанням падлучаць i адлучаць унутраную памяць."</string>
<string name="permlab_asec_rename" msgid="7496633954080472417">"перайменаваць унутраную памяць"</string>
- <!-- outdated translation 2152829985238876790 --> <string name="permdesc_asec_rename" msgid="1794757588472127675">"Дазваляе праграмам змяняць імя ўнутранай памяці."</string>
+ <string name="permdesc_asec_rename" msgid="1794757588472127675">"Дазваляе прыкладанням змяняць імя ўнутранай памяці."</string>
<string name="permlab_vibrate" msgid="7768356019980849603">"кіраваць вібрацыяй"</string>
- <!-- outdated translation 2886677177257789187 --> <string name="permdesc_vibrate" msgid="6284989245902300945">"Дазваляе прыкладанням кіраваць вібрацыяй."</string>
+ <string name="permdesc_vibrate" msgid="6284989245902300945">"Дазваляе прыкладанням кіраваць вібрацыяй."</string>
<string name="permlab_flashlight" msgid="2155920810121984215">"кіраваць ўспышкай"</string>
- <!-- outdated translation 6433045942283802309 --> <string name="permdesc_flashlight" msgid="6522284794568368310">"Дазваляе прыкладанню кіраваць ліхтарыкам."</string>
+ <string name="permdesc_flashlight" msgid="6522284794568368310">"Дазваляе прыкладанню кіраваць ліхтарыкам."</string>
<string name="permlab_manageUsb" msgid="1113453430645402723">"кіраваць спісам пажаданых і дазволеных USB-прылад"</string>
- <!-- outdated translation 6148489202092166164 --> <string name="permdesc_manageUsb" msgid="7776155430218239833">"Дазваляе выкарыстоўваць праграму для кіравання спісам пажаданых і дазволеных USB-прылад."</string>
+ <string name="permdesc_manageUsb" msgid="7776155430218239833">"Дазваляе прыкладанням кіраваць наладамі і дазволамі USB-прылад."</string>
<string name="permlab_accessMtp" msgid="4953468676795917042">"рэалізаваць пратакол MTP"</string>
<string name="permdesc_accessMtp" msgid="6532961200486791570">"Дазваляе атрымаць доступ да драйвер ядра MTP, каб рэалізаваць USB-пратакол MTP."</string>
<string name="permlab_hardware_test" msgid="4148290860400659146">"тэставаць апаратнае забеспячэнне"</string>
- <!-- outdated translation 3668894686500081699 --> <string name="permdesc_hardware_test" msgid="6597964191208016605">"Дазваляе прыкладанням кіраваць рознымі перыферыйнымі прыладамі для тэставання абсталявання."</string>
+ <string name="permdesc_hardware_test" msgid="6597964191208016605">"Дазваляе прыкладанням кіраваць рознымі перыферыйнымі прыладамі для тэставання апаратнага абсталявання."</string>
<string name="permlab_callPhone" msgid="3925836347681847954">"непасрэдна набіраць тэлефонныя нумары"</string>
- <!-- outdated translation 3369867353692722456 --> <string name="permdesc_callPhone" msgid="6396463004110544744">"Дазваляе прыкладанням выклікаць тэлефонныя нумары без вашага ўмяшальніцтва. Шкодныя праграмы могуць рабіць непрадугледжаныя званкі за ваш кошт. Звярніце ўвагу: гэта не дазваляе прыкладанням выклікаць нумары экстраных службаў."</string>
+ <string name="permdesc_callPhone" msgid="6396463004110544744">"Дазваляе прыкладанням выклікаць тэлефонныя нумары без вашага ведама. Шкоднасныя прыкладанні могуць прывесці да з\'яўлення нечаканых выклікаў у вашым рахунку за паслугі тэлефоннай сувязі. Звярніце ўвагу, што гэты дазвол не дазваляе прыкладанню выклікаць экстраныя нумары."</string>
<string name="permlab_callPrivileged" msgid="4198349211108497879">"непасрэдна выклікаць любыя тэлефонныя нумары"</string>
- <!-- outdated translation 244405067160028452 --> <string name="permdesc_callPrivileged" msgid="1689024901509996810">"Дазваляе прыкладанням тэлефанаваць на любы нумар, у тым лiку на нумары экстраных служб, без вашага ўмяшальніцтва. Шкодныя праграмы могуць рабіць непатрэбныя і незаконныя выклікі аварыйных службаў."</string>
+ <string name="permdesc_callPrivileged" msgid="1689024901509996810">"Дазваляе прыкладанню тэлефанаваць на любы тэлефонны нумар, у тым лiку на экстраныя нумары, без вашага ведама. Шкоднасныя прыкладанні могуць рабіць непатрэбныя і незаконныя экстраныя выклікі."</string>
<string name="permlab_performCdmaProvisioning" product="tablet" msgid="4842576994144604821">"непасрэдна пачаць наладу CDMA-планшэта"</string>
<string name="permlab_performCdmaProvisioning" product="default" msgid="5604848095315421425">"непасрэдна запускаць налады тэлефона CDMA"</string>
- <!-- outdated translation 6457447676108355905 --> <string name="permdesc_performCdmaProvisioning" msgid="1994193538802314186">"Дазваляе прыкладанням запускаць падрыхтоўку CDMA. Шкоднасныя прыкладанні могуць без неабходнасці пачаць падрыхтоўку CDMA"</string>
+ <string name="permdesc_performCdmaProvisioning" msgid="1994193538802314186">"Дазваляе прыкладанням запускаць рэзервы CDMA. Шкоднасныя прыкладанні могуць запускаць залішнія рэзервы CDMA."</string>
<string name="permlab_locationUpdates" msgid="7785408253364335740">"кіраваць абвесткамі абнаўлення месцазнаходжання"</string>
- <!-- outdated translation 2300018303720930256 --> <string name="permdesc_locationUpdates" msgid="1120741557891438876">"Дазваляе ўключаць/выключаць абнаўленнi апавяшчэнняў аб месцазнаходжанні праз радыё. Не для выкарыстання звычайнымі прыкладаннямі."</string>
+ <string name="permdesc_locationUpdates" msgid="1120741557891438876">"Дазваляе прыкладанням уключаць i адключаць апавяшчэннi аб абнаўленні месцазнаходжання ад радыё. Не для выкарыстання звычайнымі прыкладаннямі."</string>
<string name="permlab_checkinProperties" msgid="7855259461268734914">"атрымліваць доступ да ўласцівасцяў праверкі"</string>
- <!-- outdated translation 7150307006141883832 --> <string name="permdesc_checkinProperties" msgid="4024526968630194128">"Дазваляе счытваць і запісваць уласцівасці, загружаныя службай рэгістрацыі. Не выкарыстоўваецца звычайнымі прыкладаннямі."</string>
+ <string name="permdesc_checkinProperties" msgid="4024526968630194128">"Дазваляе прыкладанням сытваць/запісваць доступ да ўласцівасцяў, запампаваных службай праверкі. Не для выкарыстання звычайнымі прыкладаннямі."</string>
<string name="permlab_bindGadget" msgid="776905339015863471">"выбіраць віджэты"</string>
- <!-- outdated translation 2098697834497452046 --> <string name="permdesc_bindGadget" msgid="8261326938599049290">"Дазваляе прыкладанням паведамляць сістэме, якія прыкладанні могуць выкарыстоўваць віджэты. З гэтым дазволам яны могуць даваць іншым прыкладанням доступ да персанальных дадзеных. Не выкарыстоўваецца звычайнымі прыкладаннямі."</string>
+ <string name="permdesc_bindGadget" msgid="8261326938599049290">"Дазваляе прыкладанням паведамляць сістэме, якая віджэты могуць быць выкарыстаны пэўнымі прыкладаннямі. Прыкладанне з гэтым дазволам можа прадастаўляць доступ да персанальных дадзеных іншым прыкладанням. Не для выкарыстання звычайнымі прыкладаннямі."</string>
<string name="permlab_modifyPhoneState" msgid="8423923777659292228">"змяняць стан тэлефона"</string>
- <!-- outdated translation 3302284561346956587 --> <string name="permdesc_modifyPhoneState" msgid="1029877529007686732">"Дазваляе прыкладанням кіраваць тэлефоннымі функцыямі прылады. Прыкладанні з гэтым дазволам могуць пераключаць сеткі, уключаць і адключаць радыё на тэлефоне і г. д., нават не паведамляючы пра гэта."</string>
+ <string name="permdesc_modifyPhoneState" msgid="1029877529007686732">"Дазваляе прыкладанням кіраваць тэлефоннымі функцыямі прылады. Прыкладанне з гэтым дазволам можа пераключаць сеткі, уключаць і выключаць радыё на тэлефоне і г. д., нават не паведамляючы пра гэта."</string>
<string name="permlab_readPhoneState" msgid="2326172951448691631">"чытаць стан тэлефона і ідэнтыфікацыйныя дадзеныя"</string>
- <!-- outdated translation 188877305147626781 --> <string name="permdesc_readPhoneState" msgid="5127767618743602782">"Дазваляе прыкладанням атрымліваць доступ да функцый тэлефона прылады. Прыкладанні з гэтым дазволам могуць вызначыць нумар тэлефона і серыйны нумар гэтага тэлефона, актыўнасць выкліка, нумар выкліканага абанента і таму падобнае."</string>
+ <string name="permdesc_readPhoneState" msgid="5127767618743602782">"Дазваляе прыкладанням атрымліваць доступ да тэлефонных функцый прылады. Прыкладанне з гэтым дазволам можа вызначаць нумар тэлефона і серыйны нумар гэтага тэлефона ці актыўны выклік, нумар выкліканага абанента і г. д."</string>
<string name="permlab_wakeLock" product="tablet" msgid="1531731435011495015">"прадухіліць планшэт ад пераходу ў рэжым сну"</string>
<string name="permlab_wakeLock" product="default" msgid="573480187941496130">"забараняць тэлефону пераходзіць ў рэжым сну"</string>
- <!-- outdated translation 4032181488045338551 --> <string name="permdesc_wakeLock" product="tablet" msgid="7311319824400447868">"Дазваляе прыкладанню прадухіліць планшэт ад пераходу ў рэжым сну."</string>
- <!-- outdated translation 4032181488045338551 --> <string name="permdesc_wakeLock" product="default" msgid="8559100677372928754">"Дазваляе прыкладанню прадухіліць планшэт ад пераходу ў рэжым сну."</string>
+ <string name="permdesc_wakeLock" product="tablet" msgid="7311319824400447868">"Дазваляе прыкладанням прадухіляць пераход планшэта ў рэжым сну."</string>
+ <string name="permdesc_wakeLock" product="default" msgid="8559100677372928754">"Дазваляе прыкладанням прадухіляць тэлефон ад пераходу ў рэжым сну."</string>
<string name="permlab_devicePower" product="tablet" msgid="2787034722616350417">"Уключыць або выключыць планшэт"</string>
<string name="permlab_devicePower" product="default" msgid="4928622470980943206">"уключаць або выключаць тэлефон"</string>
- <!-- outdated translation 3853773100100451905 --> <string name="permdesc_devicePower" product="tablet" msgid="6689862878984631831">"Дазваляе прыкладанням уключаць або выключаць планшэт"</string>
- <!-- outdated translation 3853773100100451905 --> <string name="permdesc_devicePower" product="default" msgid="6037057348463131032">"Дазваляе прыкладанням уключаць або выключаць планшэт"</string>
+ <string name="permdesc_devicePower" product="tablet" msgid="6689862878984631831">"Дазваляе прыкладанням уключаць ці адключаць планшэт."</string>
+ <string name="permdesc_devicePower" product="default" msgid="6037057348463131032">"Дазваляе прыкладанням уключаць або адключаць тэлефон."</string>
<string name="permlab_factoryTest" msgid="3715225492696416187">"запусціць у рэжыме заводскага тэставання"</string>
<string name="permdesc_factoryTest" product="tablet" msgid="3952059318359653091">"Запуск у якасці нізкаўзроўневага тэсты вытворцы, што дазваляе атрымаць поўны доступ да абсталявання планшэта. Даступна, толькі калі планшэт працуе ў рэжыме тэставання вытворцы."</string>
<string name="permdesc_factoryTest" product="default" msgid="8136644990319244802">"Запусціць як нізкаўзроўневы тэст вытворцы, што дазваляе атрымаць поўны доступ да абсталявання тэлефона. Даступна, толькі калі прылада працуе ў рэжыме тэста вытворцы."</string>
<string name="permlab_setWallpaper" msgid="6627192333373465143">"усталёўваць шпалеры"</string>
- <!-- outdated translation 6417041752170585837 --> <string name="permdesc_setWallpaper" msgid="7373447920977624745">"Дазваляе прыкладанням усталёўваць сiстэмныя шпалеры."</string>
+ <string name="permdesc_setWallpaper" msgid="7373447920977624745">"Дазваляе прыкладанням ксталёўваць сiстэмныя шпалеры."</string>
<string name="permlab_setWallpaperHints" msgid="3600721069353106851">"усталёўваць падказкі памераў шпалер"</string>
- <!-- outdated translation 6019479164008079626 --> <string name="permdesc_setWallpaperHints" msgid="8235784384223730091">"Дазваляе прыкладанням задаваць падказкі па памеру сістэмных шпалераў."</string>
+ <string name="permdesc_setWallpaperHints" msgid="8235784384223730091">"Дазваляе прыкладанням задаваць падказкі па памеры сістэмных шпалер."</string>
<string name="permlab_masterClear" msgid="2315750423139697397">"скідаць сістэму да завадскіх наладаў"</string>
- <!-- outdated translation 5033465107545174514 --> <string name="permdesc_masterClear" msgid="3665380492633910226">"Дазваляе прыкладанням рабіць поўнае скіданне да завадскіх налад. Пры гэтым выдаляюцца ўсе дадзеныя, канфігурацыя і ўсталяваныя прыкладанні."</string>
+ <string name="permdesc_masterClear" msgid="3665380492633910226">"Дазваляе прыкладанню цалкам скідваць сістэму да заводскіх налад, выдаляючы ўсе дадзеныя, налады і ўсталяваныя прыкладанні."</string>
<string name="permlab_setTime" msgid="2021614829591775646">"задаць час"</string>
- <!-- outdated translation 209693136361006073 --> <string name="permdesc_setTime" product="tablet" msgid="1896341438151152881">"Дазваляе прыкладанню змяняць час на планшэце."</string>
- <!-- outdated translation 209693136361006073 --> <string name="permdesc_setTime" product="default" msgid="1855702730738020">"Дазваляе прыкладанню змяняць час на планшэце."</string>
+ <string name="permdesc_setTime" product="tablet" msgid="1896341438151152881">"Дазваляе прыкладанням змяняць час на гадзінніку планшэта."</string>
+ <string name="permdesc_setTime" product="default" msgid="1855702730738020">"Дазваляе прыкладаннМ змяняць час на гадзінніку тэлефона."</string>
<string name="permlab_setTimeZone" msgid="2945079801013077340">"усталёўваць часавы пояс"</string>
- <!-- outdated translation 2522877107613885139 --> <string name="permdesc_setTimeZone" product="tablet" msgid="1676983712315827645">"Дазваляе прыкладанню змяняць гадзінны пояс планшэта."</string>
- <!-- outdated translation 2522877107613885139 --> <string name="permdesc_setTimeZone" product="default" msgid="4499943488436633398">"Дазваляе прыкладанню змяняць гадзінны пояс планшэта."</string>
+ <string name="permdesc_setTimeZone" product="tablet" msgid="1676983712315827645">"Дазваляе прыкладанням змяняць гадзінны пояс планшэта."</string>
+ <string name="permdesc_setTimeZone" product="default" msgid="4499943488436633398">"Дазваляе прыкладанню змяняць гадзінны пояс тэлефона."</string>
<string name="permlab_accountManagerService" msgid="4829262349691386986">"выступаць у якасці службы AccountManagerService"</string>
- <!-- outdated translation 6056903274106394752 --> <string name="permdesc_accountManagerService" msgid="2684502137670299915">"Дазваляе прыкладанням тэлефанаваць на AccountAuthenticators"</string>
+ <string name="permdesc_accountManagerService" msgid="1948455552333615954">"Дазваляе прыкладанням тэлефанаваць на AccountAuthenticators."</string>
<string name="permlab_getAccounts" msgid="4549918644233460103">"выяўляць вядомыя ўліковыя запісы"</string>
- <!-- outdated translation 857622793935544694 --> <string name="permdesc_getAccounts" product="tablet" msgid="3238360555257773358">"Дазваляе прыкладанням атрымліваць спіс уліковых запісаў, якія ёсць на планшэце."</string>
- <!-- outdated translation 857622793935544694 --> <string name="permdesc_getAccounts" product="default" msgid="2735689364629830348">"Дазваляе прыкладанням атрымліваць спіс уліковых запісаў, якія ёсць на планшэце."</string>
+ <string name="permdesc_getAccounts" product="tablet" msgid="3238360555257773358">"Дазваляе прыкладанню атрымліваць спіс уліковых запісаў, вядомых планшэту."</string>
+ <string name="permdesc_getAccounts" product="default" msgid="2735689364629830348">"Дазваляе прыкладанню атрымліваць спіс уліковых запісаў, вядомых тэлефону."</string>
<string name="permlab_authenticateAccounts" msgid="3940505577982882450">"выступаць у якасці аўтэнтыфікатара ўліковага запісу"</string>
- <!-- outdated translation 4006839406474208874 --> <string name="permdesc_authenticateAccounts" msgid="5472124296908977260">"Дазваляе прыкладанню выкарыстоўваць магчымасці сродку праверкі сапраўднасці ўліковых запісаў AccountManager, у тым ліку ствараць уліковыя запісы, атрымліваць і наладжваць паролі для іх."</string>
+ <string name="permdesc_authenticateAccounts" msgid="5472124296908977260">"Дазваляе прыкладанням выкарыстоўваць магчымасці сродку праверкі сапраўднасці ўліковых запісаў AccountManager, у тым ліку ствараць уліковыя запісы, атрымліваць і наладжваць паролі для іх."</string>
<string name="permlab_manageAccounts" msgid="4440380488312204365">"кіраванне спісам уліковых запісаў"</string>
- <!-- outdated translation 8804114016661104517 --> <string name="permdesc_manageAccounts" msgid="8698295625488292506">"Дазваляе прыкладанням выконваць такія аперацыі, як дадаванне і выдаленне ўліковых запісаў альбо выдаленне іх пароляў."</string>
+ <string name="permdesc_manageAccounts" msgid="8698295625488292506">"Дазваляе прыкладанням выконваць даданне і выдаленне ўліковых запісаў або выдаленне іх пароляў."</string>
<string name="permlab_useCredentials" msgid="6401886092818819856">"выкарыстоўваць уліковыя дадзеныя ўліковага запісу"</string>
- <!-- outdated translation 7416570544619546974 --> <string name="permdesc_useCredentials" msgid="7984227147403346422">"Дазваляе прыкладанню запытваць ключы аўтэнтыфікацыі."</string>
+ <string name="permdesc_useCredentials" msgid="7984227147403346422">"Дазваляе прыкладанням запытваць ключы аўтэнтыфікаціі."</string>
<string name="permlab_accessNetworkState" msgid="6865575199464405769">"праглядаць стан сеткі"</string>
- <!-- outdated translation 558721128707712766 --> <string name="permdesc_accessNetworkState" msgid="479772796952547198">"Дазваляе прыкладанням праглядаць стан усіх сетак."</string>
+ <string name="permdesc_accessNetworkState" msgid="479772796952547198">"Дазваляе прыкладанню праглядаць стан усіх сетак."</string>
<string name="permlab_createNetworkSockets" msgid="9121633680349549585">"поўны доступ да інтэрнэту"</string>
- <!-- outdated translation 4593339106921772192 --> <string name="permdesc_createNetworkSockets" msgid="5963922297444265950">"Дазваляе прыкладанням ствараць сеткавыя злучальнікі."</string>
+ <string name="permdesc_createNetworkSockets" msgid="5963922297444265950">"Дазваляе прыкладанню ствараць сеткавыя сокеты."</string>
<string name="permlab_writeApnSettings" msgid="505660159675751896">"змяняць/перахопліваць сеткавыя налады і трафік"</string>
- <!-- outdated translation 2369786339323021771 --> <string name="permdesc_writeApnSettings" msgid="5333798886412714193">"Дазваляе прыкладанням змяняць налады сеткі, перахапляць і правяраць увесь сеткавы трафік, напрыклад для змены проксі і порта любога APN. Шкоднасныя прыкладанні могуць адсочваць, перанакіроўваць або змяняць сеткавыя пакеты без вашага ведама."</string>
+ <string name="permdesc_writeApnSettings" msgid="5333798886412714193">"Дазваляе прыкладанням змяняць налады сеткі, перахапляць і правяраць увесь сеткавы трафік, напрыклад для змены проксі-сервера і порта любога APN. Шкоднасныя прыкладанні могуць адсочваць, перанакіроўваць або змяняць сеткавыя пакеты без вашага ведама."</string>
<string name="permlab_changeNetworkState" msgid="958884291454327309">"змяніць падлучэнне да сеткі"</string>
- <!-- outdated translation 4199958910396387075 --> <string name="permdesc_changeNetworkState" msgid="6789123912476416214">"Дазваляе прыкладанням змяняць стан сеткавага падключэння."</string>
- <!-- outdated translation 2702121155761140799 --> <string name="permlab_changeTetherState" msgid="5952584964373017960">"Змяняць падлучэнне да мадэму"</string>
- <!-- outdated translation 8905815579146349568 --> <string name="permdesc_changeTetherState" msgid="1524441344412319780">"Дазваляе прыкладанню змяняць стан прывязанага сеткавага падключэння."</string>
+ <string name="permdesc_changeNetworkState" msgid="6789123912476416214">"Дазваляе прыкладанням змяняць стан сеткавага падключэння."</string>
+ <string name="permlab_changeTetherState" msgid="5952584964373017960">"змяніць прывязку да падлучэння"</string>
+ <string name="permdesc_changeTetherState" msgid="1524441344412319780">"Дазваляе прыкладанням змяняць стан прывязкі да сеткі."</string>
<string name="permlab_changeBackgroundDataSetting" msgid="1400666012671648741">"змяняць налады выкарыстання фонавых дадзеных"</string>
- <!-- outdated translation 1001482853266638864 --> <string name="permdesc_changeBackgroundDataSetting" msgid="5347729578468744379">"Дазваляе прыкладанням мяняць налады фонавай перадачы дадзеных."</string>
+ <string name="permdesc_changeBackgroundDataSetting" msgid="5347729578468744379">"Дазваляе прыкладанням змяняць налады выкарыстання зыходных дадзеных."</string>
<string name="permlab_accessWifiState" msgid="8100926650211034400">"праглядаць стан Wi-Fi"</string>
- <!-- outdated translation 485796529139236346 --> <string name="permdesc_accessWifiState" msgid="7770452658226256831">"Дазваляе прыкладанням праглядаць інфармацыю аб стане Wi-Fi."</string>
+ <string name="permdesc_accessWifiState" msgid="7770452658226256831">"Дазваляе прыкладанням праглядаць інфармацыю аб стане Wi-Fi."</string>
<string name="permlab_changeWifiState" msgid="7280632711057112137">"змяняць стан Wi-Fi"</string>
- <!-- outdated translation 2950383153656873267 --> <string name="permdesc_changeWifiState" msgid="7399961004537946240">"Дазваляе прыкладанням падключацца да кропак доступу Wi-Fi і адключацца ад іх, а таксама ўносіць змены ў наладжаныя сеткі Wi-Fi."</string>
+ <string name="permdesc_changeWifiState" msgid="7399961004537946240">"Дазваляе прыкладанням падлучацца і адключацца ад кропак доступу Wi-Fi і ўносіць змяненні ў наладжаныя сеткі Wi-Fi."</string>
<string name="permlab_changeWifiMulticastState" msgid="1368253871483254784">"дазваляе прыём Wi-Fi Multicast"</string>
- <!-- outdated translation 8199464507656067553 --> <string name="permdesc_changeWifiMulticastState" msgid="7633598524564320817">"Дазваляе прыкладанням атрымліваць пакеты, не напраўленыя непасрэдна на прыладу. Гэта можа быць карысна пры выяўленні блізкіх паслуг. Гэта выкарыстоўвае больш магутнасцяў, чым рэжым нешматадрасных перадач."</string>
- <!-- outdated translation 1092209628459341292 --> <string name="permlab_bluetoothAdmin" msgid="3606576270792236062">"кіраванне bluetooth"</string>
- <!-- outdated translation 3511795757324345837 --> <string name="permdesc_bluetoothAdmin" product="tablet" msgid="6921177471748882137">"Дазваляе прыкладанню наладжваць лакальны планшэт Bluetooth, а таксама вызначаць і падключацца да выдаленых прылад."</string>
- <!-- outdated translation 3511795757324345837 --> <string name="permdesc_bluetoothAdmin" product="default" msgid="8931682159331542137">"Дазваляе прыкладанню наладжваць лакальны планшэт Bluetooth, а таксама вызначаць і падключацца да выдаленых прылад."</string>
+ <string name="permdesc_changeWifiMulticastState" msgid="7633598524564320817">"Дазваляе прыкладаннямм атрымліваць пакеты, якія не былі адрасаваня непасрэдна вашай прыладзе. Гэта можа быць карысна пры выяўленні службаў, даступных побач. У гэтым рэжыме выкарыстоўваецца больш энергіі, чым у рэжыме аднаадраснай перадачы."</string>
+ <string name="permlab_bluetoothAdmin" msgid="3606576270792236062">"адмiнiстраванне Bluetooth"</string>
+ <string name="permdesc_bluetoothAdmin" product="tablet" msgid="6921177471748882137">"Дазваляе прыкладанням наладжваць лакальны планшэт Bluetooth, выяўляць і падлучаць выдаленыя прылады."</string>
+ <string name="permdesc_bluetoothAdmin" product="default" msgid="8931682159331542137">"Дазваляе прыкладанням наладжваць лакальны тэлефон Bluetooth, а таксама знаходзіць выдаленыя прылады i падлучацца да ix."</string>
+ <string name="permlab_accessWimaxState" msgid="1232061307208861588">"Прагляд стану WiMAX"</string>
+ <string name="permdesc_accessWimaxState" msgid="5914958077555177749">"Дазваляе прыкладанням праглядаць інфармацыю пра стан WiMAX."</string>
+ <string name="permlab_changeWimaxState" msgid="2405042267131496579">"Змяніць стан WiMAX"</string>
+ <string name="permdesc_changeWimaxState" msgid="3328853825006455912">"Дазваляе прыкладанням падключацца і адключацца ад сеткі WiMAX."</string>
<string name="permlab_bluetooth" msgid="8361038707857018732">"ствараць злучэнні Bluetooth"</string>
- <!-- outdated translation 4191941825910543803 --> <string name="permdesc_bluetooth" product="tablet" msgid="7007851048416363446">"Дазваляе прыкладанню праглядаць канфігурацыю лакальнага планшэта Bluetooth, а таксама ствараць і прымаць падключэнні да спалучаных прылад."</string>
- <!-- outdated translation 4191941825910543803 --> <string name="permdesc_bluetooth" product="default" msgid="31846362767164948">"Дазваляе прыкладанню праглядаць канфігурацыю лакальнага планшэта Bluetooth, а таксама ствараць і прымаць падключэнні да спалучаных прылад."</string>
+ <string name="permdesc_bluetooth" product="tablet" msgid="7007851048416363446">"Дазваляе прыкладанню праглядаць канфігурацыю лакальнага планшэту Bluetooth, а таксама здзяйсняць і прымаць злучэнні са спалучанымі прыладамі."</string>
+ <string name="permdesc_bluetooth" product="default" msgid="31846362767164948">"Дазваляе прыкладанню праглядаць канфігурацыю лакальнага тэлефона Bluetooth, а таксама здзяйсняць і прымаць злучэнні са спалучанымі прыладамі."</string>
<string name="permlab_nfc" msgid="4423351274757876953">"кантроль Near Field Communication"</string>
- <!-- outdated translation 9171401851954407226 --> <string name="permdesc_nfc" msgid="7120611819401789907">"Дазваляе прыкладанню звязвацца з тэгамі, карткамі і чытачамі Near Field Communication (NFC)."</string>
+ <string name="permdesc_nfc" msgid="7120611819401789907">"Дазваляе прыкладаннzv спалучацца з тэгамі, картамі і счытваючымі прыладамі Near Field Communication (NFC)."</string>
<string name="permlab_disableKeyguard" msgid="4977406164311535092">"адключаць блакаванне клавіятуры"</string>
- <!-- outdated translation 3189763479326302017 --> <string name="permdesc_disableKeyguard" msgid="6231611286892232626">"Дазваляе прыкладанням адключаць блакіроўку клавіятуры і абарону паролем. Добры прыклад гэтага — адключэнне блакіроўкі тэлефона пры атрыманні ўваходнага выкліка тэлефона, паўторнае ўключэнне блакіроўкі клавіятуры, калі выклік завершаны."</string>
+ <string name="permdesc_disableKeyguard" msgid="6231611286892232626">"Дазваляе прыкладанням адключаць блакаванне клавіятуры і любыя сродкі абароны, звязаныя з паролем. Прыкладам гэтага з\'яўляецца адключэнне тэлефонам блакавання клавіятуры пры атрыманні ўваходнага выкліку і паўторнае ўключэнне блакавання клавіятуры, калі выклік завершаны."</string>
<string name="permlab_readSyncSettings" msgid="6201810008230503052">"чытаць параметры сінхранізацыі"</string>
- <!-- outdated translation 5315925706353341823 --> <string name="permdesc_readSyncSettings" msgid="5464056785274229278">"Дазваляе прыкладанням счытваць налады сінхранізацыі (напрыклад, ці ўключана сінхранізацыя для кантактаў)."</string>
+ <string name="permdesc_readSyncSettings" msgid="5464056785274229278">"Дазваляе прыкладанням змяняць налады сінхранізацыі, напрыклад, ці будзе сінхранізацыя ўключана для прыкладання People."</string>
<string name="permlab_writeSyncSettings" msgid="6297138566442486462">"запісваць параметры сінхранізацыі"</string>
- <!-- outdated translation 2498201614431360044 --> <string name="permdesc_writeSyncSettings" msgid="1466056564502117130">"Дазваляе прыкладанням мяняць налады сінхранізацыі, напрыклад дазвол сінхранізацыі для Кантактаў."</string>
+ <string name="permdesc_writeSyncSettings" msgid="1466056564502117130">"Дазваляе прыкладанню змяняць налады сінхранізацыі, напрыклад, ці будзе сінхранізацыя ўключана для прыкладання People."</string>
<string name="permlab_readSyncStats" msgid="7396577451360202448">"чытаць статыстыку сінхранізацыі"</string>
- <!-- outdated translation 7511448343374465000 --> <string name="permdesc_readSyncStats" msgid="3801971839939951678">"Дазваляе прыкладанням счытваць статыстыку сінхранізацыі, напрыклад гісторыю здзейсненых сінхранізацый."</string>
+ <string name="permdesc_readSyncStats" msgid="3801971839939951678">"Дазваляе прыкладанню счытваць статыстыку сінхранізацыі, напрыклад гісторыю здзейсненых сінхранізацый."</string>
<string name="permlab_subscribedFeedsRead" msgid="4756609637053353318">"чытаць падпісаныя каналы"</string>
- <!-- outdated translation 3622200625634207660 --> <string name="permdesc_subscribedFeedsRead" msgid="5557058907906144505">"Дазваляе прыкладанням атрымліваць інфармацыю аб сінхранізацыі бягучых каналаў."</string>
+ <string name="permdesc_subscribedFeedsRead" msgid="5557058907906144505">"Дазваляе прыкладанням атрымліваць інфармацыю пра каналы, якія сінхранізуюцца ў бягучы момант."</string>
<string name="permlab_subscribedFeedsWrite" msgid="9015246325408209296">"запісваць каналы, на якія ёсць падпіска"</string>
- <!-- outdated translation 8121607099326533878 --> <string name="permdesc_subscribedFeedsWrite" msgid="6928930188826089413">"Дазваляе прыкладанням змяняць бягучыя сінхранізуемыя каналы. Гэта можа дазволіць шкоднасным прыкладанням змяняць сінхранізаваныя каналы."</string>
- <!-- outdated translation 432535716804748781 --> <string name="permlab_readDictionary" msgid="8410247960433376352">"чытаць карыстальніцкі слоўнік"</string>
- <!-- outdated translation 1082972603576360690 --> <string name="permdesc_readDictionary" msgid="8977815988329283705">"Дазваляе прыкладанням счытваць любыя прыватныя словы, імёны і фразы, якія карыстальнік можа захоўваць у карыстальніцкім слоўніку."</string>
- <!-- outdated translation 6703109511836343341 --> <string name="permlab_writeDictionary" msgid="2296383164914812772">"пісаць у карыстальніцкі слоўнік"</string>
- <!-- outdated translation 2241256206524082880 --> <string name="permdesc_writeDictionary" msgid="8185385716255065291">"Дазваляе прыкладанням запісваць новыя словы ў слоўнік карыстальніка."</string>
+ <string name="permdesc_subscribedFeedsWrite" msgid="6928930188826089413">"Дазваляе прыкладанням змяняць бягучыя каналы сінхранізавання. Шкоднасныя прыкладанні могуць змяняць вашы каналы сінхранізацыi."</string>
+ <string name="permlab_readDictionary" msgid="8410247960433376352">"чытаць карыстальніцкі слоўнік"</string>
+ <string name="permdesc_readDictionary" msgid="8977815988329283705">"Дазваляе прыкладанню счытваць любыя прыватныя словы, імёны і фразы, якія карыстальнік можа захоўваць у карыстальніцкім слоўніку."</string>
+ <string name="permlab_writeDictionary" msgid="2296383164914812772">"запісаць у карыстальніцкі слоўнік"</string>
+ <string name="permdesc_writeDictionary" msgid="8185385716255065291">"Дазваляе прыкладанням запісваць новыя словы ў карыстальніцкі слоўнік."</string>
<string name="permlab_sdcardWrite" product="nosdcard" msgid="85430876310764752">"змяніць/выдаліць змесціва USB-назапашвальнiка"</string>
<string name="permlab_sdcardWrite" product="default" msgid="8079403759001777291">"змяняць/выдаляць змесціва SD-карты"</string>
- <!-- outdated translation 6594393334785738252 --> <string name="permdesc_sdcardWrite" product="nosdcard" msgid="6175406299445710888">"Дазваляе прыкладанню запісваць дадзеныя на USB-назапашвальнiк."</string>
- <!-- outdated translation 6594393334785738252 --> <string name="permdesc_sdcardWrite" product="default" msgid="4337417790936632090">"Дазваляе прыкладанню запісваць дадзеныя на USB-назапашвальнiк."</string>
+ <string name="permdesc_sdcardWrite" product="nosdcard" msgid="6175406299445710888">"Дазваляе прыкладаням выконваць запіс ва USB-назапашвальнік."</string>
+ <string name="permdesc_sdcardWrite" product="default" msgid="4337417790936632090">"Дазваляе прыкладанням запісваць на SD-карту."</string>
<string name="permlab_mediaStorageWrite" product="default" msgid="6859839199706879015">"змяніць/выдаліць унутраныя носьбіты змесціва"</string>
- <!-- outdated translation 8232008512478316233 --> <string name="permdesc_mediaStorageWrite" product="default" msgid="8189160597698529185">"Дазваляе прыкладанням змяняць змесціва ўнутранага сховішча інфармацыі."</string>
+ <string name="permdesc_mediaStorageWrite" product="default" msgid="8189160597698529185">"Дазваляе прыкладанням змяняць змесціва ўнутранай памяці."</string>
<string name="permlab_cache_filesystem" msgid="5656487264819669824">"доступ да файлавай сістэмы кэша"</string>
- <!-- outdated translation 1624734528435659906 --> <string name="permdesc_cache_filesystem" msgid="5578967642265550955">"Дазваляе прыкладанням чытаць і запісваць дадзеныя ў файлавую сістэму кэша."</string>
+ <string name="permdesc_cache_filesystem" msgid="5578967642265550955">"Дазваляе прыкладанню счытваць і выконваць запіс у файлавую сістэму кэш-памяці."</string>
<string name="permlab_use_sip" msgid="5986952362795870502">"рабіць/прымаць iнтэрнэт-выклікі"</string>
- <!-- outdated translation 6320376185606661843 --> <string name="permdesc_use_sip" msgid="4717632000062674294">"Дазваляе прыкладанню выкарыстоўваць службу SIP, каб рабіць/прымаць iнтэрнэт-выклікі."</string>
+ <string name="permdesc_use_sip" msgid="4717632000062674294">"Дазваляе прыкладанням выкарыстоўваць службу SIP, каб прымаць/рабіць Інтэрнэт-выклікі."</string>
<string name="permlab_readNetworkUsageHistory" msgid="7862593283611493232">"чытаць дадзеныя выкарыстання сеткі"</string>
- <!-- outdated translation 6040738474779135653 --> <string name="permdesc_readNetworkUsageHistory" msgid="7689060749819126472">"Дазваляе прыкладанням чытаць дадзеныя дзённiка выкарыстання для пэўных сетак і прыкладанняў."</string>
+ <string name="permdesc_readNetworkUsageHistory" msgid="7689060749819126472">"Дазваляе прыкладанню счытваць дадзеныя аб гісторыі выкарыстання сеткі для пэўных сетак і прыкладанняў."</string>
<string name="permlab_manageNetworkPolicy" msgid="2562053592339859990">"кіраванне палітыкай сеткі"</string>
- <!-- outdated translation 3723795285132803958 --> <string name="permdesc_manageNetworkPolicy" msgid="7537586771559370668">"Дазваляе прыкладанням кіраваць сеткавымі палітыкамі і вызначаць правілы для прыкладанняў."</string>
+ <string name="permdesc_manageNetworkPolicy" msgid="7537586771559370668">"Дазваляе прыкладаннм кіраваць сеткавымі палітыкамі і вызначаць правілы пэўных прыкладанняў."</string>
<string name="permlab_modifyNetworkAccounting" msgid="5088217309088729650">"змяніць улік выкарыстання сеткі"</string>
- <!-- outdated translation 8702285686629184404 --> <string name="permdesc_modifyNetworkAccounting" msgid="8553240749784321765">"Дазваляе мадыфікаваць улік выкарыстання сеткі прыкладаннямі. Не для выкарыстання звычайнымі прыкладаннямі."</string>
+ <string name="permdesc_modifyNetworkAccounting" msgid="5443412866746198123">"Дазваляе прыкладанням змяняць метад уліку выкарыстання сеткі прыкладаннямі. Не для выкарыстання звычайнымі прыкладаннямі."</string>
<string name="policylab_limitPassword" msgid="4497420728857585791">"Устанавіць правілы паролю"</string>
- <string name="policydesc_limitPassword" msgid="9083400080861728056">"Кіраванне даўжынёй і колькасцю знакаў на экране разблакоўкі пароляў"</string>
+ <string name="policydesc_limitPassword" msgid="3252114203919510394">"Кіраванне даўжынёй і колькасцю знакаў у паролі разблакоўкі экрана."</string>
<string name="policylab_watchLogin" msgid="914130646942199503">"Сачыць за спробамі разблакоўкі экрана"</string>
- <!-- outdated translation 933601759466308092 --> <string name="policydesc_watchLogin" product="tablet" msgid="3215729294215070072">"Сачыць за колькасцю няправільных спроб уводу пароляў пры разблакоўцы экрана і блакаваць планшэт або сціраць ўсе дадзеныя на планшэце, калі ўводзіцца занадта шмат няправільных пароляў"</string>
- <!-- outdated translation 933601759466308092 --> <string name="policydesc_watchLogin" product="default" msgid="5712323091846761073">"Сачыць за колькасцю няправільных спроб уводу пароляў пры разблакоўцы экрана і блакаваць планшэт або сціраць ўсе дадзеныя на планшэце, калі ўводзіцца занадта шмат няправільных пароляў"</string>
+ <string name="policydesc_watchLogin" product="tablet" msgid="3215729294215070072">"Сачыць за колькасцю няправільных набраных пароляў падчас разблакоўкі экрана і блакаваць планшэт або сціраць усе дадзеныя на ім, калі няправільны пароль набраны занадта шмат разоў."</string>
+ <string name="policydesc_watchLogin" product="default" msgid="5712323091846761073">"Сачыць за колькасцю няправільных набраных пароляў падчас разблакоўкі экрана і блакаваць тяэлефон або сціраць усе дадзеныя на ім, калі набрана занадта шмат няправільных пароляў."</string>
<string name="policylab_resetPassword" msgid="2620077191242688955">"Змяненне паролю разблакоўкі экрана"</string>
- <string name="policydesc_resetPassword" msgid="5391240616981297361">"Змяненне паролю разблакоўкі экрана"</string>
+ <string name="policydesc_resetPassword" msgid="605963962301904458">"Змяніць пароль разблакоўкі экрана."</string>
<string name="policylab_forceLock" msgid="2274085384704248431">"Заблакаваць экран"</string>
- <string name="policydesc_forceLock" msgid="5696964126226028442">"Кіраванне часам і спосабам блакоўкі экрана"</string>
+ <string name="policydesc_forceLock" msgid="1141797588403827138">"Кіраванне часам і спосабам блакавання экрана"</string>
<string name="policylab_wipeData" msgid="3910545446758639713">"Сцерці ўсе дадзеныя"</string>
- <string name="policydesc_wipeData" product="tablet" msgid="314455232799486222">"Сцерці дадзеныя планшэта без папярэджання, выканаўшы скід налад дадзеных"</string>
- <string name="policydesc_wipeData" product="default" msgid="7669895333814222586">"Сцерці дадзеныя тэлефона без папярэджання, выканаўшы скід налад дадзеных"</string>
+ <string name="policydesc_wipeData" product="tablet" msgid="4306184096067756876">"Выдаліць дадзеныя з планшэта без папярэджання, выканаўшы скід налад."</string>
+ <string name="policydesc_wipeData" product="default" msgid="5096895604574188391">"Выдаліць дадзеныя з тэлефона без папярэджання, выканаўшы скід налад."</string>
<string name="policylab_setGlobalProxy" msgid="2784828293747791446">"Усталяваць глабальны проксі прылады"</string>
<string name="policydesc_setGlobalProxy" msgid="6387497466660154931">"Усталяваць глабальны проксі-cервер прылады, які будзе выкарыстоўвацца, калі палітыка актыўная. Толькі першы адміністратар прылады ўсталёўвае эфектыўныя глабальныя проксі-серверы."</string>
<string name="policylab_expirePassword" msgid="885279151847254056">"Нал. тэрм. дз. пар. блак. экр."</string>
- <string name="policydesc_expirePassword" msgid="4844430354224822074">"Кантраляваць, як часта трэба мяняць пароль для блакавання экрана"</string>
+ <string name="policydesc_expirePassword" msgid="1729725226314691591">"Кіраваць частатой змены паролю для блакавання экрана."</string>
<string name="policylab_encryptedStorage" msgid="8901326199909132915">"Усталяваць шыфраванне сховішча."</string>
- <!-- outdated translation 2504984732631479399 --> <string name="policydesc_encryptedStorage" msgid="8877192718681120469">"Патрабаваць шыфраванне захаваных дадзеных прыкладання"</string>
+ <string name="policydesc_encryptedStorage" msgid="2637732115325316992">"Запыт на шыфраванне захаваных дадзеных прыкладанняў."</string>
<string name="policylab_disableCamera" msgid="6395301023152297826">"Адключыць камеры"</string>
- <string name="policydesc_disableCamera" msgid="5680054212889413366">"Забарона выкарыстання ўсіх камер прылады"</string>
+ <string name="policydesc_disableCamera" msgid="2306349042834754597">"Забараніць выкарыстанне ўсіх камер прылады."</string>
<string-array name="phoneTypes">
<item msgid="8901098336658710359">"Галоўная старонка"</item>
<item msgid="869923650527136615">"Мабільны"</item>
@@ -635,14 +644,14 @@
<string name="sipAddressTypeHome" msgid="6093598181069359295">"Галоўная старонка"</string>
<string name="sipAddressTypeWork" msgid="6920725730797099047">"Працоўны"</string>
<string name="sipAddressTypeOther" msgid="4408436162950119849">"Іншае"</string>
- <!-- outdated translation 3731488827218876115 --> <string name="keyguard_password_enter_pin_code" msgid="3037685796058495017">"Увядзіце PIN-код"</string>
- <!-- outdated translation 5965173481572346878 --> <string name="keyguard_password_enter_puk_code" msgid="4800725266925845333">"Увядзіце PUK і новы PIN-код"</string>
+ <string name="keyguard_password_enter_pin_code" msgid="3037685796058495017">"Увядзіце PIN-код"</string>
+ <string name="keyguard_password_enter_puk_code" msgid="4800725266925845333">"Увядзіце PUK-код і новы PIN-код"</string>
<string name="keyguard_password_enter_puk_prompt" msgid="1341112146710087048">"PUK"</string>
- <!-- outdated translation 2987350144349051286 --> <string name="keyguard_password_enter_pin_prompt" msgid="8027680321614196258">"Новы PIN-код"</string>
- <!-- outdated translation 7906561917570259833 --> <string name="keyguard_password_entry_touch_hint" msgid="7858547464982981384"><font size="17">"Дакраніцеся, каб увесці пароль"</font></string>
- <!-- outdated translation 9138158344813213754 --> <string name="keyguard_password_enter_password_code" msgid="1054721668279049780">"Увядзіце пароль для разблакавання"</string>
- <!-- outdated translation 638347075625491514 --> <string name="keyguard_password_enter_pin_password_code" msgid="6391755146112503443">"Увядзіце PIN-код для разблакоўкі"</string>
- <string name="keyguard_password_wrong_pin_code" msgid="1295984114338107718">"Няправільны PIN-код"</string>
+ <string name="keyguard_password_enter_pin_prompt" msgid="8027680321614196258">"Новы PIN-код"</string>
+ <string name="keyguard_password_entry_touch_hint" msgid="7858547464982981384"><font size="17">"Дакраніцеся, каб увесці пароль"</font></string>
+ <string name="keyguard_password_enter_password_code" msgid="1054721668279049780">"Увядзіце пароль для разблакавання"</string>
+ <string name="keyguard_password_enter_pin_password_code" msgid="6391755146112503443">"Каб разблакаваць, увядзіце PIN-код"</string>
+ <string name="keyguard_password_wrong_pin_code" msgid="2422225591006134936">"Няправільны PIN-код."</string>
<string name="keyguard_label_text" msgid="861796461028298424">"Каб разблакаваць, націсніце \"Меню\", затым 0."</string>
<string name="emergency_call_dialog_number_for_display" msgid="696192103195090970">"Нумар экстранай службы"</string>
<string name="lockscreen_carrier_default" msgid="8963839242565653192">"Не абслугоўваецца"</string>
@@ -653,8 +662,9 @@
<string name="lockscreen_emergency_call" msgid="5347633784401285225">"Экстраны выклік"</string>
<string name="lockscreen_return_to_call" msgid="5244259785500040021">"Вярнуцца да выкліку"</string>
<string name="lockscreen_pattern_correct" msgid="9039008650362261237">"Правільна!"</string>
- <!-- outdated translation 4817583279053112312 --> <string name="lockscreen_pattern_wrong" msgid="4317955014948108794">"Паспрабуйце яшчэ раз"</string>
- <!-- outdated translation 6237443657358168819 --> <string name="lockscreen_password_wrong" msgid="5737815393253165301">"Паспрабуйце яшчэ раз"</string>
+ <string name="lockscreen_pattern_wrong" msgid="4317955014948108794">"Паспрабуйце яшчэ раз"</string>
+ <string name="lockscreen_password_wrong" msgid="5737815393253165301">"Паўтарыце спробу"</string>
+ <string name="faceunlock_multiple_failures" msgid="754137583022792429">"Перавышана максімальная колькасць спроб разблакоўкі праз Фэйскантроль"</string>
<string name="lockscreen_plugged_in" msgid="8057762828355572315">"Зарадка, <xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
<string name="lockscreen_charged" msgid="4938930459620989972">"Зараджаны."</string>
<string name="lockscreen_battery_short" msgid="3617549178603354656">"<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
@@ -662,9 +672,9 @@
<string name="lockscreen_missing_sim_message_short" msgid="7381499217732227295">"Няма SIM-карты."</string>
<string name="lockscreen_missing_sim_message" product="tablet" msgid="151659196095791474">"Няма SIM-карты ў планшэце."</string>
<string name="lockscreen_missing_sim_message" product="default" msgid="2186920585695169078">"У тэлефоне няма SIM-карты."</string>
- <!-- outdated translation 8874620818937719067 --> <string name="lockscreen_missing_sim_instructions" msgid="5372787138023272615">"Устаўце SIM-карту."</string>
- <!-- outdated translation 7138450788301444298 --> <string name="lockscreen_missing_sim_instructions_long" msgid="3526573099019319472">"SIM-карта адсутнічае ці не чытаецца. Устаўце SIM-карту."</string>
- <!-- outdated translation 1631853574702335453 --> <string name="lockscreen_permanent_disabled_sim_instructions" msgid="910904643433151371">"Вашая SIM-картка поўнасцю адключаная."\n"Звярніцеся да пастаўшчыка паслуг мабільнай сувязі, каб атрымаць іншую SIM-карту."</string>
+ <string name="lockscreen_missing_sim_instructions" msgid="5372787138023272615">"Усталюйце SIM-карту."</string>
+ <string name="lockscreen_missing_sim_instructions_long" msgid="3526573099019319472">"SIM-карта адсутнічае ці не чытаецца. Устаўце SIM-карту."</string>
+ <string name="lockscreen_permanent_disabled_sim_instructions" msgid="910904643433151371">"Ваша SIM-карта была адключана назаўсёды."\n" Звяжыцеся з аператарам бесправадной сувязі, каб атрымаць іншую SIM-карту."</string>
<string name="lockscreen_transport_prev_description" msgid="201594905152746886">"Кнопка папярэдняй кампазiцыi"</string>
<string name="lockscreen_transport_next_description" msgid="6089297650481292363">"Кнопка наступнай кампазiцыi"</string>
<string name="lockscreen_transport_pause_description" msgid="7659088786780128001">"Кнопка паўзы"</string>
@@ -673,19 +683,14 @@
<string name="emergency_calls_only" msgid="6733978304386365407">"Толькі экстраныя выклікі"</string>
<string name="lockscreen_network_locked_message" msgid="143389224986028501">"Сетка заблакаваная"</string>
<string name="lockscreen_sim_puk_locked_message" msgid="7441797339976230">"SIM-карта заблакавана PUK-кодам."</string>
- <!-- outdated translation 635967534992394321 --> <string name="lockscreen_sim_puk_locked_instructions" msgid="8127916255245181063">"Глядзіце Інструкцыю карыстальніка або звяжыцеся са службай падтрымкі."</string>
+ <string name="lockscreen_sim_puk_locked_instructions" msgid="8127916255245181063">"Глядзіце \"Інструкцыю для карыстальніка\" або звяжыцеся са службай тэхнiчнай падтрымкі."</string>
<string name="lockscreen_sim_locked_message" msgid="8066660129206001039">"SIM-карта заблакаваная."</string>
<string name="lockscreen_sim_unlock_progress_dialog_message" msgid="595323214052881264">"Разблакаванне SIM-карты..."</string>
- <!-- no translation found for lockscreen_too_many_failed_attempts_dialog_message (6481623830344107222) -->
- <skip />
- <!-- no translation found for lockscreen_too_many_failed_password_attempts_dialog_message (2725973286239344555) -->
- <skip />
- <!-- no translation found for lockscreen_too_many_failed_pin_attempts_dialog_message (6216672706545696955) -->
- <skip />
- <!-- no translation found for lockscreen_failed_attempts_almost_glogin (9191611984625460820) -->
- <skip />
- <!-- no translation found for lockscreen_failed_attempts_almost_glogin (2590227559763762751) -->
- <skip />
+ <string name="lockscreen_too_many_failed_attempts_dialog_message" msgid="6481623830344107222">"Вы няправільна ўвялі графічны ключ разблакавання пэўную колькасць разоў: <xliff:g id="NUMBER_0">%d</xliff:g>. "\n\n"Паўтарыце спробу праз наступную колькасць секунд: <xliff:g id="NUMBER_1">%d</xliff:g>."</string>
+ <string name="lockscreen_too_many_failed_password_attempts_dialog_message" msgid="2725973286239344555">"Вы няправільна ўвялі пароль пэўную колькасць разоў: <xliff:g id="NUMBER_0">%d</xliff:g>. "\n\n"Паўтарыце спробу праз наступную колькасць секунд: <xliff:g id="NUMBER_1">%d</xliff:g>."</string>
+ <string name="lockscreen_too_many_failed_pin_attempts_dialog_message" msgid="6216672706545696955">"Вы няправільна ўвялі PIN-код пэўную колькасць разоў: <xliff:g id="NUMBER_0">%d</xliff:g>. "\n\n"Паўтарыце спробу праз наступную колькасць секунд: <xliff:g id="NUMBER_1">%d</xliff:g>."</string>
+ <string name="lockscreen_failed_attempts_almost_glogin" product="tablet" msgid="9191611984625460820">"Вы няправільна ўвялі графічны ключ разблакавання пэўную колькасць разоў: <xliff:g id="NUMBER_0">%d</xliff:g>. Пасля яшчэ некалькiх няўдалых спроб (<xliff:g id="NUMBER_1">%d</xliff:g>) вам будзе прапанавана разблакаваць планшэт з дапамогай уваходу ў Google."\n\n" Паўтарыце спробу праз наступную колькасць секунд: <xliff:g id="NUMBER_2">%d</xliff:g>."</string>
+ <string name="lockscreen_failed_attempts_almost_glogin" product="default" msgid="2590227559763762751">"Вы няправільна ўвялі графічны ключ разблакавання пэўную колькасць разоў: <xliff:g id="NUMBER_0">%d</xliff:g>. Пасля яшчэ некалькiх няўдалых спроб (<xliff:g id="NUMBER_1">%d</xliff:g>) вам будзе прапанавана разблакаваць тэлефон з дапамогай уваходу ў Google."\n\n" Паўтарыце спробу праз наступную колькасць секунд: <xliff:g id="NUMBER_2">%d</xliff:g>."</string>
<string name="lockscreen_failed_attempts_almost_at_wipe" product="tablet" msgid="6128106399745755604">"Вы няправільна спрабавалі разблакаваць планшэт некалькi разоў (<xliff:g id="NUMBER_0">%d</xliff:g>). Пасля яшчэ некалькiх спробаў (<xliff:g id="NUMBER_1">%d</xliff:g>) ён будзе скінуты да заводскіх налад i карыстальнiцкiя дадзеныя будуць згубленыя."</string>
<string name="lockscreen_failed_attempts_almost_at_wipe" product="default" msgid="8603565142156826565">"Вы няправільна спрабавалі разблакаваць планшэт некалькi разоў (<xliff:g id="NUMBER_0">%d</xliff:g>). Пасля яшчэ некалькiх спробаў (<xliff:g id="NUMBER_1">%d</xliff:g>) ён будзе скінуты да заводскіх налад i карыстальнiцкiя дадзеныя будуць згубленыя."</string>
<string name="lockscreen_failed_attempts_now_wiping" product="tablet" msgid="280873516493934365">"Вы няправільна спрабавалі разблакаваць планшэт некалькi разоў (<xliff:g id="NUMBER">%d</xliff:g>). Цяпер ён будзе скінуты да заводскіх налад."</string>
@@ -693,14 +698,14 @@
<string name="lockscreen_too_many_failed_attempts_countdown" msgid="6251480343394389665">"Паўтарыце спробу праз <xliff:g id="NUMBER">%d</xliff:g> с."</string>
<string name="lockscreen_forgot_pattern_button_text" msgid="2626999449610695930">"Забылі ўзор?"</string>
<string name="lockscreen_glogin_forgot_pattern" msgid="2588521501166032747">"Разблакаванне ўліковага запісу"</string>
- <string name="lockscreen_glogin_too_many_attempts" msgid="2446246026221678244">"Занадта шмат спробаў узору!"</string>
- <string name="lockscreen_glogin_instructions" msgid="1816635201812207709">"Каб разблакаваць, увайдзіце праз уліковы запіс Google"</string>
+ <string name="lockscreen_glogin_too_many_attempts" msgid="2751368605287288808">"Занадта шмат спроб паўтарыць шаблон!"</string>
+ <string name="lockscreen_glogin_instructions" msgid="3931816256100707784">"Каб разблакаваць, увайдзіце ў свой уліковы запіс Google."</string>
<string name="lockscreen_glogin_username_hint" msgid="8846881424106484447">"Імя карыстальніка (электронная пошта)"</string>
<string name="lockscreen_glogin_password_hint" msgid="5958028383954738528">"Пароль"</string>
<string name="lockscreen_glogin_submit_button" msgid="7130893694795786300">"Увайсці"</string>
<string name="lockscreen_glogin_invalid_input" msgid="1364051473347485908">"Няправільнае імя карыстальніка ці пароль."</string>
- <string name="lockscreen_glogin_account_recovery_hint" msgid="8253152905532900548">"Забыліся на імя карыстальніка або пароль?"\n"Наведайце"<b>"google.com/accounts/recovery"</b></string>
- <string name="lockscreen_glogin_checking_password" msgid="6758890536332363322">"Праверка..."</string>
+ <string name="lockscreen_glogin_account_recovery_hint" msgid="1696924763690379073">"Забыліся на імя карыстальніка або пароль?"\n"Наведайце "<b>"google.com/accounts/recovery"</b></string>
+ <string name="lockscreen_glogin_checking_password" msgid="7114627351286933867">"Праверка..."</string>
<string name="lockscreen_unlock_label" msgid="737440483220667054">"Разблакаваць"</string>
<string name="lockscreen_sound_on_label" msgid="9068877576513425970">"Гук уключаны"</string>
<string name="lockscreen_sound_off_label" msgid="996822825154319026">"Гук выключаны"</string>
@@ -717,14 +722,13 @@
<string name="factorytest_not_system" msgid="4435201656767276723">"Дзеянне FACTORY_TEST падтрымліваецца толькі для пакетаў, усталяваных на шляху /system/app."</string>
<string name="factorytest_no_action" msgid="872991874799998561">"Пакет, які выконвае дзеянне FACTORY_TEST, не знойдзены."</string>
<string name="factorytest_reboot" msgid="6320168203050791643">"Перазагрузіць"</string>
- <string name="js_dialog_title" msgid="8143918455087008109">"Старонка з адрасам \"<xliff:g id="TITLE">%s</xliff:g>\" кажа:"</string>
+ <string name="js_dialog_title" msgid="1987483977834603872">"На старонцы з адрасам <xliff:g id="TITLE">%s</xliff:g> вызначана:"</string>
<string name="js_dialog_title_default" msgid="6961903213729667573">"JavaScript"</string>
- <!-- no translation found for js_dialog_before_unload (730366588032430474) -->
- <skip />
+ <string name="js_dialog_before_unload" msgid="730366588032430474">"Пакiнуць гэту старонку?"\n\n"<xliff:g id="MESSAGE">%s</xliff:g>"\n\n"Націсніце \"OK\", каб працягнуць, або \"Адмена\", каб застацца на бягучай старонцы."</string>
<string name="save_password_label" msgid="6860261758665825069">"Пацвердзіць"</string>
- <!-- outdated translation 1068216937244567247 --> <string name="double_tap_toast" msgid="2729045387923870404">"Падказка: націсніце двойчы, каб павялічыць або паменшыць."</string>
- <string name="autofill_this_form" msgid="1272247532604569872">"Аўтазапаўненне"</string>
- <string name="setup_autofill" msgid="8154593408885654044">"Усталёўка аўтазапаўнення"</string>
+ <string name="double_tap_toast" msgid="4595046515400268881">"Падказка: двойчы націсніце, каб павялічыць або паменшыць."</string>
+ <string name="autofill_this_form" msgid="4616758841157816676">"Аўтазапаўненне"</string>
+ <string name="setup_autofill" msgid="7103495070180590814">"Усталяванне аўтазапаўнення"</string>
<string name="autofill_address_name_separator" msgid="2504700673286691795">" "</string>
<string name="autofill_address_summary_name_format" msgid="3268041054899214945">"$1$2$3"</string>
<string name="autofill_address_summary_separator" msgid="7483307893170324129">", "</string>
@@ -742,25 +746,25 @@
<string name="autofill_area" msgid="3547409050889952423">"Плошча"</string>
<string name="autofill_emirate" msgid="2893880978835698818">"Эмірат"</string>
<string name="permlab_readHistoryBookmarks" msgid="1284843728203412135">"чытаць гісторыю браўзэра і закладак"</string>
- <!-- outdated translation 4981489815467617191 --> <string name="permdesc_readHistoryBookmarks" msgid="4577476392604595921">"Дазваляе прыкладанням счытваць усе URL, якія наведвалiся з браўзэра, а таксама ўсе закладкi."</string>
+ <string name="permdesc_readHistoryBookmarks" msgid="4577476392604595921">"Дазваляе прыкладанням счытваць усе URL, якія наведвалiся з браўзэра, а таксама ўсе закладкi браўзэра."</string>
<string name="permlab_writeHistoryBookmarks" msgid="9009434109836280374">"пісаць гісторыю браўзэра і закладак"</string>
- <!-- outdated translation 7193514090469945307 --> <string name="permdesc_writeHistoryBookmarks" product="tablet" msgid="1757103804824209530">"Дазваляе прыкладанням змяняць гісторыю браўзэра або закладкі, якія захоўваюцца на планшэце. Шкоднасныя прыкладанні могуць выкарыстоўваць гэтую магчымасць, каб выдаляць або змяняць дадзеныя вашага браўзэра."</string>
- <!-- outdated translation 7193514090469945307 --> <string name="permdesc_writeHistoryBookmarks" product="default" msgid="6693764355720719197">"Дазваляе прыкладанням змяняць гісторыю браўзэра або закладкі, якія захоўваюцца на планшэце. Шкоднасныя прыкладанні могуць выкарыстоўваць гэтую магчымасць, каб выдаляць або змяняць дадзеныя вашага браўзэра."</string>
+ <string name="permdesc_writeHistoryBookmarks" product="tablet" msgid="1757103804824209530">"Дазваляе прыкладанням змяняць гісторыю браўзэра або закладкі, якія захоўваюцца на планшэце. Шкоднасныя прыкладанні могуць выкарыстоўваць гэту магчымасць для выдалення або змены дадзеных вашага браўзэра."</string>
+ <string name="permdesc_writeHistoryBookmarks" product="default" msgid="6693764355720719197">"Дазваляе прыкладанням змяняць гісторыю браўзэра або закладак, захаваных у тэлефоне. Шкоднасныя прыкладанні могуць выкарыстоўваць гэту магчымасць для выдалення або змены дадзеных вашага браўзэра."</string>
<string name="permlab_setAlarm" msgid="5924401328803615165">"Усталяваць сігнал у будзільніку"</string>
- <!-- outdated translation 5966966598149875082 --> <string name="permdesc_setAlarm" msgid="316392039157473848">"Дазваляе прыкладанням задаваць сігнал усталяванага прыкладання будзільніка. Пэўныя прыкладанні будзільніка не могуць рэалізаваць гэтую функцыю."</string>
+ <string name="permdesc_setAlarm" msgid="316392039157473848">"Дазваляе прыкладанню ўсталёўваць сігнал на ўсталяваным прыкладанні будзільніка. Пэўныя прыкладанні будзільніка не могуць рэалізоўваць гэтую магчымасць."</string>
<string name="permlab_addVoicemail" msgid="5525660026090959044">"дадаць галасавое паведамленне"</string>
- <!-- outdated translation 4828507394878206682 --> <string name="permdesc_addVoicemail" msgid="6604508651428252437">"Дазваляе праграме дадаваць паведамленні ў паштовую скрыню галасавых паведамленняў."</string>
- <!-- outdated translation 4715212655598275532 --> <string name="permlab_writeGeolocationPermissions" msgid="5962224158955273932">"Змяніць дазволы геапазіцыянавання для браўзэра"</string>
- <!-- outdated translation 4011908282980861679 --> <string name="permdesc_writeGeolocationPermissions" msgid="1083743234522638747">"Дазваляе прыкладанням змяняць дазволы геалакацыі браўзэра. Шкодныя прыкладанні могуць карыстацца гэтым, каб дазваляць адпраўку інфармацыі аб месцазнаходжанні адвольным вэб-сайтам."</string>
+ <string name="permdesc_addVoicemail" msgid="6604508651428252437">"Дазваляе прыкладанням дадаваць паведамленні ў вашу скрыню галасавой пошты."</string>
+ <string name="permlab_writeGeolocationPermissions" msgid="5962224158955273932">"змяніць дазволы геапазіцыянавання для браўзэра"</string>
+ <string name="permdesc_writeGeolocationPermissions" msgid="1083743234522638747">"Дазваляе прыкладанням змяняць дазволы геалакацыі браўзэра. Шкоднасныя прыкладанні могуць выкарыстоўваць гэта, каб дазваляць адпраўку інфармацыі аб месцазнаходжанні выпадковым вэб-сайтам."</string>
<string name="permlab_packageVerificationAgent" msgid="5568139100645829117">"верыфікаваць пакеты"</string>
- <!-- outdated translation 6033195477325381106 --> <string name="permdesc_packageVerificationAgent" msgid="8437590190990843381">"Дазваляе прыкладанням правяраць магчымасць усталёўкі пакету."</string>
+ <string name="permdesc_packageVerificationAgent" msgid="8437590190990843381">"Дазваляе прыкладанням правяраць магчымасць усталявання пакету."</string>
<string name="permlab_bindPackageVerifier" msgid="4187786793360326654">"прывязаць да верыфікатару пакету"</string>
- <!-- outdated translation 2409521927385789318 --> <string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"Дазваляе ўладальніку рабіць запыты верыфікатараў пакету. Не патрабуецца для звычайных прыкладанняў."</string>
+ <string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"Дазваляе ўладальніку рабіць запыты верыфікатараў пакету. Не патрабуецца для звычайных прыкладанняў."</string>
<string name="save_password_message" msgid="767344687139195790">"Вы хочаце, каб браўзэр запомніў гэты пароль?"</string>
<string name="save_password_notnow" msgid="6389675316706699758">"Не цяпер"</string>
<string name="save_password_remember" msgid="6491879678996749466">"Запомніць"</string>
<string name="save_password_never" msgid="8274330296785855105">"Ніколі"</string>
- <!-- outdated translation 5661861460947222274 --> <string name="open_permission_deny" msgid="7374036708316629800">"У вас няма дазволу адкрываць гэтую старонку."</string>
+ <string name="open_permission_deny" msgid="7374036708316629800">"У вас няма дазволу на адкрыццё гэтай старонкі."</string>
<string name="text_copied" msgid="4985729524670131385">"Тэкст скапіяваны ў буфер абмену."</string>
<string name="more_item_label" msgid="4650918923083320495">"Больш"</string>
<string name="prepend_shortcut_label" msgid="2572214461676015642">"Меню+"</string>
@@ -859,9 +863,9 @@
<string name="weeks" msgid="6509623834583944518">"тыд."</string>
<string name="year" msgid="4001118221013892076">"год"</string>
<string name="years" msgid="6881577717993213522">"г."</string>
- <!-- outdated translation 3359437293118172396 --> <string name="VideoView_error_title" msgid="5927895235831021723">"Немагчыма прайграць відэа"</string>
- <!-- outdated translation 897920883624437033 --> <string name="VideoView_error_text_invalid_progressive_playback" msgid="3186670335938670444">"Гэтае відэа не падыходзіць для патокавай перадачы на гэтую прыладу."</string>
- <!-- outdated translation 710301040038083944 --> <string name="VideoView_error_text_unknown" msgid="4309847331399592194">"На жаль, гэтае відэа не можа быць прайграна."</string>
+ <string name="VideoView_error_title" msgid="3534509135438353077">"Праблема з відэа"</string>
+ <string name="VideoView_error_text_invalid_progressive_playback" msgid="3186670335938670444">"Відэа не падыходзіць для патокавай перадачы на гэту прыладу."</string>
+ <string name="VideoView_error_text_unknown" msgid="3450439155187810085">"Немагчыма прайграць гэта відэа."</string>
<string name="VideoView_error_button" msgid="2822238215100679592">"ОК"</string>
<string name="relative_time" msgid="1818557177829411417">"<xliff:g id="DATE">%1$s</xliff:g>, <xliff:g id="TIME">%2$s</xliff:g>"</string>
<string name="noon" msgid="7245353528818587908">"апоўдні"</string>
@@ -877,7 +881,7 @@
<string name="replace" msgid="5781686059063148930">"Замяніць..."</string>
<string name="delete" msgid="6098684844021697789">"Выдаліць"</string>
<string name="copyUrl" msgid="2538211579596067402">"Скапіяваць URL"</string>
- <!-- outdated translation 6738556348861347240 --> <string name="selectTextMode" msgid="1018691815143165326">"Вылучыць тэкст..."</string>
+ <string name="selectTextMode" msgid="1018691815143165326">"Выбраць тэкст"</string>
<string name="textSelectionCABTitle" msgid="5236850394370820357">"Вылучэнне тэксту"</string>
<string name="addToDictionary" msgid="9090375111134433012">"дадаць у слоўнік"</string>
<string name="deleteText" msgid="7070985395199629156">"выдаліць"</string>
@@ -891,57 +895,52 @@
<string name="yes" msgid="5362982303337969312">"ОК"</string>
<string name="no" msgid="5141531044935541497">"Адмяніць"</string>
<string name="dialog_alert_title" msgid="2049658708609043103">"Увага"</string>
- <!-- outdated translation 1760724998928255250 --> <string name="loading" msgid="7933681260296021180">"Загрузка..."</string>
+ <string name="loading" msgid="7933681260296021180">"Загрузка..."</string>
<string name="capital_on" msgid="1544682755514494298">"Уключыць"</string>
<string name="capital_off" msgid="6815870386972805832">"Адключана"</string>
<string name="whichApplication" msgid="4533185947064773386">"Завяршыць дзеянне з дапамогай"</string>
<string name="alwaysUse" msgid="4583018368000610438">"Выкарыстоўваць па змаўчанні для гэтага дзеяння."</string>
- <!-- outdated translation 4815455344600932173 --> <string name="clearDefaultHintMsg" msgid="3252584689512077257">"Ачысціць налады па змаўчанні ў меню \"Налады > Прыкладанні > Кіраванне прыкладаннямі."</string>
- <string name="chooseActivity" msgid="1009246475582238425">"Выберыце дзеянне."</string>
- <!-- outdated translation 7892597146032121735 --> <string name="chooseUsbActivity" msgid="6894748416073583509">"Выберыце праграму для USB-прылады"</string>
- <!-- outdated translation 1691104391758345586 --> <string name="noApplications" msgid="2991814273936504689">"Ніякае прыкладанне не можа выканаць гэтае дзеянне."</string>
+ <string name="clearDefaultHintMsg" msgid="3252584689512077257">"Ачысціць па змаўчанні ў раздзеле \"Налады сістэмы > Прыкладанні > Спампаваныя\"."</string>
+ <string name="chooseActivity" msgid="7486876147751803333">"Выберыце дзеянне"</string>
+ <string name="chooseUsbActivity" msgid="6894748416073583509">"Выберыце прыкладанне для USB-прылады"</string>
+ <string name="noApplications" msgid="2991814273936504689">"Няма прыкладанняў, якія могуць выконваць гэты працэс."</string>
<string name="aerr_title" msgid="1905800560317137752"></string>
<string name="aerr_application" msgid="932628488013092776">"На жаль, прыкладанне <xliff:g id="APPLICATION">%1$s</xliff:g> спынілася."</string>
<string name="aerr_process" msgid="4507058997035697579">"На жаль, працэс <xliff:g id="PROCESS">%1$s</xliff:g> спыніўся."</string>
<string name="anr_title" msgid="4351948481459135709"></string>
- <!-- no translation found for anr_activity_application (1904477189057199066) -->
- <skip />
- <!-- no translation found for anr_activity_process (5776209883299089767) -->
- <skip />
- <!-- no translation found for anr_application_process (8941757607340481057) -->
- <skip />
- <!-- no translation found for anr_process (6513209874880517125) -->
- <skip />
+ <string name="anr_activity_application" msgid="1904477189057199066">"Прыкладанне <xliff:g id="APPLICATION">%2$s</xliff:g> не адказвае."\n\n"Закрыць яго?"</string>
+ <string name="anr_activity_process" msgid="5776209883299089767">"Працэс <xliff:g id="ACTIVITY">%1$s</xliff:g> не адказвае."\n\n"Закрыць яго?"</string>
+ <string name="anr_application_process" msgid="8941757607340481057">"Прыкладанне <xliff:g id="APPLICATION">%1$s</xliff:g> не адказвае. Закрыць яго?"</string>
+ <string name="anr_process" msgid="6513209874880517125">"Працэс <xliff:g id="PROCESS">%1$s</xliff:g> не адказвае."\n\n"Закрыць яго?"</string>
<string name="force_close" msgid="8346072094521265605">"ОК"</string>
<string name="report" msgid="4060218260984795706">"Справаздача"</string>
<string name="wait" msgid="7147118217226317732">"Чакаць"</string>
- <!-- outdated translation 8323761616052121936 --> <string name="launch_warning_title" msgid="1547997780506713581">"Прыкладанне перанакіраванае"</string>
+ <string name="webpage_unresponsive" msgid="3272758351138122503">"Старонка не адказвае на запыты."\n\n"Закрыць яе?"</string>
+ <string name="launch_warning_title" msgid="1547997780506713581">"Прыкл. перанакіраванае"</string>
<string name="launch_warning_replace" msgid="6202498949970281412">"Прыкладанне <xliff:g id="APP_NAME">%1$s</xliff:g> зараз запушчанае."</string>
<string name="launch_warning_original" msgid="188102023021668683">"Прыкладанне <xliff:g id="APP_NAME">%1$s</xliff:g> запушчанае."</string>
<string name="screen_compat_mode_scale" msgid="3202955667675944499">"Шкала"</string>
<string name="screen_compat_mode_show" msgid="4013878876486655892">"Заўсёды паказваць"</string>
- <!-- outdated translation 2953716574198046484 --> <string name="screen_compat_mode_hint" msgid="1064524084543304459">"Каб зноў уключыць, перайдзіце ў Налады > Прыкладанні > Кіраванне прыкладаннямі."</string>
- <!-- no translation found for smv_application (3307209192155442829) -->
- <skip />
+ <string name="screen_compat_mode_hint" msgid="1064524084543304459">"Зноў уключыце гэта ў раздзеле \"Сістэмныя налады > Прыкладанні > Спампаваныя\"."</string>
+ <string name="smv_application" msgid="3307209192155442829">"Прыкладанне <xliff:g id="APPLICATION">%1$s</xliff:g> (працэс <xliff:g id="PROCESS">%2$s</xliff:g>) парушыла ўласную палітыку StrictMode."</string>
<string name="smv_process" msgid="5120397012047462446">"Працэс <xliff:g id="PROCESS">%1$s</xliff:g> парушыў уласную палітыку StrictMode."</string>
- <!-- outdated translation 378740715658358071 --> <string name="android_upgrading_title" msgid="1584192285441405746">"Абнаўленне Android..."</string>
- <!-- no translation found for android_upgrading_apk (7904042682111526169) -->
- <skip />
- <!-- outdated translation 7959542881906488763 --> <string name="android_upgrading_starting_apps" msgid="451464516346926713">"Запуск прыкладанняў."</string>
+ <string name="android_upgrading_title" msgid="1584192285441405746">"Абнаўленне Android..."</string>
+ <string name="android_upgrading_apk" msgid="7904042682111526169">"Аптымізацыя прыкладання <xliff:g id="NUMBER_0">%1$d</xliff:g> з <xliff:g id="NUMBER_1">%2$d</xliff:g>."</string>
+ <string name="android_upgrading_starting_apps" msgid="451464516346926713">"Запуск прыкладанняў."</string>
<string name="android_upgrading_complete" msgid="1405954754112999229">"Завяршэнне загрузкі."</string>
<string name="heavy_weight_notification" msgid="9087063985776626166">"Прыкладанне \"<xliff:g id="APP">%1$s</xliff:g>\" запушчанае"</string>
- <!-- outdated translation 2423977499339403402 --> <string name="heavy_weight_notification_detail" msgid="1721681741617898865">"Выберыце, каб пераключыцца да прыкладання"</string>
- <!-- outdated translation 1135403633766694316 --> <string name="heavy_weight_switcher_title" msgid="7153167085403298169">"Пераключыць прыкладанні?"</string>
- <!-- outdated translation 4592075610079319667 --> <string name="heavy_weight_switcher_text" msgid="7022631924534406403">"Ужо запушчана іншае прыкладанне, якое павінна быць спыненае перад запускам новага."</string>
+ <string name="heavy_weight_notification_detail" msgid="1721681741617898865">"Націсніце, каб перайсці да прыкладання"</string>
+ <string name="heavy_weight_switcher_title" msgid="7153167085403298169">"Пераключыць прыкладанні?"</string>
+ <string name="heavy_weight_switcher_text" msgid="7022631924534406403">"Ужо запушчана іншае прыкладанне, якое павінна быць спынена перад запускам новага."</string>
<string name="old_app_action" msgid="493129172238566282">"Вярнуцца да <xliff:g id="OLD_APP">%1$s</xliff:g>"</string>
- <!-- outdated translation 942967900237208466 --> <string name="old_app_description" msgid="2082094275580358049">"Не запускайце новае прыкладанне."</string>
+ <string name="old_app_description" msgid="2082094275580358049">"Не запускайце новыя прыкладанні."</string>
<string name="new_app_action" msgid="5472756926945440706">"Запусціць <xliff:g id="OLD_APP">%1$s</xliff:g>"</string>
- <!-- outdated translation 6830398339826789493 --> <string name="new_app_description" msgid="1932143598371537340">"Спыніць старое прыкладанне, не захоўваючы яго."</string>
- <string name="sendText" msgid="5132506121645618310">"Выберыце дзеянне для тэксту"</string>
+ <string name="new_app_description" msgid="1932143598371537340">"Спыніць старыя прыкладанні без захавання."</string>
+ <string name="sendText" msgid="5209874571959469142">"Выберыце дзеянне для тэкста"</string>
<string name="volume_ringtone" msgid="6885421406845734650">"Гучнасць званка"</string>
<string name="volume_music" msgid="5421651157138628171">"Гучнасць прайгравальніка"</string>
<string name="volume_music_hint_playing_through_bluetooth" msgid="9165984379394601533">"Прайграваецца праз Bluetooth"</string>
- <string name="volume_music_hint_silent_ringtone_selected" msgid="6158339745293431194">"Выбрана ціхая мелодыя"</string>
+ <string name="volume_music_hint_silent_ringtone_selected" msgid="8310739960973156272">"Усталяваны ціхі рэжым"</string>
<string name="volume_call" msgid="3941680041282788711">"Гучнасць падчас размовы"</string>
<string name="volume_bluetooth_call" msgid="2002891926351151534">"Гучнасць Bluetooth падчас выкліку"</string>
<string name="volume_alarm" msgid="1985191616042689100">"Гучнасць будзільніка"</string>
@@ -965,30 +964,35 @@
<item quantity="one" msgid="1634101450343277345">"Адкрытая сетка Wi-Fi даступная"</item>
<item quantity="other" msgid="7915895323644292768">"Даступны адкрытыя сеткі Wi-Fi"</item>
</plurals>
- <string name="wifi_available_sign_in" msgid="9157196203958866662">"Уваход у сетку Wi-Fi"</string>
+ <string name="wifi_available_sign_in" msgid="4029489716605255386">"Увайдзіце ў сетку Wi-Fi"</string>
<!-- no translation found for wifi_available_sign_in_detailed (6797764740339907572) -->
<skip />
<string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Немагчыма падключыцца да Wi-Fi"</string>
- <string name="wifi_watchdog_network_disabled_detailed" msgid="4917472096696322767">" дрэннае падключэнне да Інтэрнэту."</string>
+ <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" дрэннае падключэнне да Інтэрнэту."</string>
<string name="wifi_p2p_dialog_title" msgid="97611782659324517">"Wi-Fi Direct"</string>
- <string name="wifi_p2p_turnon_message" msgid="2804722042556269129">"Пачаць работу Wi-Fi Direct. Гэта адключыць Wi-Fi кліента/кропку доступу."</string>
- <string name="wifi_p2p_failed_message" msgid="1820097493844848281">"Немагчыма запусціць Wi-Fi Direct"</string>
- <string name="wifi_p2p_pbc_go_negotiation_request_message" msgid="3170321684621420428">"Запыт злучэння Wi-Fi Direct ад <xliff:g id="P2P_DEVICE_ADDRESS">%1$s</xliff:g>. Націсніце \"ОК\", каб прыняць."</string>
- <string name="wifi_p2p_pin_go_negotiation_request_message" msgid="5177412094633377308">"Запыт злучэння Wi-Fi Direct ад <xliff:g id="P2P_DEVICE_ADDRESS">%1$s</xliff:g>. Увядзіце PIN-код для працягу."</string>
- <string name="wifi_p2p_pin_display_message" msgid="2834049169114922902">"Для працягу настройкі злучэння неабходна ўвесці PIN-код WPS <xliff:g id="P2P_WPS_PIN">%1$s</xliff:g> на аднарангавай прыладзе <xliff:g id="P2P_CLIENT_ADDRESS">%2$s</xliff:g>"</string>
+ <string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"Пачаць работу Wi-Fi Direct. Гэта адключыць кліента або кропку доступу Wi-Fi."</string>
+ <string name="wifi_p2p_failed_message" msgid="3763669677935623084">"Немагчыма запусціць Wi-Fi Direct."</string>
+ <string name="accept" msgid="1645267259272829559">"Прыняць"</string>
+ <string name="decline" msgid="2112225451706137894">"Адхіліць"</string>
+ <string name="wifi_p2p_invitation_sent_title" msgid="1318975185112070734">"Запрашэнне адпраўлена"</string>
+ <string name="wifi_p2p_invitation_to_connect_title" msgid="4958803948658533637">"Запрашэнне далучыцца"</string>
+ <string name="wifi_p2p_from_message" msgid="570389174731951769">"Ад:"</string>
+ <string name="wifi_p2p_to_message" msgid="248968974522044099">"Каму:"</string>
+ <string name="wifi_p2p_enter_pin_message" msgid="5920929550367828970">"Увядзіце патрэбны PIN-код:"</string>
+ <string name="wifi_p2p_show_pin_message" msgid="8530563323880921094">"PIN-код"</string>
<string name="wifi_p2p_enabled_notification_title" msgid="2068321881673734886">"Wi-Fi Direct уключаны"</string>
<string name="wifi_p2p_enabled_notification_message" msgid="1638949953993894335">"Дакраніцеся, каб наладзіць"</string>
<string name="select_character" msgid="3365550120617701745">"Уставіць сімвал"</string>
- <!-- outdated translation 7630529934366549163 --> <string name="sms_control_default_app_name" msgid="3058577482636640465">"Невядомае прыкладанне"</string>
+ <string name="sms_control_default_app_name" msgid="3058577482636640465">"Невядомае прыкладанне"</string>
<string name="sms_control_title" msgid="7296612781128917719">"Адпраўка SMS"</string>
- <!-- outdated translation 1289331457999236205 --> <string name="sms_control_message" msgid="4073755190243093924">"Адпраўляецца вялікая колькасць SMS. Выберыце \"OK\", каб працягнуць, ці \"Адмена\", каб спыніць адпраўку."</string>
+ <string name="sms_control_message" msgid="4073755190243093924">"Адпраўляецца вялікая колькасць SMS-паведамленняў. Націсніце \"OK\", каб працягнуць, ці \"Адмена\", каб спыніць адпраўку."</string>
<string name="sms_control_yes" msgid="2532062172402615953">"ОК"</string>
<string name="sms_control_no" msgid="1715320703137199869">"Адмяніць"</string>
<string name="sim_removed_title" msgid="6227712319223226185">"SIM-карта выдаленая"</string>
<string name="sim_removed_message" msgid="2333164559970958645">"Мабільная сетка будзе недаступная да перазагрузкі з дзеючай SIM-картай."</string>
<string name="sim_done_button" msgid="827949989369963775">"Гатова"</string>
<string name="sim_added_title" msgid="3719670512889674693">"SIM-карта дадазеная"</string>
- <string name="sim_added_message" msgid="1209265974048554242">"Для доступу да мабільнай сеткі неабходна перазагрузіць прыладу."</string>
+ <string name="sim_added_message" msgid="6599945301141050216">"Перазагрузіце прыладу, каб атрымаць доступ да мабільнай сеткі."</string>
<string name="sim_restart_button" msgid="4722407842815232347">"Перазапусціць"</string>
<string name="time_picker_dialog_title" msgid="8349362623068819295">"Усталяваць час"</string>
<string name="date_picker_dialog_title" msgid="5879450659453782278">"Усталяваць дату"</string>
@@ -997,40 +1001,40 @@
<string name="no_permissions" msgid="7283357728219338112">"Дазволу не патрабуецца"</string>
<string name="perms_hide" msgid="7283915391320676226"><b>"Не паказваць"</b></string>
<string name="perms_show_all" msgid="2671791163933091180"><b>"Паказаць усе"</b></string>
- <string name="usb_storage_activity_title" msgid="2399289999608900443">"USB-назапашвальнік"</string>
+ <string name="usb_storage_activity_title" msgid="4465055157209648641">"Унiверсальны USB-назапашвальнік"</string>
<string name="usb_storage_title" msgid="5901459041398751495">"USB падлучаны"</string>
- <string name="usb_storage_message" product="nosdcard" msgid="6631094834151575841">"Вы падключыліся да кампутара праз USB. Націсніце кнопку ніжэй, калі вы хочаце капіраваць файлы з кампутара і USB-назапашвальнiка Android."</string>
- <string name="usb_storage_message" product="default" msgid="4510858346516069238">"Вы падключыліся да кампутара праз USB. Націсніце кнопку ніжэй, калі хочаце капіяваць файлы з кампутара і вашай SD-карты Android."</string>
+ <string name="usb_storage_message" product="nosdcard" msgid="3308538094316477839">"Вы падлучаны да камп\'ютара праз USB. Націсніце на кнопку ніжэй, калі жадаеце капіраваць файлы з камп\'ютара на USB-назапашвальнік прылады Android і наадварот."</string>
+ <string name="usb_storage_message" product="default" msgid="805351000446037811">"Вы падключыліся да камп\'ютара праз USB. Націсніце на кнопку ніжэй, калі вы жадаеце скапіраваць файлы з камп\'ютара на SD-карту прылады Android і наадварот."</string>
<string name="usb_storage_button_mount" msgid="1052259930369508235">"Уключыць USB-назапашвальнiк"</string>
- <string name="usb_storage_error_message" product="nosdcard" msgid="3276413764430468454">"Праблема з выкарыстаннем USB-назапашвальнiка для прылады захоўвання дадзеных USB."</string>
- <string name="usb_storage_error_message" product="default" msgid="120810397713773275">"Праблема з выкарыстаннем SD-карты для USB-назапашвальнiка дадзеных."</string>
+ <string name="usb_storage_error_message" product="nosdcard" msgid="3017045217365540658">"Паўстала праблема з выкарыстаннем USB-назапашвальнiка ва ўнiверсальным USB-назапашвальнiку."</string>
+ <string name="usb_storage_error_message" product="default" msgid="2876018512716970313">"Паўстала праблема выкарыстання SD-карты ва ўнiверсальным USB-назапашвальнiку."</string>
<string name="usb_storage_notification_title" msgid="8175892554757216525">"USB падключаны"</string>
- <string name="usb_storage_notification_message" msgid="7380082404288219341">"Выберыце файлы для капіявання паміж тэлефонам і кампутарам."</string>
+ <string name="usb_storage_notification_message" msgid="939822783828183763">"Дакраніцеся, каб капіяваць файлы з камп\'ютара цi на яго."</string>
<string name="usb_storage_stop_notification_title" msgid="2336058396663516017">"Выключыць USB-назапашвальнiк"</string>
- <string name="usb_storage_stop_notification_message" msgid="2591813490269841539">"Выберыце, каб адключыць гэты USB-назапашвальнiк."</string>
+ <string name="usb_storage_stop_notification_message" msgid="1656852098555623822">"Націсніце, каб адключыць USB-назапашвальнік."</string>
<string name="usb_storage_stop_title" msgid="660129851708775853">"USB-назапашвальнік выкарыстоўваецца"</string>
- <string name="usb_storage_stop_message" product="nosdcard" msgid="1368842269463745067">"Перш чым адключыць USB-назпашвальнiк, пераканайцеся, што вы адключылі (...выцягнулі...) USB-назапашвальнiк Android з кампутара."</string>
- <string name="usb_storage_stop_message" product="default" msgid="3613713396426604104">"Перш чым адключыць USB-назапашвальнік, пераканайцеся, што SD-карта Android адключана ад кампутара."</string>
+ <string name="usb_storage_stop_message" product="nosdcard" msgid="4264025280777219521">"Перш чым адключыць USB-назапашвальнік, адключыце(\"вымiце\") USB-назапашвальнік прылады Android ад камп\'ютара."</string>
+ <string name="usb_storage_stop_message" product="default" msgid="8043969782460613114">"Перш чым адключыць USB-назапашвальнік, адключыце(\"вымiце\") SD-карту вашай прылады Android з камп\'ютара."</string>
<string name="usb_storage_stop_button_mount" msgid="7060218034900696029">"Адключыць USB-назапашвальнiк"</string>
- <string name="usb_storage_stop_error_message" msgid="143881914840412108">"Праблема адключэння USB-назапашвальнiка. Пераканайцеся ў тым, што вы адлучылі хост USB, а затым паўтарыце спробу."</string>
+ <string name="usb_storage_stop_error_message" msgid="1970374898263063836">"Памылка адключэння USB-назапашвальніка. Пераканайцеся, што вы адключылі хост USB, а потым паўтарыце спробу."</string>
<string name="dlg_confirm_kill_storage_users_title" msgid="963039033470478697">"Падключыць USB-назапашвальнiк"</string>
- <!-- outdated translation 3202838234780505886 --> <string name="dlg_confirm_kill_storage_users_text" msgid="6206212680430268343">"Калі вы падлучыце USB-назапашвальнік, некаторыя прыкладанні, якія вы выкарыстоўваеце, спыняцца і могуць быць недаступныя, пакуль USB-назапашвальнік не будзе адключаны."</string>
+ <string name="dlg_confirm_kill_storage_users_text" msgid="5100428757107469454">"Калі вы ўключыце USB-назапашвальнік, некаторыя прыкладанні, якія вы выкарыстоўваеце, спыняцца і могуць быць недаступныя, пакуль USB-назапашвальнік не будзе адключаны."</string>
<string name="dlg_error_title" msgid="7323658469626514207">"Памылка працы USB"</string>
<string name="dlg_ok" msgid="7376953167039865701">"ОК"</string>
<string name="usb_mtp_notification_title" msgid="3699913097391550394">"Падлучана як медыя-прылада"</string>
<string name="usb_ptp_notification_title" msgid="1960817192216064833">"Падключаны як камера"</string>
<string name="usb_cd_installer_notification_title" msgid="6774712827892090754">"Падлучаны як усталявальнік"</string>
<string name="usb_accessory_notification_title" msgid="7848236974087653666">"Падключаны да USB-прылады"</string>
- <string name="usb_notification_message" msgid="4447869605109736382">"Націсніце, каб убачыць параметры USB"</string>
- <!-- outdated translation 7980995592595097841 --> <string name="extmedia_format_title" product="nosdcard" msgid="9020092196061007262">"Фарматаваць USB-назапашвальнiк"</string>
- <!-- outdated translation 7980995592595097841 --> <string name="extmedia_format_title" product="default" msgid="3648415921526526069">"Фарматаваць USB-назапашвальнiк"</string>
- <!-- outdated translation 8296908079722897772 --> <string name="extmedia_format_message" product="nosdcard" msgid="3934016853425761078">"Фарматаваць USB-назапашвальнiк, выдаліўшы ўсе файлы, якія захоўваюцца там? Адмянiць нельга"</string>
- <!-- outdated translation 8296908079722897772 --> <string name="extmedia_format_message" product="default" msgid="14131895027543830">"Фарматаваць USB-назапашвальнiк, выдаліўшы ўсе файлы, якія захоўваюцца там? Адмянiць нельга"</string>
+ <string name="usb_notification_message" msgid="2290859399983720271">"Націсніце, каб убачыць іншыя параметры USB."</string>
+ <string name="extmedia_format_title" product="nosdcard" msgid="9020092196061007262">"Фарматаваць USB-назапашвальнiк?"</string>
+ <string name="extmedia_format_title" product="default" msgid="3648415921526526069">"Фарматаваць SD-карту?"</string>
+ <string name="extmedia_format_message" product="nosdcard" msgid="3934016853425761078">"Усе файлы, якія захоўваюцца на вашым USB-назапашвальніку, будуць выдалены. Гэта дзеянне не можа быць адменена."</string>
+ <string name="extmedia_format_message" product="default" msgid="14131895027543830">"Усе дадзеныя на карце будуць страчаны."</string>
<string name="extmedia_format_button_format" msgid="4131064560127478695">"Фармат"</string>
<string name="adb_active_notification_title" msgid="6729044778949189918">"Прылада адладкі USB падключана"</string>
- <!-- outdated translation 8592219392855947984 --> <string name="adb_active_notification_message" msgid="1016654627626476142">"Гэты кіёск абсталяваны Nexus S."</string>
- <!-- outdated translation 6865512749462072765 --> <string name="select_input_method" msgid="4653387336791222978">"Выберыце метад уводу"</string>
- <!-- outdated translation 6324843080254191535 --> <string name="configure_input_methods" msgid="9091652157722495116">"Налада метадаў уводу"</string>
+ <string name="adb_active_notification_message" msgid="1016654627626476142">"Націсніце, каб адключыць адладку USB."</string>
+ <string name="select_input_method" msgid="4653387336791222978">"Выберыце метад уводу"</string>
+ <string name="configure_input_methods" msgid="9091652157722495116">"Наладзіць метады ўводу"</string>
<string name="fast_scroll_alphabet" msgid="5433275485499039199">" АБВГДЕЁЖЗІЙКЛМНОПРСТУЎФХЦЧШ\'ЫЬЭЮЯ"</string>
<string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="candidates_style" msgid="4333913089637062257"><u>"кандыдат."</u></string>
@@ -1039,12 +1043,12 @@
<string name="ext_media_checking_notification_message" msgid="8287319882926737053">"Праверка на наяўнасць памылак."</string>
<string name="ext_media_nofs_notification_title" product="nosdcard" msgid="7788040745686229307">"Пусты USB-назапашвальнiк"</string>
<string name="ext_media_nofs_notification_title" product="default" msgid="780477838241212997">"Пустая SD-карта"</string>
- <string name="ext_media_nofs_notification_message" product="nosdcard" msgid="8623130522556087311">"USB-назапашвальнiк пусты або файлавая сістэма не падтрымліваецца."</string>
- <string name="ext_media_nofs_notification_message" product="default" msgid="3817704088027829380">"SD-карта пустая, або файлавая сістэма не падтрымліваецца."</string>
+ <string name="ext_media_nofs_notification_message" product="nosdcard" msgid="7840121067427269500">"USB-назапашвальнік пусты або мае файлавую сістэму, якая не падтрымліваецца."</string>
+ <string name="ext_media_nofs_notification_message" product="default" msgid="8641065641786923604">"SD-карта пустая або мае файлавую сістэму, якая не падтрымліваецца."</string>
<string name="ext_media_unmountable_notification_title" product="nosdcard" msgid="2090046769532713563">"Пашкоджаны USB-назапашвальнiк"</string>
<string name="ext_media_unmountable_notification_title" product="default" msgid="6410723906019100189">"SD-карта пашкоджаная"</string>
- <string name="ext_media_unmountable_notification_message" product="nosdcard" msgid="529021299294450667">"USB-назапашвальнiк пашкоджаны. Магчыма, вам прыйдзецца яго перафарматаваць."</string>
- <string name="ext_media_unmountable_notification_message" product="default" msgid="6902531775948238989">"SD-карта пашкоджаная. Магчыма, вам прыйдзецца перафарматаваць яе."</string>
+ <string name="ext_media_unmountable_notification_message" product="nosdcard" msgid="1795917578395333280">"USB-назапашвальнік пашкоджаны. Паспрабуйце адфарматаваць яго."</string>
+ <string name="ext_media_unmountable_notification_message" product="default" msgid="1753898567525568253">"SD-карта пашкоджана. Паспрабуйце адфарматаваць яе."</string>
<string name="ext_media_badremoval_notification_title" product="nosdcard" msgid="1661683031330951073">"USB-назапашвальнiк нечакана быў выдалены"</string>
<string name="ext_media_badremoval_notification_title" product="default" msgid="6872152882604407837">"SD-карта была нечакана выдалена"</string>
<string name="ext_media_badremoval_notification_message" product="nosdcard" msgid="4329848819865594241">"Адключыце USB-назапашвальнiк, перш чым выцягваць яго, каб пазбегнуць страты дадзеных."</string>
@@ -1057,13 +1061,13 @@
<string name="ext_media_nomedia_notification_title" product="default" msgid="8902518030404381318">"SD-карта выдаленая"</string>
<string name="ext_media_nomedia_notification_message" product="nosdcard" msgid="6921126162580574143">"USB-назапашвальнiк выдалены. Уставіць новыя носьбіты."</string>
<string name="ext_media_nomedia_notification_message" product="default" msgid="3870120652983659641">"SD-карта выдаленая. Устаўце новую."</string>
- <string name="activity_list_empty" msgid="4168820609403385789">"Няма адпаведных дзеянняў"</string>
+ <string name="activity_list_empty" msgid="1675388330786841066">"Адпаведныя дзеянні не знойдзены."</string>
<string name="permlab_pkgUsageStats" msgid="8787352074326748892">"абнавіць статыстыку выкарыстання кампанентаў"</string>
- <!-- outdated translation 891553695716752835 --> <string name="permdesc_pkgUsageStats" msgid="1106612424254277630">"Дазваляе мяняць сабраную статыстыку выкарыстання кампанента. Не выкарыстоўваецца звычайнымі прыкладаннямі."</string>
- <!-- outdated translation 1660908117394854464 --> <string name="permlab_copyProtectedData" msgid="4341036311211406692">"Дазваляе выклікаць службы кантэйнера па змаўчанні для капіявання змесціва. Не выкарыстоўваецца звычайнымi прыкладаннямi."</string>
- <!-- outdated translation 537780957633976401 --> <string name="permdesc_copyProtectedData" msgid="4390697124288317831">"Дазваляе выклікаць службы кантэйнера па змаўчанні для капіявання змесціва. Не выкарыстоўваецца звычайнымi прыкладаннямi."</string>
- <!-- outdated translation 1311810005957319690 --> <string name="tutorial_double_tap_to_zoom_message_short" msgid="4070433208160063538">"Націсніце двойчы, каб кіраваць маштабаваннем"</string>
- <string name="gadget_host_error_inflating" msgid="2613287218853846830">"Памылка ўключэння віджэту"</string>
+ <string name="permdesc_pkgUsageStats" msgid="1106612424254277630">"Дазваляе прыкладанням змяняць сабраную статыстыку выкарыстання кампанентаў. Не для выкарыстання звычайнымі прыкладаннямі."</string>
+ <string name="permlab_copyProtectedData" msgid="4341036311211406692">"капіяваць змесціва"</string>
+ <string name="permdesc_copyProtectedData" msgid="4390697124288317831">"Дазваляе прыкладанням выклікаць службу захавання па змаўчанні для капіявання змесціва. Не выкарыстоўваецца звычайнымі прыкладаннямі."</string>
+ <string name="tutorial_double_tap_to_zoom_message_short" msgid="4070433208160063538">"Двойчы дакраніцеся, каб змянiць маштаб"</string>
+ <string name="gadget_host_error_inflating" msgid="4882004314906466162">"Немагчыма дадаць віджэт."</string>
<string name="ime_action_go" msgid="8320845651737369027">"Пачаць"</string>
<string name="ime_action_search" msgid="658110271822807811">"Пошук"</string>
<string name="ime_action_send" msgid="2316166556349314424">"Адправіць"</string>
@@ -1073,37 +1077,37 @@
<string name="ime_action_default" msgid="2840921885558045721">"Выканаць"</string>
<string name="dial_number_using" msgid="5789176425167573586">"Набраць нумар"\n"з выкарыстаннем <xliff:g id="NUMBER">%s</xliff:g>"</string>
<string name="create_contact_using" msgid="4947405226788104538">"Стварыць кантакт"\n"з дапамогай<xliff:g id="NUMBER">%s</xliff:g>"</string>
- <!-- outdated translation 6824538733852821001 --> <string name="grant_credentials_permission_message_header" msgid="2106103817937859662">"Гэтыя адно або некалькі прыкладанняў пытаюцца дазволу на доступ да вашага ўліковага запісу цяпер і ў будучыні."</string>
+ <string name="grant_credentials_permission_message_header" msgid="2106103817937859662">"Гэтыя адно або некалькі прыкладанняў запытваюць дазвол на доступ да вашага ўліковага запісу цяпер і ў будучыні."</string>
<string name="grant_credentials_permission_message_footer" msgid="3125211343379376561">"Дазволіць гэты запыт?"</string>
- <string name="grant_permissions_header_text" msgid="2722567482180797717">"Запыт на доступ"</string>
+ <string name="grant_permissions_header_text" msgid="6874497408201826708">"Запыт на доступ"</string>
<string name="allow" msgid="7225948811296386551">"Дазволіць"</string>
<string name="deny" msgid="2081879885755434506">"Забараніць"</string>
- <string name="permission_request_notification_title" msgid="5390555465778213840">"Запытаны дазвол"</string>
- <string name="permission_request_notification_with_subtitle" msgid="4325409589686688000">"Запытаны дазвол"\n"для ўліковага запісу<xliff:g id="ACCOUNT">%s</xliff:g>"</string>
+ <string name="permission_request_notification_title" msgid="6486759795926237907">"Дазвол запытаны"</string>
+ <string name="permission_request_notification_with_subtitle" msgid="8530393139639560189">"Запытаны дазвол"\n"для ўліковага запісу <xliff:g id="ACCOUNT">%s</xliff:g>"</string>
<string name="input_method_binding_label" msgid="1283557179944992649">"Метад уводу"</string>
<string name="sync_binding_label" msgid="3687969138375092423">"Сінхранізацыя"</string>
<string name="accessibility_binding_label" msgid="4148120742096474641">"Спецыяльныя магчымасці"</string>
<string name="wallpaper_binding_label" msgid="1240087844304687662">"Шпалеры"</string>
<string name="chooser_wallpaper" msgid="7873476199295190279">"Змена шпалер"</string>
- <string name="vpn_title" msgid="8219003246858087489">"VPN актываваны."</string>
+ <string name="vpn_title" msgid="19615213552042827">"VPN актываваны"</string>
<string name="vpn_title_long" msgid="6400714798049252294">"VPN актывуецца прыкладаннем <xliff:g id="APP">%s</xliff:g>"</string>
- <string name="vpn_text" msgid="1610714069627824309">"Націсніце, каб кіраваць сеткай."</string>
- <string name="vpn_text_long" msgid="4907843483284977618">"Падлучаны да <xliff:g id="SESSION">%s</xliff:g>. Націсніце, каб кiраваць сеткай."</string>
+ <string name="vpn_text" msgid="3011306607126450322">"Дакраніцеся, каб кіраваць сеткай."</string>
+ <string name="vpn_text_long" msgid="6407351006249174473">"Падлучаны да сеанса \"<xliff:g id="SESSION">%s</xliff:g>\". Дакраніцеся, каб кiраваць сеткай."</string>
<string name="upload_file" msgid="2897957172366730416">"Выберыце файл"</string>
<string name="no_file_chosen" msgid="6363648562170759465">"Файл не выбраны"</string>
<string name="reset" msgid="2448168080964209908">"Скінуць"</string>
<string name="submit" msgid="1602335572089911941">"Перадаць"</string>
<string name="car_mode_disable_notification_title" msgid="3164768212003864316">"Рэжым \"У машыне\" ўключаны"</string>
- <string name="car_mode_disable_notification_message" msgid="668663626721675614">"Выберыце, каб выйсці з рэжыму \"Ў аўтамабілі\"."</string>
+ <string name="car_mode_disable_notification_message" msgid="8035230537563503262">"Дакраніцеся, каб выйсці з рэжыму \"Штурман\"."</string>
<string name="tethered_notification_title" msgid="3146694234398202601">"USB-мадэм або кропка доступу Wi-Fi актыўныя"</string>
- <string name="tethered_notification_message" msgid="3067108323903048927">"Націсніце, каб змяніць налады"</string>
+ <string name="tethered_notification_message" msgid="6857031760103062982">"Націсніце, каб наладзіць."</string>
<string name="back_button_label" msgid="2300470004503343439">"Назад"</string>
<string name="next_button_label" msgid="1080555104677992408">"Далей"</string>
<string name="skip_button_label" msgid="1275362299471631819">"Прапусціць"</string>
<string name="throttle_warning_notification_title" msgid="4890894267454867276">"Інтэнсіўнае выкарыстанне перадачы дадзеных праз мабільную сетку"</string>
- <string name="throttle_warning_notification_message" msgid="2609734763845705708">"Націсніце, каб даведацца больш аб выкарыстанні перадачы дадзеных праз мабільную сетку"</string>
+ <string name="throttle_warning_notification_message" msgid="3340822228599337743">"Націсніце, каб атрымаць дадатковыя звесткі аб выкарыстанні мабiльнай перадачы дадзеных."</string>
<string name="throttled_notification_title" msgid="6269541897729781332">"Ліміт мабільнай перадачы дадзеных перавышаны"</string>
- <string name="throttled_notification_message" msgid="4712369856601275146">"Націсніце, каб даведацца больш аб выкарыстанні перадачы дадзеных праз мабільную сетку"</string>
+ <string name="throttled_notification_message" msgid="5443457321354907181">"Націсніце, каб атрымаць дадатковыя звесткі аб выкарыстанні мабiльнай перадачы дадзеных."</string>
<string name="no_matches" msgid="8129421908915840737">"Няма супадзенняў"</string>
<string name="find_on_page" msgid="1946799233822820384">"Знайсці на старонцы"</string>
<plurals name="matches_found">
@@ -1111,10 +1115,10 @@
<item quantity="other" msgid="4641872797067609177">"<xliff:g id="INDEX">%d</xliff:g> з <xliff:g id="TOTAL">%d</xliff:g>"</item>
</plurals>
<string name="action_mode_done" msgid="7217581640461922289">"Гатова"</string>
- <string name="progress_unmounting" product="nosdcard" msgid="535863554318797377">"Адключэнне USB-назапашвальнiка..."</string>
- <string name="progress_unmounting" product="default" msgid="5556813978958789471">"Адключэнне SD-карты..."</string>
- <string name="progress_erasing" product="nosdcard" msgid="4183664626203056915">"Ачышчэнне USB-назапашвальнiка..."</string>
- <string name="progress_erasing" product="default" msgid="2115214724367534095">"Ачышчэнне SD-карты..."</string>
+ <string name="progress_unmounting" product="nosdcard" msgid="3923810448507612746">"Адключэнне USB-назапашвальнiка..."</string>
+ <string name="progress_unmounting" product="default" msgid="1327894998409537190">"Адключэнне SD-карты..."</string>
+ <string name="progress_erasing" product="nosdcard" msgid="4521573321524340058">"Выдаленне дадзеных з USB-назапашвальнiка..."</string>
+ <string name="progress_erasing" product="default" msgid="6596988875507043042">"Выдаленне дадзеных з SD-карты..."</string>
<string name="format_error" product="nosdcard" msgid="6299769563624776948">"Немагчыма ачысцiць USB-назапашвальнік."</string>
<string name="format_error" product="default" msgid="7315248696644510935">"Немагчыма ачысцiць SD-карту."</string>
<string name="media_bad_removal" msgid="7960864061016603281">"SD-карта была вынутая да адключэння"</string>
@@ -1133,17 +1137,17 @@
<string name="gpsVerifYes" msgid="2346566072867213563">"Так"</string>
<string name="gpsVerifNo" msgid="1146564937346454865">"Не"</string>
<string name="sync_too_many_deletes" msgid="5296321850662746890">"Выдаліць перавышаны ліміт"</string>
- <string name="sync_too_many_deletes_desc" msgid="7030265992955132593">"Ёсць выдаленыя элементы (<xliff:g id="NUMBER_OF_DELETED_ITEMS">%1$d</xliff:g>) для тыпу сiнхранiзацыi <xliff:g id="TYPE_OF_SYNC">%2$s</xliff:g>, уліковы запіс <xliff:g id="ACCOUNT_NAME">%3$s</xliff:g>. Што вы хочаце зрабіць?"</string>
- <string name="sync_really_delete" msgid="8933566316059338692">"Выдаліць элементы."</string>
- <string name="sync_undo_deletes" msgid="8610996708225006328">"Скасаваць выдаленне."</string>
- <string name="sync_do_nothing" msgid="8717589462945226869">"Нічога зараз не рабіць."</string>
- <!-- outdated translation 4191313562041125787 --> <string name="choose_account_label" msgid="5655203089746423927">"Выберыце ўліковы запіс"</string>
+ <string name="sync_too_many_deletes_desc" msgid="496551671008694245">"Выдалена элементаў для тыпу сінхранiзацыi \"<xliff:g id="TYPE_OF_SYNC">%2$s</xliff:g>\": <xliff:g id="NUMBER_OF_DELETED_ITEMS">%1$d</xliff:g>. Уліковы запіс <xliff:g id="ACCOUNT_NAME">%3$s</xliff:g>. Што вы жадаеце зрабіць?"</string>
+ <string name="sync_really_delete" msgid="2572600103122596243">"Выдаліць элементы."</string>
+ <string name="sync_undo_deletes" msgid="2941317360600338602">"Скасаваць выдаленні"</string>
+ <string name="sync_do_nothing" msgid="3743764740430821845">"Нічога зараз не рабіць"</string>
+ <string name="choose_account_label" msgid="5655203089746423927">"Выберыце ўліковы запіс"</string>
<string name="add_account_label" msgid="2935267344849993553">"Дадаць уліковы запіс"</string>
- <string name="choose_account_text" msgid="6891230675141555481">"Які ўліковы запіс вы хацелі б выкарыстоўваць?"</string>
+ <string name="choose_account_text" msgid="6303348737197849675">"Які ўліковы запіс вы жадаеце выкарыстоўваць?"</string>
<string name="add_account_button_label" msgid="3611982894853435874">"Дадаць уліковы запіс"</string>
<string name="number_picker_increment_button" msgid="4830170763103463443">"Інкрэмент"</string>
<string name="number_picker_decrement_button" msgid="2576606679160067262">"Дэкрэмент"</string>
- <string name="number_picker_increment_scroll_mode" msgid="1343063395404990189">"Націсніце і ўтрымлівайце кнопку <xliff:g id="VALUE">%s</xliff:g>."</string>
+ <string name="number_picker_increment_scroll_mode" msgid="3073101067441638428">"Націсніце і ўтрымлівайце <xliff:g id="VALUE">%s</xliff:g>."</string>
<string name="number_picker_increment_scroll_action" msgid="4628981789985093179">"Перасуньце палец уверх, каб павялiчыць адрэзак, або ўніз, каб паменшыць."</string>
<string name="time_picker_increment_minute_button" msgid="2843066823236250329">"На хвiлiну больш"</string>
<string name="time_picker_decrement_minute_button" msgid="4357907223628449595">"На хвiлiну менш"</string>
@@ -1172,10 +1176,10 @@
<string name="keyboardview_keycode_mode_change" msgid="4547387741906537519">"Змена рэжыму"</string>
<string name="keyboardview_keycode_shift" msgid="2270748814315147690">"Shift"</string>
<string name="keyboardview_keycode_enter" msgid="2985864015076059467">"Enter"</string>
- <!-- outdated translation 4540794444768613567 --> <string name="activitychooserview_choose_application" msgid="2125168057199941199">"Выберыце прыкладанне"</string>
+ <string name="activitychooserview_choose_application" msgid="2125168057199941199">"Выберыце прыкладанне"</string>
<string name="shareactionprovider_share_with" msgid="806688056141131819">"Апублікаваць з дапамогай"</string>
<string name="shareactionprovider_share_with_application" msgid="5627411384638389738">"Адправiць з дапамогай прыкладання <xliff:g id="APPLICATION_NAME">%s</xliff:g>"</string>
- <!-- outdated translation 7311938669217173870 --> <string name="content_description_sliding_handle" msgid="415975056159262248">"Ручка для перасоўвання. Націсніце і ўтрымлівайце."</string>
+ <string name="content_description_sliding_handle" msgid="415975056159262248">"Ручка для перасоўвання. Націсніце і ўтрымлівайце."</string>
<string name="description_direction_up" msgid="1983114130441878529">"Уверх да <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
<string name="description_direction_down" msgid="4294993639091088240">"Уніз да <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
<string name="description_direction_left" msgid="6814008463839915747">"Улева да <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
@@ -1185,29 +1189,29 @@
<string name="description_target_silent" msgid="893551287746522182">"Ціхі рэжым"</string>
<string name="description_target_soundon" msgid="30052466675500172">"Гук уключаны"</string>
<string name="description_target_unlock_tablet" msgid="3833195335629795055">"Прагартайце, каб разблакаваць."</string>
- <string name="keyboard_headset_required_to_hear_password" msgid="5913502399391940888">"Каб праслухаць паролi, падключыце гарнiтуру."</string>
+ <string name="keyboard_headset_required_to_hear_password" msgid="7011927352267668657">"Каб праслухаць паролi, падключыце гарнiтуру."</string>
<string name="keyboard_password_character_no_headset" msgid="2859873770886153678">"Кропка."</string>
<string name="action_bar_home_description" msgid="5293600496601490216">"Перайсці да пачатковай старонкі"</string>
<string name="action_bar_up_description" msgid="2237496562952152589">"Перайсці ўверх"</string>
<string name="action_menu_overflow_description" msgid="2295659037509008453">"Больш налад"</string>
- <string name="storage_internal" msgid="7556050805474115618">"Унутраная памяць"</string>
- <string name="storage_sd_card" msgid="8921771478629812343">"SD-карта"</string>
+ <string name="storage_internal" msgid="4891916833657929263">"Унутраная памяць"</string>
+ <string name="storage_sd_card" msgid="3282948861378286745">"SD-карта"</string>
<string name="storage_usb" msgid="3017954059538517278">"USB-назапашвальнік"</string>
- <string name="extract_edit_menu_button" msgid="302060189057163906">"Рэдагаваць..."</string>
+ <string name="extract_edit_menu_button" msgid="8940478730496610137">"Рэдагаваць"</string>
<string name="data_usage_warning_title" msgid="1955638862122232342">"Папярэджанне выкарыстання дадзеных"</string>
- <string name="data_usage_warning_body" msgid="7217480745540055170">"Дакраніцеся, каб прагледзець выкарыстанне і налады"</string>
+ <string name="data_usage_warning_body" msgid="2814673551471969954">"Дакраніцеся, каб прагледзець гісторыю выкарыстання і налады."</string>
<string name="data_usage_3g_limit_title" msgid="7093334419518706686">"Перадача дадз. 2G-3G выключана"</string>
<string name="data_usage_4g_limit_title" msgid="7636489436819470761">"Перадача дадзеных 4G выключана"</string>
<string name="data_usage_mobile_limit_title" msgid="7869402519391631884">"Мабільная перадача дадз. выкл."</string>
<string name="data_usage_wifi_limit_title" msgid="8992154736441284865">"Перад. дадз. Wi-Fi адключаная"</string>
- <string name="data_usage_limit_body" msgid="4313857592916426843">"Націсніце, каб уключыць"</string>
+ <string name="data_usage_limit_body" msgid="3317964706973601386">"Націсніце, каб уключыць."</string>
<string name="data_usage_3g_limit_snoozed_title" msgid="7026739121138005231">"Перавышаны ліміт 2G-3G"</string>
<string name="data_usage_4g_limit_snoozed_title" msgid="1106562779311209039">"Перавышаны ліміт дадзеных 4G"</string>
<string name="data_usage_mobile_limit_snoozed_title" msgid="279240572165412168">"Перавышаны ліміт мабільных дадзеных"</string>
<string name="data_usage_wifi_limit_snoozed_title" msgid="8743856006384825974">"Перав. ліміт па дадзеным Wi-Fi"</string>
- <string name="data_usage_limit_snoozed_body" msgid="2932736326652880660">"<xliff:g id="SIZE">%s</xliff:g> звыш устаноўленай мяжы"</string>
+ <string name="data_usage_limit_snoozed_body" msgid="7035490278298441767">"Аб\'ём <xliff:g id="SIZE">%s</xliff:g> перавышае устаноўл. мяжу."</string>
<string name="data_usage_restricted_title" msgid="5965157361036321914">"Зыходныя дадзеныя абмежаваныя"</string>
- <string name="data_usage_restricted_body" msgid="5087354814839059798">"Націсніце, каб зняць абмежаванне"</string>
+ <string name="data_usage_restricted_body" msgid="6741521330997452990">"Націсніце, каб зняць абмежаванне."</string>
<string name="ssl_certificate" msgid="6510040486049237639">"Сертыфікат бяспекі"</string>
<string name="ssl_certificate_is_valid" msgid="6825263250774569373">"Гэты сертыфікат сапраўдны."</string>
<string name="issued_to" msgid="454239480274921032">"Выдадзены:"</string>
@@ -1222,9 +1226,12 @@
<string name="fingerprints" msgid="4516019619850763049">"Адбіткі пальцаў:"</string>
<string name="sha256_fingerprint" msgid="4391271286477279263">"Адбітак пальцаў SHA-256:"</string>
<string name="sha1_fingerprint" msgid="7930330235269404581">"Адбіткі пальцаў SHA-1:"</string>
- <!-- outdated translation 180268188117163072 --> <string name="activity_chooser_view_see_all" msgid="4292569383976636200">"Глядзець усе..."</string>
- <!-- outdated translation 3325054276356556835 --> <string name="activity_chooser_view_dialog_title_default" msgid="4710013864974040615">"Выберыце дзеянне"</string>
- <!-- outdated translation 1791316789651185229 --> <string name="share_action_provider_share_with" msgid="5247684435979149216">"Апублікаваць праз..."</string>
+ <string name="activity_chooser_view_see_all" msgid="4292569383976636200">"Прагледзець усё"</string>
+ <string name="activity_chooser_view_dialog_title_default" msgid="4710013864974040615">"Выберыце працэс"</string>
+ <string name="share_action_provider_share_with" msgid="5247684435979149216">"Апублікаваць з дапамогай"</string>
<string name="status_bar_device_locked" msgid="3092703448690669768">"Прылада заблакаваная."</string>
<string name="list_delimeter" msgid="3975117572185494152">", "</string>
+ <string name="sending" msgid="3245653681008218030">"Адпраўка..."</string>
+ <string name="launchBrowserDefault" msgid="2057951947297614725">"Запусцiць браўзер?"</string>
+ <string name="SetupCallDefault" msgid="5834948469253758575">"Прыняць выклік?"</string>
</resources>
diff --git a/core/res/res/values-bg/strings.xml b/core/res/res/values-bg/strings.xml
index 8cc9ba3..6bec103 100644
--- a/core/res/res/values-bg/strings.xml
+++ b/core/res/res/values-bg/strings.xml
@@ -915,6 +915,7 @@
<string name="force_close" msgid="8346072094521265605">"OK"</string>
<string name="report" msgid="4060218260984795706">"Подаване на сигнал"</string>
<string name="wait" msgid="7147118217226317732">"Изчакване"</string>
+ <string name="webpage_unresponsive" msgid="3272758351138122503">"Страницата не отговаря."\n\n"Искате ли да я затворите?"</string>
<string name="launch_warning_title" msgid="1547997780506713581">"Приложението се пренасочи"</string>
<string name="launch_warning_replace" msgid="6202498949970281412">"<xliff:g id="APP_NAME">%1$s</xliff:g> се изпълнява."</string>
<string name="launch_warning_original" msgid="188102023021668683">"Първоначално бе стартирано: <xliff:g id="APP_NAME">%1$s</xliff:g>."</string>
diff --git a/core/res/res/values-ca/strings.xml b/core/res/res/values-ca/strings.xml
index 4f2aef8..8dced70 100644
--- a/core/res/res/values-ca/strings.xml
+++ b/core/res/res/values-ca/strings.xml
@@ -915,6 +915,7 @@
<string name="force_close" msgid="8346072094521265605">"D\'acord"</string>
<string name="report" msgid="4060218260984795706">"Informe"</string>
<string name="wait" msgid="7147118217226317732">"Espera"</string>
+ <string name="webpage_unresponsive" msgid="3272758351138122503">"La pàgina ha deixat de respondre."\n\n"Vols tancar-la?"</string>
<string name="launch_warning_title" msgid="1547997780506713581">"Aplicació redirigida"</string>
<string name="launch_warning_replace" msgid="6202498949970281412">"<xliff:g id="APP_NAME">%1$s</xliff:g> s\'està executant."</string>
<string name="launch_warning_original" msgid="188102023021668683">"<xliff:g id="APP_NAME">%1$s</xliff:g> es va iniciar originalment."</string>
diff --git a/core/res/res/values-cs/strings.xml b/core/res/res/values-cs/strings.xml
index bfcf23f..e21de4b 100644
--- a/core/res/res/values-cs/strings.xml
+++ b/core/res/res/values-cs/strings.xml
@@ -915,6 +915,7 @@
<string name="force_close" msgid="8346072094521265605">"OK"</string>
<string name="report" msgid="4060218260984795706">"Nahlásit"</string>
<string name="wait" msgid="7147118217226317732">"Počkat"</string>
+ <string name="webpage_unresponsive" msgid="3272758351138122503">"Stránka nereaguje."\n\n"Chcete ji zavřít?"</string>
<string name="launch_warning_title" msgid="1547997780506713581">"Přesměrování aplikace"</string>
<string name="launch_warning_replace" msgid="6202498949970281412">"Je spuštěna aplikace <xliff:g id="APP_NAME">%1$s</xliff:g>."</string>
<string name="launch_warning_original" msgid="188102023021668683">"Původně byla spuštěna aplikace <xliff:g id="APP_NAME">%1$s</xliff:g>."</string>
diff --git a/core/res/res/values-da/strings.xml b/core/res/res/values-da/strings.xml
index 67b24bc..1175cbb 100644
--- a/core/res/res/values-da/strings.xml
+++ b/core/res/res/values-da/strings.xml
@@ -140,7 +140,7 @@
<string name="silent_mode_silent" msgid="319298163018473078">"Ringeren er deaktiveret"</string>
<string name="silent_mode_vibrate" msgid="7072043388581551395">"Ringervibrering"</string>
<string name="silent_mode_ring" msgid="8592241816194074353">"Ringeren er aktiveret"</string>
- <string name="shutdown_progress" msgid="2281079257329981203">"Lukker ned ..."</string>
+ <string name="shutdown_progress" msgid="2281079257329981203">"Lukker ned..."</string>
<string name="shutdown_confirm" product="tablet" msgid="3385745179555731470">"Din tabletcomputer slukkes nu."</string>
<string name="shutdown_confirm" product="default" msgid="649792175242821353">"Din telefon slukkes nu."</string>
<string name="shutdown_confirm_question" msgid="2906544768881136183">"Vil du slukke?"</string>
@@ -881,7 +881,7 @@
<string name="replace" msgid="5781686059063148930">"Erstat..."</string>
<string name="delete" msgid="6098684844021697789">"Slet"</string>
<string name="copyUrl" msgid="2538211579596067402">"Kopier webadresse"</string>
- <string name="selectTextMode" msgid="1018691815143165326">"Marker tekst"</string>
+ <string name="selectTextMode" msgid="1018691815143165326">"Markér tekst"</string>
<string name="textSelectionCABTitle" msgid="5236850394370820357">"Tekstmarkering"</string>
<string name="addToDictionary" msgid="9090375111134433012">"føj til ordbog"</string>
<string name="deleteText" msgid="7070985395199629156">"slet"</string>
@@ -915,6 +915,7 @@
<string name="force_close" msgid="8346072094521265605">"OK"</string>
<string name="report" msgid="4060218260984795706">"Rapporter"</string>
<string name="wait" msgid="7147118217226317732">"Vent"</string>
+ <string name="webpage_unresponsive" msgid="3272758351138122503">"Siden svarer ikke."\n\n"Vil du lukke den?"</string>
<string name="launch_warning_title" msgid="1547997780506713581">"Appen er omdirigeret"</string>
<string name="launch_warning_replace" msgid="6202498949970281412">"<xliff:g id="APP_NAME">%1$s</xliff:g> kører nu."</string>
<string name="launch_warning_original" msgid="188102023021668683">"<xliff:g id="APP_NAME">%1$s</xliff:g> blev oprindeligt åbnet."</string>
diff --git a/core/res/res/values-de/strings.xml b/core/res/res/values-de/strings.xml
index 7c85323..953897c 100644
--- a/core/res/res/values-de/strings.xml
+++ b/core/res/res/values-de/strings.xml
@@ -684,7 +684,7 @@
<string name="lockscreen_network_locked_message" msgid="143389224986028501">"Netzwerk gesperrt"</string>
<string name="lockscreen_sim_puk_locked_message" msgid="7441797339976230">"PUK-Sperre auf SIM"</string>
<string name="lockscreen_sim_puk_locked_instructions" msgid="8127916255245181063">"Weitere Informationen erhalten Sie im Nutzerhandbuch oder beim Kundendienst."</string>
- <string name="lockscreen_sim_locked_message" msgid="8066660129206001039">"Bitte PIN eingeben"</string>
+ <string name="lockscreen_sim_locked_message" msgid="8066660129206001039">"PIN eingeben"</string>
<string name="lockscreen_sim_unlock_progress_dialog_message" msgid="595323214052881264">"SIM-Karte wird entsperrt..."</string>
<string name="lockscreen_too_many_failed_attempts_dialog_message" msgid="6481623830344107222">"Sie haben Ihr Entsperrungsmuster <xliff:g id="NUMBER_0">%d</xliff:g>-mal falsch gezeichnet. "\n\n"Bitte versuchen Sie es in <xliff:g id="NUMBER_1">%d</xliff:g> Sekunden noch einmal."</string>
<string name="lockscreen_too_many_failed_password_attempts_dialog_message" msgid="2725973286239344555">"Sie haben Ihr Passwort <xliff:g id="NUMBER_0">%d</xliff:g>-mal falsch eingegeben."\n\n"Bitte versuchen Sie es in <xliff:g id="NUMBER_1">%d</xliff:g> Sekunden noch einmal."</string>
@@ -915,6 +915,7 @@
<string name="force_close" msgid="8346072094521265605">"OK"</string>
<string name="report" msgid="4060218260984795706">"Bericht"</string>
<string name="wait" msgid="7147118217226317732">"Warten"</string>
+ <string name="webpage_unresponsive" msgid="3272758351138122503">"Die Seite reagiert nicht mehr."\n\n"Möchten Sie die Seite schließen?"</string>
<string name="launch_warning_title" msgid="1547997780506713581">"App umgeleitet"</string>
<string name="launch_warning_replace" msgid="6202498949970281412">"<xliff:g id="APP_NAME">%1$s</xliff:g> wird jetzt ausgeführt."</string>
<string name="launch_warning_original" msgid="188102023021668683">"<xliff:g id="APP_NAME">%1$s</xliff:g> wurde ursprünglich gestartet."</string>
diff --git a/core/res/res/values-el/strings.xml b/core/res/res/values-el/strings.xml
index aa07f3b..458517c 100644
--- a/core/res/res/values-el/strings.xml
+++ b/core/res/res/values-el/strings.xml
@@ -915,6 +915,7 @@
<string name="force_close" msgid="8346072094521265605">"ΟΚ"</string>
<string name="report" msgid="4060218260984795706">"Αναφορά"</string>
<string name="wait" msgid="7147118217226317732">"Αναμονή"</string>
+ <string name="webpage_unresponsive" msgid="3272758351138122503">"Η σελίδα δεν ανταποκρίνεται πια."\n\n"Θέλετε να την κλείσετε;"</string>
<string name="launch_warning_title" msgid="1547997780506713581">"Ανακατεύθυνση εφαρμογής"</string>
<string name="launch_warning_replace" msgid="6202498949970281412">"Η εφαρμογή <xliff:g id="APP_NAME">%1$s</xliff:g> εκτελείται τώρα."</string>
<string name="launch_warning_original" msgid="188102023021668683">"Έγινε εκκίνηση πρώτα της εφαρμογής <xliff:g id="APP_NAME">%1$s</xliff:g>."</string>
diff --git a/core/res/res/values-en-rGB/strings.xml b/core/res/res/values-en-rGB/strings.xml
index c1f1b40..d48f544 100644
--- a/core/res/res/values-en-rGB/strings.xml
+++ b/core/res/res/values-en-rGB/strings.xml
@@ -915,6 +915,7 @@
<string name="force_close" msgid="8346072094521265605">"OK"</string>
<string name="report" msgid="4060218260984795706">"Report"</string>
<string name="wait" msgid="7147118217226317732">"Wait"</string>
+ <string name="webpage_unresponsive" msgid="3272758351138122503">"The page has become unresponsive."\n\n"Do you want to close it?"</string>
<string name="launch_warning_title" msgid="1547997780506713581">"App redirected"</string>
<string name="launch_warning_replace" msgid="6202498949970281412">"<xliff:g id="APP_NAME">%1$s</xliff:g> is now running."</string>
<string name="launch_warning_original" msgid="188102023021668683">"<xliff:g id="APP_NAME">%1$s</xliff:g> was originally launched."</string>
diff --git a/core/res/res/values-es-rUS/strings.xml b/core/res/res/values-es-rUS/strings.xml
index c7f86d0..c66dc8e 100644
--- a/core/res/res/values-es-rUS/strings.xml
+++ b/core/res/res/values-es-rUS/strings.xml
@@ -86,8 +86,8 @@
<string name="serviceClassDataSync" msgid="7530000519646054776">"Sincronización"</string>
<string name="serviceClassPacket" msgid="6991006557993423453">"Paquete"</string>
<string name="serviceClassPAD" msgid="3235259085648271037">"PAD"</string>
- <string name="roamingText0" msgid="7170335472198694945">"Indicador de roaming encendido"</string>
- <string name="roamingText1" msgid="5314861519752538922">"Indicador de roaming apagado"</string>
+ <string name="roamingText0" msgid="7170335472198694945">"Indicador de roaming activado"</string>
+ <string name="roamingText1" msgid="5314861519752538922">"Indicador de roaming desactivado"</string>
<string name="roamingText2" msgid="8969929049081268115">"Indicador de roaming titilando"</string>
<string name="roamingText3" msgid="5148255027043943317">"Fuera del vecindario"</string>
<string name="roamingText4" msgid="8808456682550796530">"Fuera de construcción"</string>
@@ -97,8 +97,8 @@
<string name="roamingText8" msgid="5989569778604089291">"Roaming: socio premium"</string>
<string name="roamingText9" msgid="7969296811355152491">"Roaming: funcionalidad de servicio completa"</string>
<string name="roamingText10" msgid="3992906999815316417">"Roaming: funcionalidad de servicio parcial"</string>
- <string name="roamingText11" msgid="4154476854426920970">"Banner de roaming encendido"</string>
- <string name="roamingText12" msgid="1189071119992726320">"Banner de roaming apagado"</string>
+ <string name="roamingText11" msgid="4154476854426920970">"Banner de roaming activado"</string>
+ <string name="roamingText12" msgid="1189071119992726320">"Banner de roaming desactivado"</string>
<string name="roamingTextSearching" msgid="8360141885972279963">"Buscando servicio"</string>
<string name="cfTemplateNotForwarded" msgid="1683685883841272560">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: no se ha remitido"</string>
<string name="cfTemplateForwarded" msgid="1302922117498590521">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g>"</string>
@@ -128,13 +128,13 @@
<string name="contentServiceSyncNotificationTitle" msgid="397743349191901458">"Sincronización"</string>
<string name="contentServiceTooManyDeletesNotificationDesc" msgid="8100981435080696431">"Demasiadas eliminaciones de <xliff:g id="CONTENT_TYPE">%s</xliff:g>"</string>
<string name="low_memory" product="tablet" msgid="6494019234102154896">"Se ha agotado el espacio de almacenamiento de la tableta. Elimina algunos archivos para liberar espacio."</string>
- <string name="low_memory" product="default" msgid="3475999286680000541">"Se ha agotado el espacio de almacenamiento del teléfono. Elimina algunos archivos para liberar espacio."</string>
+ <string name="low_memory" product="default" msgid="3475999286680000541">"Se ha agotado el espacio de almacenamiento del dispositivo. Elimina algunos archivos para liberar espacio."</string>
<string name="me" msgid="6545696007631404292">"Yo"</string>
<string name="power_dialog" product="tablet" msgid="8545351420865202853">"Opciones de tablet"</string>
- <string name="power_dialog" product="default" msgid="1319919075463988638">"Opciones de teléfono"</string>
+ <string name="power_dialog" product="default" msgid="1319919075463988638">"Opciones de dispositivo"</string>
<string name="silent_mode" msgid="7167703389802618663">"Modo silencioso"</string>
- <string name="turn_on_radio" msgid="3912793092339962371">"Encender el teléfono inalámbrico"</string>
- <string name="turn_off_radio" msgid="8198784949987062346">"Apagar el teléfono inalámbrico"</string>
+ <string name="turn_on_radio" msgid="3912793092339962371">"Activar conexión inalámbrica"</string>
+ <string name="turn_off_radio" msgid="8198784949987062346">"Desactivar conexión inalámbrica"</string>
<string name="screen_lock" msgid="799094655496098153">"Bloqueo de pantalla"</string>
<string name="power_off" msgid="4266614107412865048">"Apagar"</string>
<string name="silent_mode_silent" msgid="319298163018473078">"Timbre desactivado"</string>
@@ -142,30 +142,30 @@
<string name="silent_mode_ring" msgid="8592241816194074353">"Timbre activado"</string>
<string name="shutdown_progress" msgid="2281079257329981203">"Apagando…"</string>
<string name="shutdown_confirm" product="tablet" msgid="3385745179555731470">"Tu tablet se apagará."</string>
- <string name="shutdown_confirm" product="default" msgid="649792175242821353">"Tu teléfono se apagará."</string>
+ <string name="shutdown_confirm" product="default" msgid="649792175242821353">"Tu dispositivo se apagará."</string>
<string name="shutdown_confirm_question" msgid="2906544768881136183">"¿Deseas apagarlo?"</string>
<string name="recent_tasks_title" msgid="3691764623638127888">"Reciente"</string>
<string name="no_recent_tasks" msgid="8794906658732193473">"No hay aplicaciones recientes."</string>
<string name="global_actions" product="tablet" msgid="408477140088053665">"Opciones de tablet"</string>
- <string name="global_actions" product="default" msgid="2406416831541615258">"Opciones de teléfono"</string>
+ <string name="global_actions" product="default" msgid="2406416831541615258">"Opciones de dispositivo"</string>
<string name="global_action_lock" msgid="2844945191792119712">"Bloqueo de pantalla"</string>
<string name="global_action_power_off" msgid="4471879440839879722">"Apagar"</string>
<string name="global_action_toggle_silent_mode" msgid="8219525344246810925">"Modo silencioso"</string>
- <string name="global_action_silent_mode_on_status" msgid="3289841937003758806">"El sonido está Apagado"</string>
- <string name="global_action_silent_mode_off_status" msgid="1506046579177066419">"El sonido está Encendido"</string>
+ <string name="global_action_silent_mode_on_status" msgid="3289841937003758806">"El sonido está Desactivado"</string>
+ <string name="global_action_silent_mode_off_status" msgid="1506046579177066419">"El sonido está Activado"</string>
<string name="global_actions_toggle_airplane_mode" msgid="5884330306926307456">"Modo avión"</string>
- <string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"El modo avión está Encendido"</string>
- <string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"El modo avión está Apagado"</string>
+ <string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"El modo avión está Activado"</string>
+ <string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"El modo avión está Desactivado"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
<string name="safeMode" msgid="2788228061547930246">"Modo seguro"</string>
<string name="android_system_label" msgid="6577375335728551336">"Sistema Android"</string>
<string name="permgrouplab_costMoney" msgid="5429808217861460401">"Servicios que te cuestan dinero"</string>
<string name="permgroupdesc_costMoney" msgid="3293301903409869495">"Permite que las aplicaciones realicen actividades con cargo."</string>
<string name="permgrouplab_messages" msgid="7521249148445456662">"Tus mensajes"</string>
- <string name="permgroupdesc_messages" msgid="7821999071003699236">"Lee y escribe tus SMS, mensajes de correo electrónico y otros mensajes."</string>
+ <string name="permgroupdesc_messages" msgid="7821999071003699236">"Lee y escribe tus SMS, mensajes de correo y otros mensajes."</string>
<string name="permgrouplab_personalInfo" msgid="3519163141070533474">"Tu información personal"</string>
- <string name="permgroupdesc_personalInfo" product="tablet" msgid="6975389054186265786">"Acceso directo a los contactos y calendario guardados en tu teléfono."</string>
- <string name="permgroupdesc_personalInfo" product="default" msgid="5488050357388806068">"Acceso directo a tus contactos y calendario guardado en el teléfono."</string>
+ <string name="permgroupdesc_personalInfo" product="tablet" msgid="6975389054186265786">"Acceso directo a los contactos y calendario guardados en tu dispositivo."</string>
+ <string name="permgroupdesc_personalInfo" product="default" msgid="5488050357388806068">"Acceso directo a tus contactos y calendario guardado en el dispositivo."</string>
<string name="permgrouplab_location" msgid="635149742436692049">"Tu ubicación"</string>
<string name="permgroupdesc_location" msgid="5704679763124170100">"Controlar tu ubicación física"</string>
<string name="permgrouplab_network" msgid="5808983377727109831">"Comunicación de red"</string>
@@ -173,7 +173,7 @@
<string name="permgrouplab_accounts" msgid="3359646291125325519">"Tus cuentas"</string>
<string name="permgroupdesc_accounts" msgid="4948732641827091312">"Acceder a las cuentas disponibles."</string>
<string name="permgrouplab_hardwareControls" msgid="7998214968791599326">"Controles de hardware"</string>
- <string name="permgroupdesc_hardwareControls" msgid="4357057861225462702">"Acceso directo al hardware en el teléfono."</string>
+ <string name="permgroupdesc_hardwareControls" msgid="4357057861225462702">"Acceso directo al hardware en el dispositivo."</string>
<string name="permgrouplab_phoneCalls" msgid="9067173988325865923">"Llamadas telefónicas"</string>
<string name="permgroupdesc_phoneCalls" msgid="7489701620446183770">"Controlar, grabar y procesar llamadas telefónicas."</string>
<string name="permgrouplab_systemTools" msgid="4652191644082714048">"Herramientas del sistema"</string>
@@ -203,10 +203,10 @@
<string name="permdesc_sendSmsNoConfirmation" msgid="3437759207020400204">"Permite que la aplicación envíe mensajes SMS. Las aplicaciones maliciosas pueden generar gastos a causa del envío de mensajes sin tu confirmación."</string>
<string name="permlab_readSms" msgid="4085333708122372256">"leer SMS o MMS"</string>
<string name="permdesc_readSms" product="tablet" msgid="2341692916884515613">"Permite que la aplicación lea mensajes SMS almacenados en tu tableta o tarjeta SIM. Las aplicaciones maliciosas pueden leer tus mensajes confidenciales."</string>
- <string name="permdesc_readSms" product="default" msgid="5653850482025875493">"Permite que la aplicación lea mensajes SMS almacenados en tu teléfono o tarjeta SIM. Las aplicaciones maliciosas pueden leer tus mensajes confidenciales."</string>
+ <string name="permdesc_readSms" product="default" msgid="5653850482025875493">"Permite que la aplicación lea mensajes SMS almacenados en tu dispositivo o tarjeta SIM. Las aplicaciones maliciosas pueden leer tus mensajes confidenciales."</string>
<string name="permlab_writeSms" msgid="6881122575154940744">"editar SMS o MMS"</string>
<string name="permdesc_writeSms" product="tablet" msgid="5160413947794501538">"Permite que la aplicación escriba en mensajes SMS almacenados en tu tableta o tarjeta SIM. Las aplicaciones maliciosas pueden eliminar tus mensajes."</string>
- <string name="permdesc_writeSms" product="default" msgid="7268668709052328567">"Permite que la aplicación escriba en mensajes SMS almacenados en tu teléfono o tarjeta SIM. Las aplicaciones maliciosas pueden eliminar tus mensajes."</string>
+ <string name="permdesc_writeSms" product="default" msgid="7268668709052328567">"Permite que la aplicación escriba en mensajes SMS almacenados en tu dispositivo o tarjeta SIM. Las aplicaciones maliciosas pueden eliminar tus mensajes."</string>
<string name="permlab_receiveWapPush" msgid="8258226427716551388">"recibir WAP"</string>
<string name="permdesc_receiveWapPush" msgid="7983455145335316872">"Permite que la aplicación reciba y procese mensajes WAP. Las aplicaciones maliciosas pueden controlar tus mensajes o eliminarlos sin mostrártelos."</string>
<string name="permlab_getTasks" msgid="6466095396623933906">"recuperar aplicaciones en ejecución"</string>
@@ -215,11 +215,11 @@
<string name="permdesc_reorderTasks" msgid="4175137612205663399">"Permite que la aplicación mueva tareas al primero o segundo plano. Las aplicaciones maliciosas pueden forzar su paso al primer plano sin que tú las controles."</string>
<string name="permlab_removeTasks" msgid="6821513401870377403">"detener las aplicaciones en ejecución"</string>
<string name="permdesc_removeTasks" msgid="1394714352062635493">"Permite que la aplicación elimine tareas y cierre sus aplicaciones. Las aplicaciones malintencionadas pueden usar este permiso para interferir en el comportamiento de otras aplicaciones."</string>
- <string name="permlab_setDebugApp" msgid="3022107198686584052">"habilitar depuración de aplicación"</string>
+ <string name="permlab_setDebugApp" msgid="3022107198686584052">"activar depuración de aplicación"</string>
<string name="permdesc_setDebugApp" msgid="4474512416299013256">"Permite que la aplicación active la depuración de otra aplicación. Las aplicaciones malintencionadas pueden usar este permiso para interrumpir la ejecución de otras aplicaciones."</string>
<string name="permlab_changeConfiguration" msgid="8214475779521218295">"cambiar tu configuración de la interfaz de usuario"</string>
<string name="permdesc_changeConfiguration" msgid="4372223873154296076">"Permite que la aplicación cambie la configuración actual como, por ejemplo, la configuración regional o el tamaño de fuente general."</string>
- <string name="permlab_enableCarMode" msgid="5684504058192921098">"habilitar el modo de auto"</string>
+ <string name="permlab_enableCarMode" msgid="5684504058192921098">"activar el modo de auto"</string>
<string name="permdesc_enableCarMode" msgid="4853187425751419467">"Permite que la aplicación habilite el modo coche."</string>
<string name="permlab_killBackgroundProcesses" msgid="8373714752793061963">"eliminar los procesos de fondo"</string>
<string name="permdesc_killBackgroundProcesses" msgid="931129103262126617">"Permite que la aplicación elimine procesos de otras aplicaciones que se ejecutan en segundo plano, aunque haya suficiente memoria."</string>
@@ -263,7 +263,7 @@
<string name="permdesc_manageAppTokens" msgid="8043431713014395671">"Permite que la aplicación cree y administre sus propios tokens al ignorar su orden z normal. Las aplicaciones normales no deben utilizar este permiso."</string>
<string name="permlab_injectEvents" msgid="1378746584023586600">"presionar teclas y botones de control"</string>
<string name="permdesc_injectEvents" product="tablet" msgid="206352565599968632">"Permite que la aplicación ofrezca sus propios eventos de entrada (pulsaciones de teclas, etc.) a otras aplicaciones. Las aplicaciones maliciosas pueden utilizar este permiso para controlar la tableta."</string>
- <string name="permdesc_injectEvents" product="default" msgid="653128057572326253">"Permite que la aplicación ofrezca sus propios eventos de entrada (pulsaciones de teclas, etc.) a otras aplicaciones. Las aplicaciones maliciosas pueden utilizar este permiso para controlar el teléfono."</string>
+ <string name="permdesc_injectEvents" product="default" msgid="653128057572326253">"Permite que la aplicación ofrezca sus propios eventos de entrada (pulsaciones de teclas, etc.) a otras aplicaciones. Las aplicaciones maliciosas pueden utilizar este permiso para controlar el dispositivo."</string>
<string name="permlab_readInputState" msgid="469428900041249234">"grabar tu tipo y las medidas que tomes"</string>
<string name="permdesc_readInputState" msgid="8387754901688728043">"Permite que la aplicación observe las teclas que presionas, incluso al interactuar con otra aplicación (como cuando escribes una contraseña). Las aplicaciones normales no deberían necesitar este permiso."</string>
<string name="permlab_bindInputMethod" msgid="3360064620230515776">"vincular a un método de entrada"</string>
@@ -298,19 +298,19 @@
<string name="permdesc_installPackages" msgid="5628530972548071284">"Permite que la aplicación instale paquetes de Android nuevos o actualizados. Las aplicaciones maliciosas pueden utilizar este permiso para agregar nuevas aplicaciones con permisos arbitrarios potentes."</string>
<string name="permlab_clearAppCache" msgid="7487279391723526815">"eliminar todos los datos de caché de la aplicación"</string>
<string name="permdesc_clearAppCache" product="tablet" msgid="3523396284474042284">"Permite que la aplicación libere almacenamiento en la tableta al eliminar archivos en el directorio caché de la aplicación. El acceso al proceso del sistema suele ser muy restringido."</string>
- <string name="permdesc_clearAppCache" product="default" msgid="5067988373366292186">"Permite que la aplicación libere espacio de almacenamiento en el teléfono al eliminar archivos en el directorio caché de la aplicación. El acceso al proceso del sistema suele ser muy restringido."</string>
+ <string name="permdesc_clearAppCache" product="default" msgid="5067988373366292186">"Permite que la aplicación libere espacio de almacenamiento en el dispositivo al eliminar archivos en el directorio caché de la aplicación. El acceso al proceso del sistema suele ser muy restringido."</string>
<string name="permlab_movePackage" msgid="3289890271645921411">"mover recursos de la aplicación"</string>
<string name="permdesc_movePackage" msgid="319562217778244524">"Permite que la aplicación traslade recursos de la aplicación de medios internos a medios externos y viceversa."</string>
<string name="permlab_readLogs" msgid="6615778543198967614">"lee los datos confidenciales del registro"</string>
<string name="permdesc_readLogs" product="tablet" msgid="82061313293455151">"Permite que la aplicación lea diversos archivos de registro del sistema. Esto le permite descubrir información general acerca de lo que haces con la tableta, lo que podría incluir información personal o privada."</string>
- <string name="permdesc_readLogs" product="default" msgid="2063438140241560443">"Permite que la aplicación lea los diversos archivos de registro del sistema. Esto le permite descubrir información general acerca de lo que haces con el teléfono, que puede incluir información personal o privada."</string>
+ <string name="permdesc_readLogs" product="default" msgid="2063438140241560443">"Permite que la aplicación lea los diversos archivos de registro del sistema. Esto le permite descubrir información general acerca de lo que haces con el dispositivo, que puede incluir información personal o privada."</string>
<string name="permlab_anyCodecForPlayback" msgid="715805555823881818">"Usar cualquier decodificador de medios para la reproducción"</string>
<string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"Permite que la aplicación use cualquier decodificador de archivos multimedia instalado para la reproducción."</string>
<string name="permlab_diagnostic" msgid="8076743953908000342">"leer y escribir a recursos dentro del grupo de diagnóstico"</string>
<string name="permdesc_diagnostic" msgid="6608295692002452283">"Permite que la aplicación lea y escriba en cualquier recurso propiedad del grupo de diagnóstico como, por ejemplo, archivos in/dev. Este permiso podría afectar la seguridad y estabilidad del sistema. SOLO se debe utilizar para diagnósticos específicos de hardware realizados por el fabricante o el operador."</string>
<string name="permlab_changeComponentState" msgid="6335576775711095931">"activar o desactivar componentes de la aplicación"</string>
- <string name="permdesc_changeComponentState" product="tablet" msgid="8887435740982237294">"Permite que la aplicación determine si un componente de otra aplicación está habilitado o no. Las aplicaciones maliciosas pueden utilizar este permiso para inhabilitar funciones importantes de la tableta. Es necesario ser precavido con este permiso, ya que es posible que los componentes de la aplicación queden inservibles, incoherentes o inestables."</string>
- <string name="permdesc_changeComponentState" product="default" msgid="1827232484416505615">"Permite que la aplicación determine si un componente de otra aplicación está habilitado o no. Las aplicaciones maliciosas pueden utilizar este permiso para inhabilitar funciones importantes del teléfono. Es necesario ser precavido con este permiso, ya que es posible que los componentes de la aplicación queden inservibles, incoherentes o inestables."</string>
+ <string name="permdesc_changeComponentState" product="tablet" msgid="8887435740982237294">"Permite que la aplicación determine si un componente de otra aplicación está habilitado o no. Las aplicaciones maliciosas pueden utilizar este permiso para desactivar funciones importantes de la tableta. Es necesario ser precavido con este permiso, ya que es posible que los componentes de la aplicación queden inservibles, incoherentes o inestables."</string>
+ <string name="permdesc_changeComponentState" product="default" msgid="1827232484416505615">"Permite que la aplicación determine si un componente de otra aplicación está habilitado o no. Las aplicaciones maliciosas pueden utilizar este permiso para desactivar funciones importantes del dispositivo. Es necesario ser precavido con este permiso, ya que es posible que los componentes de la aplicación queden inservibles, incoherentes o inestables."</string>
<string name="permlab_setPreferredApplications" msgid="8463181628695396391">"establecer aplicaciones preferidas"</string>
<string name="permdesc_setPreferredApplications" msgid="4973986762241783712">"Permite que la aplicación modifique tus aplicaciones preferidas. Las aplicaciones maliciosas pueden modificar sin aviso las aplicaciones que se ejecutan y así engañar a tus aplicaciones existentes para que recopilen tu información privada."</string>
<string name="permlab_writeSettings" msgid="1365523497395143704">"modificar la configuración global del sistema"</string>
@@ -321,16 +321,16 @@
<string name="permdesc_writeGservices" msgid="1287309437638380229">"Permite que la aplicación modifique el mapa de servicios de Google. Las aplicaciones normales no deben utilizar este permiso."</string>
<string name="permlab_receiveBootCompleted" msgid="7776779842866993377">"ejecutar automáticamente al iniciar"</string>
<string name="permdesc_receiveBootCompleted" product="tablet" msgid="7390304664116880704">"Permite que la aplicación se inicie en cuanto el sistema haya finalizado la inicialización. Esto puede ocasionar que la tableta tarde más en inicializarse y que la aplicación ralentice el funcionamiento general de la tableta al estar en ejecución constante."</string>
- <string name="permdesc_receiveBootCompleted" product="default" msgid="513950589102617504">"Permite que la aplicación se inicie en cuanto el sistema haya finalizado la inicialización. Esto puede ocasionar que el teléfono tarde más en inicializarse y que la aplicación ralentice el funcionamiento general del teléfono al estar en ejecución constante."</string>
+ <string name="permdesc_receiveBootCompleted" product="default" msgid="513950589102617504">"Permite que la aplicación se inicie en cuanto el sistema haya finalizado la inicialización. Esto puede ocasionar que el dispositivo tarde más en inicializarse y que la aplicación ralentice el funcionamiento general del dispositivo al estar en ejecución constante."</string>
<string name="permlab_broadcastSticky" msgid="7919126372606881614">"enviar emisiones pegajosas"</string>
<string name="permdesc_broadcastSticky" product="tablet" msgid="1181582512022829259">"Permite que la aplicación envíe transmisiones persistentes que permanecen luego de que finaliza la transmisión. Las aplicaciones maliciosas pueden hacer que la tableta funcione más lentamente o de manera inestable al forzarla a utilizar mucha memoria."</string>
- <string name="permdesc_broadcastSticky" product="default" msgid="3287869131621514325">"Permite que la aplicación envíe transmisiones persistentes que permanecen luego de que finaliza la transmisión. Las aplicaciones maliciosas pueden hacer que el teléfono funcione más lento o de manera inestable al forzarlo a utilizar mucha memoria."</string>
+ <string name="permdesc_broadcastSticky" product="default" msgid="3287869131621514325">"Permite que la aplicación envíe transmisiones persistentes que permanecen luego de que finaliza la transmisión. Las aplicaciones maliciosas pueden hacer que el dispositivo funcione más lento o de manera inestable al forzarlo a utilizar mucha memoria."</string>
<string name="permlab_readContacts" msgid="6219652189510218240">"leer datos de contacto"</string>
<string name="permdesc_readContacts" product="tablet" msgid="4028657556924039119">"Permite que la aplicación lea todos los datos de contacto (direcciones) almacenados en tu tableta. Las aplicaciones maliciosas pueden usar este permiso para enviar tus datos a otras personas."</string>
- <string name="permdesc_readContacts" product="default" msgid="2032222056456498547">"Permite que la aplicación lea todos los datos de contacto (direcciones) almacenados en tu teléfono. Las aplicaciones maliciosas pueden utilizar este permiso para enviar tus datos a otro teléfono."</string>
+ <string name="permdesc_readContacts" product="default" msgid="2032222056456498547">"Permite que la aplicación lea todos los datos de contacto (direcciones) almacenados en tu dispositivo. Las aplicaciones maliciosas pueden utilizar este permiso para enviar tus datos a otro dispositivo."</string>
<string name="permlab_writeContacts" msgid="644616215860933284">"escribir datos de contacto"</string>
<string name="permdesc_writeContacts" product="tablet" msgid="988969759110632978">"Permite que la aplicación modifique la información de contacto (dirección) almacenada en tu tableta. Las aplicaciones maliciosas pueden utilizar este permiso para borrar o modificar tu información de contacto."</string>
- <string name="permdesc_writeContacts" product="default" msgid="5075164818647934067">"Permite que la aplicación modifique la información de contacto (dirección) almacenada en tu teléfono. Las aplicaciones maliciosas pueden utilizar este permiso para borrar o modificar tu información de contacto."</string>
+ <string name="permdesc_writeContacts" product="default" msgid="5075164818647934067">"Permite que la aplicación modifique la información de contacto (dirección) almacenada en tu dispositivo. Las aplicaciones maliciosas pueden utilizar este permiso para borrar o modificar tu información de contacto."</string>
<string name="permlab_readProfile" msgid="6824681438529842282">"Leer tus datos de perfil"</string>
<string name="permdesc_readProfile" product="default" msgid="94520753797630679">"Permite que la aplicación lea la información de perfil almacenada en tu dispositivo, como tu nombre e información de contacto. Esto significa que la aplicación puede identificarte y enviar tu información de perfil a otros."</string>
<string name="permlab_writeProfile" msgid="4679878325177177400">"Escrib. en datos de tu perfil"</string>
@@ -341,8 +341,8 @@
<string name="permdesc_writeSocialStream" product="default" msgid="3496277176955721451">"Permite que la aplicación muestre las actualizaciones sociales de tus amigos. Las aplicaciones maliciosas pueden usar este permiso para hacerse pasar por un amigo y engañarte para que reveles contraseñas u otros datos confidenciales."</string>
<string name="permlab_readCalendar" msgid="5972727560257612398">"Leer eventos de calendario e información confidencial"</string>
<string name="permdesc_readCalendar" product="tablet" msgid="2338414551004122687">"Permite que la aplicación lea todos los eventos del calendario almacenados en tu tableta, incluidos los de amigos o compañeros de trabajo. Las aplicaciones maliciosas pueden extraer información personal de esos calendarios sin que los propietarios lo sepan."</string>
- <string name="permdesc_readCalendar" product="default" msgid="5693933067751827753">"Permite que la aplicación lea todos los eventos del calendario almacenados en tu teléfono, incluidos los de amigos o compañeros de trabajo. Las aplicaciones maliciosas pueden extraer información personal de esos calendarios sin que los propietarios lo sepan."</string>
- <string name="permlab_writeCalendar" msgid="8438874755193825647">"Agregar o modificar los eventos de calendario y enviar un correo electrónico a los invitados sin que los propietarios lo sepan"</string>
+ <string name="permdesc_readCalendar" product="default" msgid="5693933067751827753">"Permite que la aplicación lea todos los eventos del calendario almacenados en tu dispositivo, incluidos los de amigos o compañeros de trabajo. Las aplicaciones maliciosas pueden extraer información personal de esos calendarios sin que los propietarios lo sepan."</string>
+ <string name="permlab_writeCalendar" msgid="8438874755193825647">"Agregar o modificar los eventos de calendario y enviar un correo a los invitados sin que los propietarios lo sepan"</string>
<string name="permdesc_writeCalendar" msgid="2243771395254848873">"Permite que la aplicación envíe invitaciones a eventos como propietario del calendario, y que agregue, elimine y cambie eventos que puedes modificar en tu dispositivo, incluidos los de tus amigos o compañeros de trabajo. Las aplicaciones maliciosas pueden enviar correos electrónicos de spam que aparenten provenir de propietarios de calendarios, modificar eventos sin que el propietario lo sepa o agregar eventos falsos."</string>
<string name="permlab_accessMockLocation" msgid="8688334974036823330">"crear fuentes de ubicación de prueba"</string>
<string name="permdesc_accessMockLocation" msgid="7577931556422993949">"Permite que la aplicación cree fuentes de ubicación simuladas para pruebas. Las aplicaciones maliciosas pueden utilizar este permiso para anular la ubicación o el estado que devuelven las fuentes de ubicación actuales, como los proveedores de GPS o redes."</string>
@@ -352,10 +352,10 @@
<string name="permdesc_installLocationProvider" msgid="1742577679350078373">"Crear fuentes de ubicación simuladas para pruebas. Las aplicaciones maliciosas pueden utilizar esta opción para anular la ubicación o el estado que devuelven las fuentes de ubicación reales, como los proveedores de GPS o redes, o para monitorear e informar tu ubicación a una fuente externa."</string>
<string name="permlab_accessFineLocation" msgid="8116127007541369477">"ubicación precisa (GPS)"</string>
<string name="permdesc_accessFineLocation" product="tablet" msgid="5326423948268164934">"Permite acceder a las fuentes de ubicación precisas, como el sistema de posicionamiento global en la tableta, si está disponible. Las aplicaciones maliciosas pueden utilizar este permiso para determinar dónde te encuentras y pueden consumir batería adicional."</string>
- <string name="permdesc_accessFineLocation" product="default" msgid="7130267914433890869">"Permite acceder a las fuentes de ubicación precisa, como el sistema de posicionamiento global del teléfono, si está disponible. Las aplicaciones maliciosas pueden utilizar este permiso para determinar dónde te encuentras y pueden consumir batería adicional."</string>
+ <string name="permdesc_accessFineLocation" product="default" msgid="7130267914433890869">"Permite acceder a las fuentes de ubicación precisa, como el sistema de posicionamiento global del dispositivo, si está disponible. Las aplicaciones maliciosas pueden utilizar este permiso para determinar dónde te encuentras y pueden consumir batería adicional."</string>
<string name="permlab_accessCoarseLocation" msgid="4642255009181975828">"ubicación aproximada (basada en la red)"</string>
<string name="permdesc_accessCoarseLocation" product="tablet" msgid="5460726396318105483">"Permite acceder a las fuentes de ubicación aproximada, como la base de datos de la red para celulares, para determinar la ubicación aproximada de una tableta, si está disponible. Las aplicaciones maliciosas pueden utilizar este permiso para determinar tu ubicación aproximada."</string>
- <string name="permdesc_accessCoarseLocation" product="default" msgid="8900795778057579522">"Permite acceder a fuentes de ubicación aproximada como, por ejemplo, la base de datos de la red para celulares, para determinar la ubicación aproximada de un teléfono, si está disponible. Las aplicaciones maliciosas pueden utilizar este permiso para determinar tu ubicación aproximada."</string>
+ <string name="permdesc_accessCoarseLocation" product="default" msgid="8900795778057579522">"Permite acceder a fuentes de ubicación aproximada como, por ejemplo, la base de datos de la red para celulares, para determinar la ubicación aproximada de un dispositivo, si está disponible. Las aplicaciones maliciosas pueden utilizar este permiso para determinar tu ubicación aproximada."</string>
<string name="permlab_accessSurfaceFlinger" msgid="2363969641792388947">"acceder a SurfaceFlinger"</string>
<string name="permdesc_accessSurfaceFlinger" msgid="1041619516733293551">"Permite que la aplicación utilice funciones de SurfaceFlinger de bajo nivel."</string>
<string name="permlab_readFrameBuffer" msgid="6690504248178498136">"leer el búfer de tramas"</string>
@@ -366,14 +366,14 @@
<string name="permdesc_recordAudio" msgid="2387462233976248635">"Permite que la aplicación acceda a la ruta de grabación de audio."</string>
<string name="permlab_camera" msgid="3616391919559751192">"tomar fotografías y grabar videos"</string>
<string name="permdesc_camera" msgid="1507407407002492176">"Permite que la aplicación tome fotografías y grabe videos con la cámara. De este modo, la aplicación puede obtener las imágenes que capta la cámara en cualquier momento."</string>
- <string name="permlab_brick" product="tablet" msgid="2961292205764488304">"inhabilitar tablet de forma permanente"</string>
- <string name="permlab_brick" product="default" msgid="8337817093326370537">"desactivar teléfono de manera permanente"</string>
+ <string name="permlab_brick" product="tablet" msgid="2961292205764488304">"desactivar tablet de forma permanente"</string>
+ <string name="permlab_brick" product="default" msgid="8337817093326370537">"desactivar dispositivo de manera permanente"</string>
<string name="permdesc_brick" product="tablet" msgid="4334818808001699530">"Permite que la aplicación inhabilite toda la tableta de manera permanente. Esto es muy peligroso."</string>
- <string name="permdesc_brick" product="default" msgid="5788903297627283099">"Permite que la aplicación inhabilite el teléfono de forma permanente. Este permiso es muy peligroso."</string>
+ <string name="permdesc_brick" product="default" msgid="5788903297627283099">"Permite que la aplicación inhabilite el dispositivo de forma permanente. Este permiso es muy peligroso."</string>
<string name="permlab_reboot" product="tablet" msgid="3436634972561795002">"forzar reinicio del tablet"</string>
- <string name="permlab_reboot" product="default" msgid="2898560872462638242">"forzar reinicio del teléfono"</string>
+ <string name="permlab_reboot" product="default" msgid="2898560872462638242">"forzar reinicio del dispositivo"</string>
<string name="permdesc_reboot" product="tablet" msgid="8172056180063700741">"Permite que la aplicación provoque el reinicio de la tableta."</string>
- <string name="permdesc_reboot" product="default" msgid="5326008124289989969">"Permite que la aplicación fuerce el reinicio del teléfono."</string>
+ <string name="permdesc_reboot" product="default" msgid="5326008124289989969">"Permite que la aplicación fuerce el reinicio del dispositivo."</string>
<string name="permlab_mount_unmount_filesystems" msgid="1761023272170956541">"montar y desmontar filesystems"</string>
<string name="permdesc_mount_unmount_filesystems" msgid="1829290701658992347">"Permite que la aplicación active y desactive sistemas de archivos para un almacenamiento extraíble."</string>
<string name="permlab_mount_format_filesystems" msgid="5523285143576718981">"espacio de almacenamiento externo del formato"</string>
@@ -403,7 +403,7 @@
<string name="permlab_callPrivileged" msgid="4198349211108497879">"llamar directamente a cualquier número de teléfono"</string>
<string name="permdesc_callPrivileged" msgid="1689024901509996810">"Permite que la aplicación llame a cualquier número de teléfono, incluidos números de emergencia, sin tu intervención. Las aplicaciones maliciosas pueden realizar llamadas innecesarias e ilegales a servicios de emergencia."</string>
<string name="permlab_performCdmaProvisioning" product="tablet" msgid="4842576994144604821">"iniciar directamente la configuración CDMA del tablet"</string>
- <string name="permlab_performCdmaProvisioning" product="default" msgid="5604848095315421425">"iniciar directamente la configuración CDMA del teléfono"</string>
+ <string name="permlab_performCdmaProvisioning" product="default" msgid="5604848095315421425">"iniciar directamente la configuración CDMA del dispositivo"</string>
<string name="permdesc_performCdmaProvisioning" msgid="1994193538802314186">"Permite que la aplicación inicie el método de acceso CDMA. Las aplicaciones maliciosas pueden iniciar el método CDMA de forma innecesaria."</string>
<string name="permlab_locationUpdates" msgid="7785408253364335740">"controlar las notificaciones de actualización de ubicación"</string>
<string name="permdesc_locationUpdates" msgid="1120741557891438876">"Permite que la aplicación habilite/deshabilite notificaciones de actualización de ubicación de la radio. Las aplicaciones normales no deben utilizar este permiso."</string>
@@ -411,21 +411,21 @@
<string name="permdesc_checkinProperties" msgid="4024526968630194128">"Permite que la aplicación lea/escriba el acceso a propiedades subidas por el servicio de registro. Las aplicaciones normales no deben usar este permiso."</string>
<string name="permlab_bindGadget" msgid="776905339015863471">"elegir widgets"</string>
<string name="permdesc_bindGadget" msgid="8261326938599049290">"Permite que la aplicación le indique al sistema qué widgets se pueden utilizar con cada aplicación. Una aplicación con este permiso puede proporcionar acceso a información personal por parte de otras aplicaciones. Las aplicaciones normales no deben utilizar este permiso."</string>
- <string name="permlab_modifyPhoneState" msgid="8423923777659292228">"modificar el estado del teléfono"</string>
+ <string name="permlab_modifyPhoneState" msgid="8423923777659292228">"modificar el estado del dispositivo"</string>
<string name="permdesc_modifyPhoneState" msgid="1029877529007686732">"Permite que la aplicación controle las funciones de teléfono del dispositivo. Una aplicación con este permiso puede cambiar redes, encender y apagar la radio del teléfono y tareas similares sin siquiera notificártelo."</string>
- <string name="permlab_readPhoneState" msgid="2326172951448691631">"leer el estado del teléfono y la identidad"</string>
+ <string name="permlab_readPhoneState" msgid="2326172951448691631">"leer el estado del dispositivo y la identidad"</string>
<string name="permdesc_readPhoneState" msgid="5127767618743602782">"Permite que la aplicación acceda a las funciones de teléfono del dispositivo. Una aplicación con este permiso puede determinar el número de teléfono y el número de serie del teléfono, si hay una llamada activa, el número al que esa llamada está conectada, etc."</string>
<string name="permlab_wakeLock" product="tablet" msgid="1531731435011495015">"evitar que el tablet entre en estado de inactividad"</string>
- <string name="permlab_wakeLock" product="default" msgid="573480187941496130">"evitar que el teléfono entre en estado de inactividad"</string>
+ <string name="permlab_wakeLock" product="default" msgid="573480187941496130">"evitar que el dispositivo entre en estado de inactividad"</string>
<string name="permdesc_wakeLock" product="tablet" msgid="7311319824400447868">"Permite que la aplicación evite que la tableta entre en estado de inactividad."</string>
- <string name="permdesc_wakeLock" product="default" msgid="8559100677372928754">"Permite que la aplicación evite que el teléfono entre en estado de inactividad."</string>
+ <string name="permdesc_wakeLock" product="default" msgid="8559100677372928754">"Permite que la aplicación evite que el dispositivo entre en estado de inactividad."</string>
<string name="permlab_devicePower" product="tablet" msgid="2787034722616350417">"apagar o encender el tablet"</string>
- <string name="permlab_devicePower" product="default" msgid="4928622470980943206">"apagar o encender el teléfono"</string>
+ <string name="permlab_devicePower" product="default" msgid="4928622470980943206">"apagar o encender el dispositivo"</string>
<string name="permdesc_devicePower" product="tablet" msgid="6689862878984631831">"Permite que la aplicación encienda o apague la tableta."</string>
- <string name="permdesc_devicePower" product="default" msgid="6037057348463131032">"Permite que la aplicación encienda o apague el teléfono."</string>
+ <string name="permdesc_devicePower" product="default" msgid="6037057348463131032">"Permite que la aplicación encienda o apague el dispositivo."</string>
<string name="permlab_factoryTest" msgid="3715225492696416187">"ejecutar en el modo de prueba de fábrica"</string>
<string name="permdesc_factoryTest" product="tablet" msgid="3952059318359653091">"Se ejecuta como una prueba de fábrica de bajo nivel que permite un acceso completo al hardware del tablet. Sólo disponible cuando el tablet se ejecuta en el modo de prueba de fábrica."</string>
- <string name="permdesc_factoryTest" product="default" msgid="8136644990319244802">"Se ejecuta como una prueba de fábrica de bajo nivel que permite un acceso completo al hardware del teléfono. Sólo disponible cuando un teléfono se ejecuta en el modo de prueba de fábrica."</string>
+ <string name="permdesc_factoryTest" product="default" msgid="8136644990319244802">"Se ejecuta como una prueba de fábrica de bajo nivel que permite un acceso completo al hardware del dispositivo. Sólo disponible cuando un dispositivo se ejecuta en el modo de prueba de fábrica."</string>
<string name="permlab_setWallpaper" msgid="6627192333373465143">"establecer papel tapiz"</string>
<string name="permdesc_setWallpaper" msgid="7373447920977624745">"Permite que la aplicación establezca el fondo de pantalla del sistema."</string>
<string name="permlab_setWallpaperHints" msgid="3600721069353106851">"establecer sugerencias de tamaño del papel tapiz"</string>
@@ -434,15 +434,15 @@
<string name="permdesc_masterClear" msgid="3665380492633910226">"Permite que la aplicación restablezca por completo el sistema a su configuración de fábrica al eliminar todos los datos, la configuración y las aplicaciones instaladas."</string>
<string name="permlab_setTime" msgid="2021614829591775646">"establecer la hora"</string>
<string name="permdesc_setTime" product="tablet" msgid="1896341438151152881">"Permite que la aplicación cambie la hora del reloj de la tableta."</string>
- <string name="permdesc_setTime" product="default" msgid="1855702730738020">"Permite que la aplicación cambie la hora del reloj del teléfono."</string>
+ <string name="permdesc_setTime" product="default" msgid="1855702730738020">"Permite que la aplicación cambie la hora del reloj del dispositivo."</string>
<string name="permlab_setTimeZone" msgid="2945079801013077340">"establecer zona horaria"</string>
<string name="permdesc_setTimeZone" product="tablet" msgid="1676983712315827645">"Permite que la aplicación cambie la zona horaria de la tableta."</string>
- <string name="permdesc_setTimeZone" product="default" msgid="4499943488436633398">"Permite que la aplicación cambie la zona horaria del teléfono."</string>
+ <string name="permdesc_setTimeZone" product="default" msgid="4499943488436633398">"Permite que la aplicación cambie la zona horaria del dispositivo."</string>
<string name="permlab_accountManagerService" msgid="4829262349691386986">"actuar como cuenta, administrador o servicio"</string>
<string name="permdesc_accountManagerService" msgid="1948455552333615954">"Permite que la aplicación haga llamadas a los autenticadores de cuentas."</string>
<string name="permlab_getAccounts" msgid="4549918644233460103">"descubrir cuentas conocidas"</string>
<string name="permdesc_getAccounts" product="tablet" msgid="3238360555257773358">"Permite que la aplicación obtenga una lista de cuentas reconocidas por la tableta."</string>
- <string name="permdesc_getAccounts" product="default" msgid="2735689364629830348">"Permite que la aplicación obtenga una lista de cuentas reconocidas por el teléfono."</string>
+ <string name="permdesc_getAccounts" product="default" msgid="2735689364629830348">"Permite que la aplicación obtenga una lista de cuentas reconocidas por el dispositivo."</string>
<string name="permlab_authenticateAccounts" msgid="3940505577982882450">"actuar como autenticador de cuenta"</string>
<string name="permdesc_authenticateAccounts" msgid="5472124296908977260">"Permite que la aplicación utilice las capacidades del autenticador de cuentas del administrador de cuentas, incluida la creación de cuentas y la obtención y configuración de sus contraseñas."</string>
<string name="permlab_manageAccounts" msgid="4440380488312204365">"administrar la lista de cuentas"</string>
@@ -469,18 +469,18 @@
<string name="permdesc_changeWifiMulticastState" msgid="7633598524564320817">"Permite que la aplicación reciba paquetes que no están dirigidos directamente a tu dispositivo. Esto puede ser útil para descubrir servicios cercanos. Utiliza más energia que el modo que no es de multidifusión."</string>
<string name="permlab_bluetoothAdmin" msgid="3606576270792236062">"Administración de Bluetooth"</string>
<string name="permdesc_bluetoothAdmin" product="tablet" msgid="6921177471748882137">"Permite que la aplicación configure la tableta Bluetooth local y descubra y se sincronice con dispositivos remotos."</string>
- <string name="permdesc_bluetoothAdmin" product="default" msgid="8931682159331542137">"Permite que la aplicación configure el teléfono Bluetooth local y descubra y se sincronice con dispositivos remotos."</string>
+ <string name="permdesc_bluetoothAdmin" product="default" msgid="8931682159331542137">"Permite que la aplicación configure el dispositivo Bluetooth local y descubra y se sincronice con dispositivos remotos."</string>
<string name="permlab_accessWimaxState" msgid="1232061307208861588">"Ver el estado de WiMAX"</string>
<string name="permdesc_accessWimaxState" msgid="5914958077555177749">"Permite que la aplicación consulte la información sobre el estado de WiMAX."</string>
<string name="permlab_changeWimaxState" msgid="2405042267131496579">"Cambiar el estado de WiMAX"</string>
<string name="permdesc_changeWimaxState" msgid="3328853825006455912">"Permite que la aplicación se conecte a una red WiMAX y se desconecte de ella."</string>
<string name="permlab_bluetooth" msgid="8361038707857018732">"crear conexiones de Bluetooth"</string>
<string name="permdesc_bluetooth" product="tablet" msgid="7007851048416363446">"Permite que la aplicación vea la configuración de la tableta Bluetooth local, y que cree y acepte conexiones con los dispositivos sincronizados."</string>
- <string name="permdesc_bluetooth" product="default" msgid="31846362767164948">"Permite que la aplicación vea la configuración del teléfono Bluetooth local, y que cree y acepte conexiones con los dispositivos sincronizados."</string>
+ <string name="permdesc_bluetooth" product="default" msgid="31846362767164948">"Permite que la aplicación vea la configuración del dispositivo Bluetooth local, y que cree y acepte conexiones con los dispositivos sincronizados."</string>
<string name="permlab_nfc" msgid="4423351274757876953">"controlar la Transmisión de datos en proximidad"</string>
<string name="permdesc_nfc" msgid="7120611819401789907">"Permite que la aplicación se comunique con lectores, tarjetas y etiquetas de Comunicación de campo cercano (NFC)."</string>
<string name="permlab_disableKeyguard" msgid="4977406164311535092">"desactivar el bloqueo"</string>
- <string name="permdesc_disableKeyguard" msgid="6231611286892232626">"Permite que la aplicación inhabilite el bloqueo del teclado y cualquier protección con contraseña asociada. Un ejemplo de este permiso es la inhabilitación por parte del teléfono del bloqueo del teclado al recibir una llamada telefónica entrante y su posterior habilitación cuando finaliza la llamada."</string>
+ <string name="permdesc_disableKeyguard" msgid="6231611286892232626">"Permite que la aplicación inhabilite el bloqueo del teclado y cualquier protección con contraseña asociada. Un ejemplo de este permiso es la inhabilitación por parte del dispositivo del bloqueo del teclado al recibir una llamada telefónica entrante y su posterior habilitación cuando finaliza la llamada."</string>
<string name="permlab_readSyncSettings" msgid="6201810008230503052">"leer la configuración de sincronización"</string>
<string name="permdesc_readSyncSettings" msgid="5464056785274229278">"Permite que la aplicación lea la configuración de sincronización; por ejemplo, si está habilitada la sincronización para la aplicación Personas."</string>
<string name="permlab_writeSyncSettings" msgid="6297138566442486462">"escribir configuración de sincronización"</string>
@@ -515,14 +515,14 @@
<string name="policydesc_limitPassword" msgid="3252114203919510394">"Controlar la longitud y los caracteres permitidos en las contraseñas para desbloquear la pantalla"</string>
<string name="policylab_watchLogin" msgid="914130646942199503">"Supervisa los intentos para desbloquear la pantalla"</string>
<string name="policydesc_watchLogin" product="tablet" msgid="3215729294215070072">"Controla la cantidad de contraseñas incorrectas ingresadas al desbloquear la pantalla y bloquea la tableta o borra todos los datos de la tableta si se ingresaron demasiadas contraseñas incorrectas."</string>
- <string name="policydesc_watchLogin" product="default" msgid="5712323091846761073">"Controla la cantidad de contraseñas ingresadas incorrectamente al desbloquear la pantalla y bloquea el teléfono o borra todos sus datos si se ingresan demasiadas contraseñas incorrectas."</string>
+ <string name="policydesc_watchLogin" product="default" msgid="5712323091846761073">"Controla la cantidad de contraseñas ingresadas incorrectamente al desbloquear la pantalla y bloquea el dispositivo o borra todos sus datos si se ingresan demasiadas contraseñas incorrectas."</string>
<string name="policylab_resetPassword" msgid="2620077191242688955">"Cambiar la contraseña para desbloquear la pantalla"</string>
<string name="policydesc_resetPassword" msgid="605963962301904458">"Cambiar la contraseña para desbloquear la pantalla"</string>
<string name="policylab_forceLock" msgid="2274085384704248431">"Bloquear la pantalla"</string>
<string name="policydesc_forceLock" msgid="1141797588403827138">"Controlar cómo y cuándo se bloquea la pantalla"</string>
- <string name="policylab_wipeData" msgid="3910545446758639713">"Borrar todos los datos"</string>
- <string name="policydesc_wipeData" product="tablet" msgid="4306184096067756876">"Borrar los datos de la tableta sin avisar y restablecer la configuración de fábrica"</string>
- <string name="policydesc_wipeData" product="default" msgid="5096895604574188391">"Borrar los datos del teléfono sin avisar y restablecer la configuración de fábrica"</string>
+ <string name="policylab_wipeData" msgid="3910545446758639713">"Eliminar todos los datos"</string>
+ <string name="policydesc_wipeData" product="tablet" msgid="4306184096067756876">"Eliminar los datos de la tableta sin avisar y restablecer la configuración de fábrica"</string>
+ <string name="policydesc_wipeData" product="default" msgid="5096895604574188391">"Eliminar los datos del dispositivo sin avisar y restablecer la configuración de fábrica"</string>
<string name="policylab_setGlobalProxy" msgid="2784828293747791446">"Configura el proxy global de dispositivo"</string>
<string name="policydesc_setGlobalProxy" msgid="6387497466660154931">"Configuración del proxy global de dispositivo que se utilizará mientras se habilita la política. Sólo la primera administración de dispositivo configura el proxy global efectivo."</string>
<string name="policylab_expirePassword" msgid="885279151847254056">"Establecer la caducidad del bloqueo de pantalla"</string>
@@ -629,7 +629,7 @@
<string name="relationTypeAssistant" msgid="6274334825195379076">"Asistente"</string>
<string name="relationTypeBrother" msgid="8757913506784067713">"Hermano"</string>
<string name="relationTypeChild" msgid="1890746277276881626">"Hijo"</string>
- <string name="relationTypeDomesticPartner" msgid="6904807112121122133">"Conviviente"</string>
+ <string name="relationTypeDomesticPartner" msgid="6904807112121122133">"Pareja de hecho"</string>
<string name="relationTypeFather" msgid="5228034687082050725">"Padre"</string>
<string name="relationTypeFriend" msgid="7313106762483391262">"Amigo"</string>
<string name="relationTypeManager" msgid="6365677861610137895">"Gerente"</string>
@@ -671,7 +671,7 @@
<string name="lockscreen_low_battery" msgid="1482873981919249740">"Conecta tu cargador."</string>
<string name="lockscreen_missing_sim_message_short" msgid="7381499217732227295">"No hay tarjeta SIM."</string>
<string name="lockscreen_missing_sim_message" product="tablet" msgid="151659196095791474">"No hay tarjeta SIM en el tablet."</string>
- <string name="lockscreen_missing_sim_message" product="default" msgid="2186920585695169078">"No hay tarjeta SIM en el teléfono."</string>
+ <string name="lockscreen_missing_sim_message" product="default" msgid="2186920585695169078">"No hay tarjeta SIM en el dispositivo."</string>
<string name="lockscreen_missing_sim_instructions" msgid="5372787138023272615">"Inserta una tarjeta SIM."</string>
<string name="lockscreen_missing_sim_instructions_long" msgid="3526573099019319472">"Falta la tarjeta SIM o no se puede leer. Introduce una tarjeta SIM."</string>
<string name="lockscreen_permanent_disabled_sim_instructions" msgid="910904643433151371">"Tu tarjeta SIM se ha inhabilitado de forma permanente."\n" Ponte en contacto con tu proveedor de servicios inalámbricos para obtener otra tarjeta SIM."</string>
@@ -690,27 +690,27 @@
<string name="lockscreen_too_many_failed_password_attempts_dialog_message" msgid="2725973286239344555">"Escribiste incorrectamente tu contraseña <xliff:g id="NUMBER_0">%d</xliff:g> veces. "\n\n"Vuelve a intentarlo en <xliff:g id="NUMBER_1">%d</xliff:g> segundos."</string>
<string name="lockscreen_too_many_failed_pin_attempts_dialog_message" msgid="6216672706545696955">"Escribiste incorrectamente tu PIN <xliff:g id="NUMBER_0">%d</xliff:g> veces. "\n\n"Vuelve a intentarlo en <xliff:g id="NUMBER_1">%d</xliff:g> segundos."</string>
<string name="lockscreen_failed_attempts_almost_glogin" product="tablet" msgid="9191611984625460820">"Has establecido incorrectamente tu patrón de desbloqueo <xliff:g id="NUMBER_0">%d</xliff:g> veces. Luego de <xliff:g id="NUMBER_1">%d</xliff:g> intentos incorrectos, se te solicitará que desbloquees tu tableta mediante el uso de tu información de acceso de Google."\n\n" Vuelve a intentarlo en <xliff:g id="NUMBER_2">%d</xliff:g> segundos."</string>
- <string name="lockscreen_failed_attempts_almost_glogin" product="default" msgid="2590227559763762751">"Has establecido incorrectamente tu patrón de desbloqueo <xliff:g id="NUMBER_0">%d</xliff:g> veces. Luego de <xliff:g id="NUMBER_1">%d</xliff:g> intentos incorrectos, se te solicitará que desbloquees tu teléfono mediante el uso de tu información de acceso de Google."\n\n" Vuelve a intentarlo en <xliff:g id="NUMBER_2">%d</xliff:g> segundos."</string>
+ <string name="lockscreen_failed_attempts_almost_glogin" product="default" msgid="2590227559763762751">"Has establecido incorrectamente tu patrón de desbloqueo <xliff:g id="NUMBER_0">%d</xliff:g> veces. Luego de <xliff:g id="NUMBER_1">%d</xliff:g> intentos incorrectos, se te solicitará que desbloquees tu dispositivo mediante el uso de tu información de acceso de Google."\n\n" Vuelve a intentarlo en <xliff:g id="NUMBER_2">%d</xliff:g> segundos."</string>
<string name="lockscreen_failed_attempts_almost_at_wipe" product="tablet" msgid="6128106399745755604">"Intentaste desbloquear la tableta <xliff:g id="NUMBER_0">%d</xliff:g> veces, pero no lo lograste. Puedes intentarlo <xliff:g id="NUMBER_1">%d</xliff:g> veces más antes de que se restablezcan los valores predeterminados de fábrica de la tableta y se pierdan todos los datos de usuario."</string>
- <string name="lockscreen_failed_attempts_almost_at_wipe" product="default" msgid="8603565142156826565">"Intentaste desbloquear el teléfono <xliff:g id="NUMBER_0">%d</xliff:g> veces, pero no lo lograste. Puedes intentarlo <xliff:g id="NUMBER_1">%d</xliff:g> veces más antes de que se restablezcan los valores predeterminados de fábrica del teléfono y se pierdan todos los datos de usuario."</string>
+ <string name="lockscreen_failed_attempts_almost_at_wipe" product="default" msgid="8603565142156826565">"Intentaste desbloquear el dispositivo <xliff:g id="NUMBER_0">%d</xliff:g> veces, pero no lo lograste. Puedes intentarlo <xliff:g id="NUMBER_1">%d</xliff:g> veces más antes de que se restablezcan los valores predeterminados de fábrica del dispositivo y se pierdan todos los datos de usuario."</string>
<string name="lockscreen_failed_attempts_now_wiping" product="tablet" msgid="280873516493934365">"Intentaste desbloquear la tableta <xliff:g id="NUMBER">%d</xliff:g> veces, pero no lo lograste. Se restablecerán los valores predeterminados de fábrica de la tableta."</string>
- <string name="lockscreen_failed_attempts_now_wiping" product="default" msgid="3025504721764922246">"Intentaste desbloquear el teléfono <xliff:g id="NUMBER">%d</xliff:g> veces, pero no lo lograste. Se restablecerán los valores predeterminados de fábrica del teléfono."</string>
+ <string name="lockscreen_failed_attempts_now_wiping" product="default" msgid="3025504721764922246">"Intentaste desbloquear el dispositivo <xliff:g id="NUMBER">%d</xliff:g> veces, pero no lo lograste. Se restablecerán los valores predeterminados de fábrica del dispositivo."</string>
<string name="lockscreen_too_many_failed_attempts_countdown" msgid="6251480343394389665">"Vuelve a intentarlo en <xliff:g id="NUMBER">%d</xliff:g> segundos."</string>
<string name="lockscreen_forgot_pattern_button_text" msgid="2626999449610695930">"¿Olvidaste el patrón?"</string>
<string name="lockscreen_glogin_forgot_pattern" msgid="2588521501166032747">"Desbloquear cuenta"</string>
<string name="lockscreen_glogin_too_many_attempts" msgid="2751368605287288808">"Demasiados intentos incorrectos de creación del patrón"</string>
<string name="lockscreen_glogin_instructions" msgid="3931816256100707784">"Para desbloquear, accede con tu cuenta de Google."</string>
- <string name="lockscreen_glogin_username_hint" msgid="8846881424106484447">"Nombre de usuario (correo electrónico)"</string>
+ <string name="lockscreen_glogin_username_hint" msgid="8846881424106484447">"Nombre de usuario (correo)"</string>
<string name="lockscreen_glogin_password_hint" msgid="5958028383954738528">"Contraseña"</string>
<string name="lockscreen_glogin_submit_button" msgid="7130893694795786300">"Inicia sesión"</string>
<string name="lockscreen_glogin_invalid_input" msgid="1364051473347485908">"Nombre de usuario o contraseña incorrecta."</string>
<string name="lockscreen_glogin_account_recovery_hint" msgid="1696924763690379073">"¿Olvidaste tu nombre de usuario o contraseña?"\n"Accede a "<b>"google.com/accounts/recovery"</b>"."</string>
<string name="lockscreen_glogin_checking_password" msgid="7114627351286933867">"Comprobando..."</string>
<string name="lockscreen_unlock_label" msgid="737440483220667054">"Desbloquear"</string>
- <string name="lockscreen_sound_on_label" msgid="9068877576513425970">"Sonido encendido"</string>
- <string name="lockscreen_sound_off_label" msgid="996822825154319026">"Sonido apagado"</string>
+ <string name="lockscreen_sound_on_label" msgid="9068877576513425970">"Sonido activado"</string>
+ <string name="lockscreen_sound_off_label" msgid="996822825154319026">"Sonido desactivado"</string>
<string name="lockscreen_access_pattern_start" msgid="3941045502933142847">"Se inició el patrón"</string>
- <string name="lockscreen_access_pattern_cleared" msgid="5583479721001639579">"Se borró el patrón"</string>
+ <string name="lockscreen_access_pattern_cleared" msgid="5583479721001639579">"Se eliminó el patrón"</string>
<string name="lockscreen_access_pattern_cell_added" msgid="6756031208359292487">"Se agregó una celda."</string>
<string name="lockscreen_access_pattern_detected" msgid="4988730895554057058">"Se completó el patrón"</string>
<string name="password_keyboard_label_symbol_key" msgid="992280756256536042">"?123"</string>
@@ -749,7 +749,7 @@
<string name="permdesc_readHistoryBookmarks" msgid="4577476392604595921">"Permite que la aplicación consulte todos los marcadores del navegador y todas las URL que haya visitado."</string>
<string name="permlab_writeHistoryBookmarks" msgid="9009434109836280374">"escribir historial y marcadores del navegador"</string>
<string name="permdesc_writeHistoryBookmarks" product="tablet" msgid="1757103804824209530">"Permite que la aplicación modifique el historial o los marcadores del navegador guardados en tu tableta. Las aplicaciones maliciosas pueden utilizar este permiso para borrar o modificar los datos de tu navegador."</string>
- <string name="permdesc_writeHistoryBookmarks" product="default" msgid="6693764355720719197">"Permite que la aplicación modifique el historial o los marcadores del navegador guardados en tu teléfono. Las aplicaciones maliciosas pueden utilizar este permiso para borrar o modificar los datos de tu navegador."</string>
+ <string name="permdesc_writeHistoryBookmarks" product="default" msgid="6693764355720719197">"Permite que la aplicación modifique el historial o los marcadores del navegador guardados en tu dispositivo. Las aplicaciones maliciosas pueden utilizar este permiso para borrar o modificar los datos de tu navegador."</string>
<string name="permlab_setAlarm" msgid="5924401328803615165">"configurar alarma en reloj alarma"</string>
<string name="permdesc_setAlarm" msgid="316392039157473848">"Permite que la aplicación establezca una alarma en una aplicación de alarma instalada. Es posible que algunas aplicaciones de alarma no incluyan esta función."</string>
<string name="permlab_addVoicemail" msgid="5525660026090959044">"agregar correo de voz"</string>
@@ -774,7 +774,7 @@
<string name="search_go" msgid="8298016669822141719">"Buscar"</string>
<string name="searchview_description_search" msgid="6749826639098512120">"Buscar"</string>
<string name="searchview_description_query" msgid="5911778593125355124">"Consulta de búsqueda"</string>
- <string name="searchview_description_clear" msgid="1330281990951833033">"Borrar la consulta"</string>
+ <string name="searchview_description_clear" msgid="1330281990951833033">"Eliminar la consulta"</string>
<string name="searchview_description_submit" msgid="2688450133297983542">"Enviar consulta"</string>
<string name="searchview_description_voice" msgid="2453203695674994440">"Búsqueda por voz"</string>
<string name="oneMonthDurationPast" msgid="7396384508953779925">"hace 1 mes"</string>
@@ -848,7 +848,7 @@
<item quantity="one" msgid="2178576254385739855">"mañana"</item>
<item quantity="other" msgid="2973062968038355991">"en <xliff:g id="COUNT">%d</xliff:g> días"</item>
</plurals>
- <string name="preposition_for_date" msgid="9093949757757445117">"encendido <xliff:g id="DATE">%s</xliff:g>"</string>
+ <string name="preposition_for_date" msgid="9093949757757445117">"activado <xliff:g id="DATE">%s</xliff:g>"</string>
<string name="preposition_for_time" msgid="5506831244263083793">"a las <xliff:g id="TIME">%s</xliff:g>"</string>
<string name="preposition_for_year" msgid="5040395640711867177">"en <xliff:g id="YEAR">%s</xliff:g>"</string>
<string name="day" msgid="8144195776058119424">"día"</string>
@@ -889,7 +889,7 @@
<string name="editTextMenuTitle" msgid="4909135564941815494">"Acciones de texto"</string>
<string name="low_internal_storage_view_title" msgid="1399732408701697546">"Poco espacio de almacenamiento"</string>
<string name="low_internal_storage_view_text" product="tablet" msgid="4231085657068852042">"Está quedando poco espacio de almacenamiento en el tablet."</string>
- <string name="low_internal_storage_view_text" product="default" msgid="635106544616378836">"Hay poco espacio de almacenamiento en el teléfono."</string>
+ <string name="low_internal_storage_view_text" product="default" msgid="635106544616378836">"Hay poco espacio de almacenamiento en el dispositivo."</string>
<string name="ok" msgid="5970060430562524910">"Aceptar"</string>
<string name="cancel" msgid="6442560571259935130">"Cancelar"</string>
<string name="yes" msgid="5362982303337969312">"Aceptar"</string>
@@ -900,7 +900,7 @@
<string name="capital_off" msgid="6815870386972805832">"No"</string>
<string name="whichApplication" msgid="4533185947064773386">"Completar la acción mediante"</string>
<string name="alwaysUse" msgid="4583018368000610438">"Utilizar de manera predeterminada en esta acción."</string>
- <string name="clearDefaultHintMsg" msgid="3252584689512077257">"Borrar valores predeterminados en Configuración del sistema > Aplicaciones > Descargas."</string>
+ <string name="clearDefaultHintMsg" msgid="3252584689512077257">"Eliminar valores predeterminados en Configuración del sistema > Aplicaciones > Descargas."</string>
<string name="chooseActivity" msgid="7486876147751803333">"Seleccionar una acción"</string>
<string name="chooseUsbActivity" msgid="6894748416073583509">"Selecciona una aplicación para el dispositivo USB."</string>
<string name="noApplications" msgid="2991814273936504689">"Ninguna aplicación puede realizar esta acción."</string>
@@ -915,12 +915,13 @@
<string name="force_close" msgid="8346072094521265605">"Aceptar"</string>
<string name="report" msgid="4060218260984795706">"Notificar"</string>
<string name="wait" msgid="7147118217226317732">"Esperar"</string>
+ <string name="webpage_unresponsive" msgid="3272758351138122503">"La página no responde."\n\n"¿Deseas cerrarla?"</string>
<string name="launch_warning_title" msgid="1547997780506713581">"Aplicación redireccionada"</string>
<string name="launch_warning_replace" msgid="6202498949970281412">"<xliff:g id="APP_NAME">%1$s</xliff:g> se está ejecutando ahora."</string>
<string name="launch_warning_original" msgid="188102023021668683">"<xliff:g id="APP_NAME">%1$s</xliff:g> se inició originalmente."</string>
<string name="screen_compat_mode_scale" msgid="3202955667675944499">"Escala"</string>
<string name="screen_compat_mode_show" msgid="4013878876486655892">"Mostrar siempre"</string>
- <string name="screen_compat_mode_hint" msgid="1064524084543304459">"Volver a habilitar Configuración del sistema > Aplicaciones > Descargas"</string>
+ <string name="screen_compat_mode_hint" msgid="1064524084543304459">"Volver a activar Configuración del sistema > Aplicaciones > Descargas"</string>
<string name="smv_application" msgid="3307209192155442829">"La aplicación <xliff:g id="APPLICATION">%1$s</xliff:g> (proceso <xliff:g id="PROCESS">%2$s</xliff:g>) ha infringido su política StrictMode de aplicación automática."</string>
<string name="smv_process" msgid="5120397012047462446">"El proceso <xliff:g id="PROCESS">%1$s</xliff:g> ha violado su política StrictMode autoimpuesta."</string>
<string name="android_upgrading_title" msgid="1584192285441405746">"Android se está actualizando..."</string>
@@ -1031,7 +1032,7 @@
<string name="extmedia_format_message" product="default" msgid="14131895027543830">"Se perderán todos los datos de tu tarjeta."</string>
<string name="extmedia_format_button_format" msgid="4131064560127478695">"Formato"</string>
<string name="adb_active_notification_title" msgid="6729044778949189918">"Depuración de USB conectada"</string>
- <string name="adb_active_notification_message" msgid="1016654627626476142">"Toca para inhabilitar la depuración de USB."</string>
+ <string name="adb_active_notification_message" msgid="1016654627626476142">"Toca para desactivar la depuración de USB."</string>
<string name="select_input_method" msgid="4653387336791222978">"Selecciona el método de introducción"</string>
<string name="configure_input_methods" msgid="9091652157722495116">"Configurar métodos de introducción"</string>
<string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
@@ -1203,7 +1204,7 @@
<string name="data_usage_4g_limit_title" msgid="7636489436819470761">"Datos de 4 GB desactivados"</string>
<string name="data_usage_mobile_limit_title" msgid="7869402519391631884">"Datos móviles desactivados"</string>
<string name="data_usage_wifi_limit_title" msgid="8992154736441284865">"Datos Wi-Fi desactivados"</string>
- <string name="data_usage_limit_body" msgid="3317964706973601386">"Toca para habilitar."</string>
+ <string name="data_usage_limit_body" msgid="3317964706973601386">"Toca para activar."</string>
<string name="data_usage_3g_limit_snoozed_title" msgid="7026739121138005231">"Supera límite de datos de 2G-3G"</string>
<string name="data_usage_4g_limit_snoozed_title" msgid="1106562779311209039">"Límite de datos de 4G superado"</string>
<string name="data_usage_mobile_limit_snoozed_title" msgid="279240572165412168">"Límite de datos móviles superado"</string>
diff --git a/core/res/res/values-es/strings.xml b/core/res/res/values-es/strings.xml
index fe6c704..0c526ff 100644
--- a/core/res/res/values-es/strings.xml
+++ b/core/res/res/values-es/strings.xml
@@ -915,6 +915,7 @@
<string name="force_close" msgid="8346072094521265605">"Aceptar"</string>
<string name="report" msgid="4060218260984795706">"Informar"</string>
<string name="wait" msgid="7147118217226317732">"Esperar"</string>
+ <string name="webpage_unresponsive" msgid="3272758351138122503">"La página no responde."\n\n"¿Quieres cerrarla?"</string>
<string name="launch_warning_title" msgid="1547997780506713581">"Aplicación redireccionada"</string>
<string name="launch_warning_replace" msgid="6202498949970281412">"<xliff:g id="APP_NAME">%1$s</xliff:g> se está ejecutando."</string>
<string name="launch_warning_original" msgid="188102023021668683">"Inicialmente, se inició la aplicación <xliff:g id="APP_NAME">%1$s</xliff:g>."</string>
diff --git a/core/res/res/values-et/strings.xml b/core/res/res/values-et/strings.xml
index 1a86b9d..5591289 100644
--- a/core/res/res/values-et/strings.xml
+++ b/core/res/res/values-et/strings.xml
@@ -73,11 +73,11 @@
<string name="RestrictedOnData" msgid="8653794784690065540">"Andmesideteenus on blokeeritud."</string>
<string name="RestrictedOnEmergency" msgid="6581163779072833665">"Hädaabiteenus on blokeeritud."</string>
<string name="RestrictedOnNormal" msgid="4953867011389750673">"Häälteenus on blokeeritud."</string>
- <string name="RestrictedOnAllVoice" msgid="1459318899842232234">"Kõik häälteenused on blokeeritud."</string>
+ <string name="RestrictedOnAllVoice" msgid="3396963652108151260">"Kõik häälteenused on blokeeritud."</string>
<string name="RestrictedOnSms" msgid="8314352327461638897">"SMS-teenus on blokeeritud."</string>
- <string name="RestrictedOnVoiceData" msgid="8244438624660371717">"Hääl-/andmeteenused on blokeeritud."</string>
+ <string name="RestrictedOnVoiceData" msgid="996636487106171320">"Hääl-/andmeteenused on blokeeritud."</string>
<string name="RestrictedOnVoiceSms" msgid="1888588152792023873">"Hääl-/SMS-teenused on blokeeritud."</string>
- <string name="RestrictedOnAll" msgid="2714924667937117304">"Kõik hääl-/andme-/SMS-teenused on blokeeritud."</string>
+ <string name="RestrictedOnAll" msgid="5643028264466092821">"Kõik hääl-/andme-/SMS-teenused on blokeeritud."</string>
<string name="serviceClassVoice" msgid="1258393812335258019">"Hääl"</string>
<string name="serviceClassData" msgid="872456782077937893">"Andmed"</string>
<string name="serviceClassFAX" msgid="5566624998840486475">"FAKS"</string>
@@ -108,27 +108,27 @@
<string name="fcComplete" msgid="3118848230966886575">"Funktsioonikood valmis."</string>
<string name="fcError" msgid="3327560126588500777">"Ühendusprobleem või kehtetu funktsioonikood."</string>
<string name="httpErrorOk" msgid="1191919378083472204">"OK"</string>
- <string name="httpError" msgid="6603022914760066338">"Ilmnes võrgu viga."</string>
- <string name="httpErrorLookup" msgid="4517085806977851374">"URL-i ei leitud."</string>
+ <string name="httpError" msgid="7956392511146698522">"Ilmnes võrgu viga."</string>
+ <string name="httpErrorLookup" msgid="4711687456111963163">"URL-i ei leita."</string>
<string name="httpErrorUnsupportedAuthScheme" msgid="6299980280442076799">"Saidi autentimise skeemi ei toetata."</string>
- <string name="httpErrorAuth" msgid="7293960746955020542">"Autentimine ebaõnnestus."</string>
+ <string name="httpErrorAuth" msgid="1435065629438044534">"Autentimine ebaõnnestus."</string>
<string name="httpErrorProxyAuth" msgid="1788207010559081331">"Puhverserveri kaudu autentimine ebaõnnestus."</string>
- <string name="httpErrorConnect" msgid="7623096283505770433">"Ühendus serveriga ebaõnnestus."</string>
- <string name="httpErrorIO" msgid="4270874999047767599">"Serveril ei õnnestunud sidet luua. Proovige hiljem uuesti."</string>
+ <string name="httpErrorConnect" msgid="8714273236364640549">"Serveriga ei saanud ühendust."</string>
+ <string name="httpErrorIO" msgid="2340558197489302188">"Serveriga ei saanud ühendust. Proovige hiljem uuesti."</string>
<string name="httpErrorTimeout" msgid="4743403703762883954">"Ühendus serveriga aegunud."</string>
<string name="httpErrorRedirectLoop" msgid="8679596090392779516">"Leht sisaldab liiga palju serveri ümbersuunamisi."</string>
<string name="httpErrorUnsupportedScheme" msgid="5015730812906192208">"Protokolli ei toetata."</string>
- <string name="httpErrorFailedSslHandshake" msgid="3088290300440289771">"Turvalist ühendust ei saanud luua."</string>
- <string name="httpErrorBadUrl" msgid="6088183159988619736">"Lehte ei saa avada, kuna URL on vale."</string>
- <string name="httpErrorFile" msgid="8250549644091165175">"Faili ei saa avada."</string>
- <string name="httpErrorFileNotFound" msgid="5588380756326017105">"Nõutud faili ei leitud."</string>
+ <string name="httpErrorFailedSslHandshake" msgid="96549606000658641">"Turvalist ühendust ei saanud luua."</string>
+ <string name="httpErrorBadUrl" msgid="3636929722728881972">"Lehte pole võimalik avada, kuna URL on vale."</string>
+ <string name="httpErrorFile" msgid="2170788515052558676">"Failile ei pääse juurde."</string>
+ <string name="httpErrorFileNotFound" msgid="6203856612042655084">"Soovitud faili ei leitud."</string>
<string name="httpErrorTooManyRequests" msgid="1235396927087188253">"Töötlemisel on liiga palju taotlusi. Proovige hiljem uuesti."</string>
- <string name="notification_title" msgid="1259940370369187045">"Viga kontole <xliff:g id="ACCOUNT">%1$s</xliff:g> sisselogimisel"</string>
+ <string name="notification_title" msgid="8967710025036163822">"Viga kontole <xliff:g id="ACCOUNT">%1$s</xliff:g> sisselogimisel"</string>
<string name="contentServiceSync" msgid="8353523060269335667">"Sünkroonimine"</string>
<string name="contentServiceSyncNotificationTitle" msgid="397743349191901458">"Sünkroonimine"</string>
<string name="contentServiceTooManyDeletesNotificationDesc" msgid="8100981435080696431">"Liiga palju üksuse <xliff:g id="CONTENT_TYPE">%s</xliff:g> kustutusi."</string>
- <string name="low_memory" product="tablet" msgid="2292820184396262278">"Tahvelarvuti mälu on täis. Ruumi vabastamiseks kustutage mõned failid."</string>
- <string name="low_memory" product="default" msgid="6632412458436461203">"Telefonimälu on täis. Ruumi vabastamiseks kustutage mõned failid."</string>
+ <string name="low_memory" product="tablet" msgid="6494019234102154896">"Tahvelarvuti mäluruum on täis. Ruumi vabastamiseks kustutage mõned failid."</string>
+ <string name="low_memory" product="default" msgid="3475999286680000541">"Telefonimälu on täis. Ruumi vabastamiseks kustutage mõned failid."</string>
<string name="me" msgid="6545696007631404292">"Mina"</string>
<string name="power_dialog" product="tablet" msgid="8545351420865202853">"Tahvelarvuti valikud"</string>
<string name="power_dialog" product="default" msgid="1319919075463988638">"Telefonivalikud"</string>
@@ -137,6 +137,9 @@
<string name="turn_off_radio" msgid="8198784949987062346">"Lülitage raadioside välja"</string>
<string name="screen_lock" msgid="799094655496098153">"Ekraanilukk"</string>
<string name="power_off" msgid="4266614107412865048">"Lülita välja"</string>
+ <string name="silent_mode_silent" msgid="319298163018473078">"Helin on väljas"</string>
+ <string name="silent_mode_vibrate" msgid="7072043388581551395">"Vibreeriv helin"</string>
+ <string name="silent_mode_ring" msgid="8592241816194074353">"Helin on sees"</string>
<string name="shutdown_progress" msgid="2281079257329981203">"Väljalülitamine ..."</string>
<string name="shutdown_confirm" product="tablet" msgid="3385745179555731470">"Teie tahvelarvuti lülitub välja."</string>
<string name="shutdown_confirm" product="default" msgid="649792175242821353">"Teie telefon lülitub välja."</string>
@@ -157,16 +160,16 @@
<string name="safeMode" msgid="2788228061547930246">"Turvarežiim"</string>
<string name="android_system_label" msgid="6577375335728551336">"Android-süsteem"</string>
<string name="permgrouplab_costMoney" msgid="5429808217861460401">"Tasulised teenused"</string>
- <string name="permgroupdesc_costMoney" msgid="8596717365335027057">"Võimaldab rakendustel teha tasulisi toiminguid."</string>
+ <string name="permgroupdesc_costMoney" msgid="3293301903409869495">"Tasuliste toimingute tegemine."</string>
<string name="permgrouplab_messages" msgid="7521249148445456662">"Teie sõnumid"</string>
<string name="permgroupdesc_messages" msgid="7821999071003699236">"Teie SMS-, meili- ja muude sõnumite lugemine ja kirjutamine."</string>
<string name="permgrouplab_personalInfo" msgid="3519163141070533474">"Teie isiklikud andmed"</string>
<string name="permgroupdesc_personalInfo" product="tablet" msgid="6975389054186265786">"Otsene juurdepääs tahvelarvutisse salvestatud kontaktidele ja kalendrile."</string>
<string name="permgroupdesc_personalInfo" product="default" msgid="5488050357388806068">"Otsene juurdepääs telefoni salvestatud kontaktidele ja kalendrile."</string>
<string name="permgrouplab_location" msgid="635149742436692049">"Teie asukoht"</string>
- <string name="permgroupdesc_location" msgid="2430258821648348660">"Jälgige oma füüsilist asukohta"</string>
+ <string name="permgroupdesc_location" msgid="5704679763124170100">"Jälgige oma füüsilist asukohta."</string>
<string name="permgrouplab_network" msgid="5808983377727109831">"Võrgusuhtlus"</string>
- <string name="permgroupdesc_network" msgid="4917593670797570584">"Võimaldab rakendustel pääseda juurde erinevatele võrgufunktsioonidele."</string>
+ <string name="permgroupdesc_network" msgid="4478299413241861987">"Juurdepääs erinevatele võrgufunktsioonidele."</string>
<string name="permgrouplab_accounts" msgid="3359646291125325519">"Teie kontod"</string>
<string name="permgroupdesc_accounts" msgid="4948732641827091312">"Juurdepääs saadaolevatele kontodele."</string>
<string name="permgrouplab_hardwareControls" msgid="7998214968791599326">"Riistvara juhtelemendid"</string>
@@ -206,16 +209,16 @@
<string name="permdesc_writeSms" product="default" msgid="7268668709052328567">"Võimaldab rakendusel kirjutada teie telefoni või SIM-kaardile salvestatud SMS-sõnumitesse. Pahatahtlikud rakendused võivad teie sõnumid kustutada."</string>
<string name="permlab_receiveWapPush" msgid="8258226427716551388">"võta WAP vastu"</string>
<string name="permdesc_receiveWapPush" msgid="7983455145335316872">"Võimaldab rakendusel vastu võtta ja töödelda WAP-sõnumeid. Pahatahtlikud rakendused võivad teie sõnumeid jälgida või neid kustutada teile näitamata."</string>
- <string name="permlab_getTasks" msgid="6466095396623933906">"käitatud rakenduste toomine"</string>
+ <string name="permlab_getTasks" msgid="6466095396623933906">"Käitatud rakenduste toomine"</string>
<string name="permdesc_getTasks" msgid="6608159250520381359">"Võimaldab rakendusel hankida teavet praegu töötavate ja hiljuti töötanud ülesannete kohta. Pahatahtlikud rakendused võivad avastada privaatset teavet teiste rakenduste kohta."</string>
<string name="permlab_reorderTasks" msgid="2018575526934422779">"käitatud rakenduste ümberjärjestamine"</string>
<string name="permdesc_reorderTasks" msgid="4175137612205663399">"Võimaldab rakendusel teisaldada ülesanded esiplaanile ja taustale. Pahatahtlikud rakendused võivad sundida end esiplaanile tulema teie loata."</string>
<string name="permlab_removeTasks" msgid="6821513401870377403">"käitatud rakenduste peatamine"</string>
- <string name="permdesc_removeTasks" msgid="1000226123143185094">"Võimaldab rakendusel eemaldada ülesandeid ja peatada nende rakendused. Pahatahtlikud rakendused võivad häirida teiste rakenduste käitumist."</string>
+ <string name="permdesc_removeTasks" msgid="1394714352062635493">"Võimaldab rakendusel eemaldada ülesanded ja peatada nende rakendused. Pahatahtlikud rakendused võivad häirida teiste rakenduste käitumist."</string>
<string name="permlab_setDebugApp" msgid="3022107198686584052">"Rakenduse silumise lubamine"</string>
- <string name="permdesc_setDebugApp" msgid="6215654419903651172">"Võimaldab rakendusel lülitada sisse teise rakenduse silumise. Pahatahtlikud rakendused võivad seda kasutada teiste rakenduste peatamiseks."</string>
+ <string name="permdesc_setDebugApp" msgid="4474512416299013256">"Võimaldab rakendusel lülitada sisse teise rakenduse silumise. Pahatahtlikud rakendused võivad seda kasutada teiste rakenduste peatamiseks."</string>
<string name="permlab_changeConfiguration" msgid="8214475779521218295">"muuda UI-seadeid"</string>
- <string name="permdesc_changeConfiguration" msgid="4104052649900380324">"Võimaldab rakendusel muuta praegust konfiguratsiooni, näiteks lokaati või üldist kirjasuurust."</string>
+ <string name="permdesc_changeConfiguration" msgid="4372223873154296076">"Võimaldab rakendusel muuta praegust konfiguratsiooni, näiteks lokaati või üldist kirjasuurust."</string>
<string name="permlab_enableCarMode" msgid="5684504058192921098">"autorežiimi lubamine"</string>
<string name="permdesc_enableCarMode" msgid="4853187425751419467">"Võimaldab rakendusel autorežiimi lubada."</string>
<string name="permlab_killBackgroundProcesses" msgid="8373714752793061963">"taustaprotsesside peatamine"</string>
@@ -251,11 +254,11 @@
<string name="permlab_confirm_full_backup" msgid="5557071325804469102">"täieliku varukoopia kinnitamine või toimingu taastamine"</string>
<string name="permdesc_confirm_full_backup" msgid="1748762171637699562">"Võimaldab rakendusel käivitada täieliku varukoopia kinnitusliidese. Mitte kasutada üheski rakenduses."</string>
<string name="permlab_internalSystemWindow" msgid="2148563628140193231">"kuva volituseta aknad"</string>
- <string name="permdesc_internalSystemWindow" msgid="6510907081810231374">"Võimaldab rakendusel luua aknaid, mis on mõeldud süsteemisisesele kasutajaliidesele. Mitte kasutada tavarakenduste puhul."</string>
+ <string name="permdesc_internalSystemWindow" msgid="7458387759461466397">"Võimaldab rakendusel luua aknaid, mis on mõeldud kasutamiseks süsteemisisesele kasutajaliidesele. Mitte kasutada tavarakenduste puhul."</string>
<string name="permlab_systemAlertWindow" msgid="3372321942941168324">"kuva süsteemitasemel märguandeid"</string>
<string name="permdesc_systemAlertWindow" msgid="8507863469978066409">"Võimaldab rakendusel kuvada süsteemihoiatuste aknaid. Pahatahtlikud rakendused võivad hõlmata kogu ekraani."</string>
<string name="permlab_setAnimationScale" msgid="2805103241153907174">"muuda üldist animatsioonikiirust"</string>
- <string name="permdesc_setAnimationScale" msgid="6505093307223395456">"Võimaldab rakendusel muuta igal ajal üldist animatsiooni kiirust (animatsioone kiirendada või aeglustada)."</string>
+ <string name="permdesc_setAnimationScale" msgid="7690063428924343571">"Võimaldab rakendusel muuta animatsiooni üldist kiirust (animatsioone kiirendada või aeglustada) ükskõik millal."</string>
<string name="permlab_manageAppTokens" msgid="1286505717050121370">"Rakenduse lubade haldamine"</string>
<string name="permdesc_manageAppTokens" msgid="8043431713014395671">"Võimaldab rakendusel luua ja hallata tema enda lube, möödudes tavapärasest Z-järjekorrast. Tavarakenduste puhul ei peaks seda kunagi vaja minema."</string>
<string name="permlab_injectEvents" msgid="1378746584023586600">"vajuta klahve ja juhtnuppe"</string>
@@ -266,9 +269,9 @@
<string name="permlab_bindInputMethod" msgid="3360064620230515776">"seo sisestusmeetodiga"</string>
<string name="permdesc_bindInputMethod" msgid="3250440322807286331">"Lubab omanikul siduda sisestusmeetodi ülataseme liidesega. Tavarakenduste puhul ei peaks seda kunagi vaja minema."</string>
<string name="permlab_bindTextService" msgid="7358378401915287938">"tekstiteenusega sidumine"</string>
- <string name="permdesc_bindTextService" msgid="8151968910973998670">"Võimaldab omanikul siduda tekstiteenuse (nt SpellCheckerService) ülataseme liidest. Tavarakenduste puhul ei peaks seda kunagi vaja minema."</string>
+ <string name="permdesc_bindTextService" msgid="8151968910973998670">"Võimaldab omanikul siduda tekstiteenuse (nt SpellCheckerService) ülataseme liidesega. Tavarakenduste puhul ei peaks seda kunagi vaja minema."</string>
<string name="permlab_bindVpnService" msgid="4708596021161473255">"seo VPN-teenusega"</string>
- <string name="permdesc_bindVpnService" msgid="2067845564581693905">"Võimaldab omanikul siduda vidina teenuse ülataseme liidesega. Tavarakenduste puhul ei peaks seda kunagi vaja minema."</string>
+ <string name="permdesc_bindVpnService" msgid="2067845564581693905">"Võimaldab omanikul siduda VPN-teenuse ülataseme liidesega. Tavarakenduste puhul ei peaks seda kunagi vaja minema."</string>
<string name="permlab_bindWallpaper" msgid="8716400279937856462">"taustapildiga sidumine"</string>
<string name="permdesc_bindWallpaper" msgid="7108428692595491668">"Lubab omanikul siduda taustapildi ülataseme liidesega. Tavarakenduste puhul ei peaks seda kunagi vaja minema."</string>
<string name="permlab_bindRemoteViews" msgid="5697987759897367099">"vidinateenusega sidumine"</string>
@@ -292,7 +295,7 @@
<string name="permlab_getPackageSize" msgid="7472921768357981986">"Rakenduse mäluruumi mõõtmine"</string>
<string name="permdesc_getPackageSize" msgid="3921068154420738296">"Võimaldab rakendusel tuua oma koodi, andmed ja vahemälu suurused"</string>
<string name="permlab_installPackages" msgid="2199128482820306924">"Rakenduste otse installimine"</string>
- <string name="permdesc_installPackages" msgid="5628530972548071284">"Võimaldab rakendusel installida uusi või värskendatud Android-pakette. Pahatahtlikud rakendused võivad seda kasutada uute rakenduste lisamiseks omavoliliselt võimsate õigustega."</string>
+ <string name="permdesc_installPackages" msgid="5628530972548071284">"Võimaldab rakendusel installida uusi või värskendatud Android-pakette. Pahatahtlikud rakendused võivad selle abil lisada uusi meelevaldse tegevuse lubadega rakendusi."</string>
<string name="permlab_clearAppCache" msgid="7487279391723526815">"Kõigi rakenduse vahemäluandmete kustutamine"</string>
<string name="permdesc_clearAppCache" product="tablet" msgid="3523396284474042284">"Võimaldab rakendusel vabastada tahvelarvuti mälu, kustutades faile otse rakenduse kataloogist. Süsteem on juurdepääsu sellele harilikult väga piiranud."</string>
<string name="permdesc_clearAppCache" product="default" msgid="5067988373366292186">"Võimaldab rakendusel vabastada telefoni mälu, kustutades faile otse rakenduse kataloogist. Süsteem on juurdepääsu sellele harilikult väga piiranud."</string>
@@ -301,6 +304,8 @@
<string name="permlab_readLogs" msgid="6615778543198967614">"tundlike logiandmete lugemine"</string>
<string name="permdesc_readLogs" product="tablet" msgid="82061313293455151">"Võimaldab rakendusel lugeda süsteemi erinevaid logifaile. Nii on võimalik avastada üldist teavet selle kohta, mida te tahvelarvutiga teete, sh isiklikku või privaatset teavet."</string>
<string name="permdesc_readLogs" product="default" msgid="2063438140241560443">"Võimaldab rakendusel lugeda süsteemi erinevaid logifaile. Nii on võimalik avastada üldist teavet selle kohta, mida te telefoniga teete, mis võib kaasata ka isiklikku või privaatset teavet."</string>
+ <string name="permlab_anyCodecForPlayback" msgid="715805555823881818">"Mis tahes meediumidekooderi kasutamine taasesituseks"</string>
+ <string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"Võimaldab rakendusel taasesituseks kasutada mis tahes installitud meediumidekooderit."</string>
<string name="permlab_diagnostic" msgid="8076743953908000342">"loe/kirjuta valija allikaid"</string>
<string name="permdesc_diagnostic" msgid="6608295692002452283">"Võimaldab rakendusel lugeda valimisrühma mis tahes ressurssi ja sellesse kirjutada (näiteks kaustas /dev olevad failid). See võib mõjutada süsteemi stabiilsust ja turvet. Seda tohiks kasutada tootja või operaator AINULT riistvaraspetsiifiliseks diagnostikaks."</string>
<string name="permlab_changeComponentState" msgid="6335576775711095931">"Rakenduse komponentide lubamine või keelamine"</string>
@@ -335,7 +340,7 @@
<string name="permlab_writeSocialStream" product="default" msgid="3504179222493235645">"Sotsiaalvoogu kirjutamine"</string>
<string name="permdesc_writeSocialStream" product="default" msgid="3496277176955721451">"Võimaldab rakendusel kuvada sõprade suhtlusuudiseid. Pahatahtlikud rakendused saavad selle abil teie sõpra teeselda ja meelitada teid avaldama paroole või muud konfidentsiaalset teavet."</string>
<string name="permlab_readCalendar" msgid="5972727560257612398">"kalendrisündmuste lugemine ja konfidentsiaalne teave"</string>
- <string name="permdesc_readCalendar" product="tablet" msgid="2338414551004122687">"Võimaldab rakendusel lugeda kõiki teie tahvelarvutisse salvestatud kalendrisündmusi, sh teie sõprade või töökaaslaste omi. Pahatahtlikud rakendused võivad nendest kalendritest välja võtta isiklikku teavet ilma teadmiseta."</string>
+ <string name="permdesc_readCalendar" product="tablet" msgid="2338414551004122687">"Võimaldab rakendusel lugeda kõiki teie tahvelarvutisse salvestatud kalendrisündmusi, sh teie sõprade või töökaaslaste omi. Pahatahtlikud rakendused võivad nendest kalendritest välja võtta isiklikku teavet ilma omanike teadmata."</string>
<string name="permdesc_readCalendar" product="default" msgid="5693933067751827753">"Võimaldab rakendusel lugeda kõiki teie telefoni salvestatud kalendrisündmusi, sh teie sõprade või töökaaslaste omi. Pahatahtlikud rakendused võivad nendest kalendritest välja võtta isiklikku teavet omaniku teadmiseta."</string>
<string name="permlab_writeCalendar" msgid="8438874755193825647">"kalendrisündmuste lisamine või muutmine ja külalistele omanike teadmata meili saatmine"</string>
<string name="permdesc_writeCalendar" msgid="2243771395254848873">"Võimaldab rakendusel saata sündmusekutseid kalendri omanikuna ning lisada, eemaldada või muuta sündmusi, mida saate oma seadmel muuta, sh oma sõprade või töökaaslaste omi. Pahatahtlikud rakendused võivad saata rämpsposti, mis näib olevat tulnud kalendriomanikelt, muuta sündmusi omanike teadmata või lisada võltssündmusi."</string>
@@ -434,7 +439,7 @@
<string name="permdesc_setTimeZone" product="tablet" msgid="1676983712315827645">"Võimaldab rakendusel muuta tahvelarvuti ajavööndit."</string>
<string name="permdesc_setTimeZone" product="default" msgid="4499943488436633398">"Võimaldab rakendusel muuta telefoni ajavööndit."</string>
<string name="permlab_accountManagerService" msgid="4829262349691386986">"AccountManagerService\'ina tegutsemine"</string>
- <string name="permdesc_accountManagerService" msgid="2684502137670299915">"Võimaldab rakendusel helistada konto autentijatele."</string>
+ <string name="permdesc_accountManagerService" msgid="1948455552333615954">"Võimaldab rakendusel helistada konto autentijatele."</string>
<string name="permlab_getAccounts" msgid="4549918644233460103">"leia teadaolevad kontod"</string>
<string name="permdesc_getAccounts" product="tablet" msgid="3238360555257773358">"Võimaldab rakendusel hankida tahvelarvutile teadaolevate kontode loendi."</string>
<string name="permdesc_getAccounts" product="default" msgid="2735689364629830348">"Võimaldab rakendusel saada telefonile teadaolevate kontode loendi."</string>
@@ -465,6 +470,10 @@
<string name="permlab_bluetoothAdmin" msgid="3606576270792236062">"Bluetoothi haldamine"</string>
<string name="permdesc_bluetoothAdmin" product="tablet" msgid="6921177471748882137">"Võimaldab rakendusel seadistada kohalikku Bluetooth-tahvelarvutit ning leida ja siduda seda kaugseadmetega."</string>
<string name="permdesc_bluetoothAdmin" product="default" msgid="8931682159331542137">"Võimaldab rakendusel seadistada kohalikku Bluetooth-telefoni ning leida ja siduda seda kaugseadmetega."</string>
+ <string name="permlab_accessWimaxState" msgid="1232061307208861588">"WiMAX-i oleku kuvamine"</string>
+ <string name="permdesc_accessWimaxState" msgid="5914958077555177749">"Võimaldab rakendusel vaadata WiMAX-i olekuteavet."</string>
+ <string name="permlab_changeWimaxState" msgid="2405042267131496579">"WiMAX-i oleku muutmine"</string>
+ <string name="permdesc_changeWimaxState" msgid="3328853825006455912">"Võimaldab rakendusel luua ja katkestada ühenduse WiMAX-i võrguga."</string>
<string name="permlab_bluetooth" msgid="8361038707857018732">"loo Bluetooth-ühendusi"</string>
<string name="permdesc_bluetooth" product="tablet" msgid="7007851048416363446">"Võimaldab rakendusel vaadata kohaliku Bluetooth-tahvelarvuti konfiguratsiooni ning luua ja heaks kiita ühendusi seotud seadmetega."</string>
<string name="permdesc_bluetooth" product="default" msgid="31846362767164948">"Võimaldab rakendusel vaadata kohaliku Bluetooth-telefoni konfiguratsiooni ning luua ja heaks kiita ühendusi seotud seadmetega."</string>
@@ -501,27 +510,27 @@
<string name="permlab_manageNetworkPolicy" msgid="2562053592339859990">"võrgueeskirjade haldamine"</string>
<string name="permdesc_manageNetworkPolicy" msgid="7537586771559370668">"Võimaldab rakendusel hallata võrgueeskirju ja määratleda rakendusespetsiifilisi reegleid."</string>
<string name="permlab_modifyNetworkAccounting" msgid="5088217309088729650">"võrgukasutuse arvestamise muutmine"</string>
- <string name="permdesc_modifyNetworkAccounting" msgid="8553240749784321765">"Võimaldab rakendusel muuta võrgukasutuse loendamist rakenduste suhtes. Mitte kasutada tavarakenduste puhul."</string>
+ <string name="permdesc_modifyNetworkAccounting" msgid="5443412866746198123">"Võimaldab rakendusel muuta võrgukasutuse loendamist rakenduste suhtes. Mitte kasutada tavarakenduste puhul."</string>
<string name="policylab_limitPassword" msgid="4497420728857585791">"Parooli reeglite määramine"</string>
- <string name="policydesc_limitPassword" msgid="9083400080861728056">"Ekraaniluku paroolide lubatud pikkuse ja tähemärkide kontrollimine"</string>
+ <string name="policydesc_limitPassword" msgid="3252114203919510394">"Kontrollige ekraaniluku avamise paroolide pikkust ja tähemärke."</string>
<string name="policylab_watchLogin" msgid="914130646942199503">"Ekraani avamiskatsed"</string>
<string name="policydesc_watchLogin" product="tablet" msgid="3215729294215070072">"Jälgib ekraani avamisel valesti sisestatud paroolide arvu ja lukustab tahvelarvuti või kustutab kõik selle andmed, kui vale parool sisestatakse liiga palju kordi."</string>
<string name="policydesc_watchLogin" product="default" msgid="5712323091846761073">"Jälgib ekraani avamisel valesti sisestatud paroolide arvu ja lukustab telefoni või kustutab kõik selle andmed, kui vale parool sisestatakse liiga palju kordi."</string>
<string name="policylab_resetPassword" msgid="2620077191242688955">"Ekraaniluku parooli muutmine"</string>
- <string name="policydesc_resetPassword" msgid="5391240616981297361">"Ekraaniluku parooli muutmine"</string>
+ <string name="policydesc_resetPassword" msgid="605963962301904458">"Ekraaniluku parooli muutmine."</string>
<string name="policylab_forceLock" msgid="2274085384704248431">"Ekraani lukustamine"</string>
- <string name="policydesc_forceLock" msgid="5696964126226028442">"Juhtige, kuidas ja millal ekraan lukustub"</string>
+ <string name="policydesc_forceLock" msgid="1141797588403827138">"Määrake, kuidas ja millal ekraan lukustub."</string>
<string name="policylab_wipeData" msgid="3910545446758639713">"Kõikide andmete kustutamine"</string>
- <string name="policydesc_wipeData" product="tablet" msgid="314455232799486222">"Tahvelarvuti andmete hoiatuseta kustutamine, lähtestades tehaseandmed"</string>
- <string name="policydesc_wipeData" product="default" msgid="7669895333814222586">"Telefoniandmete hoiatuseta kustutamine, lähtestades tehaseandmed"</string>
+ <string name="policydesc_wipeData" product="tablet" msgid="4306184096067756876">"Kustutage tahvelarvuti andmed hoiatamata, lähtestades arvuti tehaseandmetele."</string>
+ <string name="policydesc_wipeData" product="default" msgid="5096895604574188391">"Kustuta telefoniandmed hoiatuseta, lähtestades telefoni tehaseandmetele."</string>
<string name="policylab_setGlobalProxy" msgid="2784828293747791446">"Määra seadme globaalne puhverserver"</string>
<string name="policydesc_setGlobalProxy" msgid="6387497466660154931">"Eeskirjade lubamise ajal kasutatava seadme globaalse puhverserveri määramine. Ainult esimese seadme administraator määrab tõhusa globaalse puhverserveri."</string>
<string name="policylab_expirePassword" msgid="885279151847254056">"Ekraaniluku parooli aegumise määramine"</string>
- <string name="policydesc_expirePassword" msgid="4844430354224822074">"Juhib, kui sageli ekraaniluku parooli tuleb muuta"</string>
+ <string name="policydesc_expirePassword" msgid="1729725226314691591">"Määrake ekraaniluku parooli muutmissagedus."</string>
<string name="policylab_encryptedStorage" msgid="8901326199909132915">"Salvestamise krüpt. määramine"</string>
- <string name="policydesc_encryptedStorage" msgid="8877192718681120469">"Nõue, et salvestatud rakenduse andmed krüpteeritakse"</string>
+ <string name="policydesc_encryptedStorage" msgid="2637732115325316992">"Nõua salvestatud rakenduse andmete krüpteerimist."</string>
<string name="policylab_disableCamera" msgid="6395301023152297826">"Keela kaamerad"</string>
- <string name="policydesc_disableCamera" msgid="5680054212889413366">"Väldi kõigi seadme kaamerate kasutamist"</string>
+ <string name="policydesc_disableCamera" msgid="2306349042834754597">"Vältige seadme kõigi kaamerate kasutamist."</string>
<string-array name="phoneTypes">
<item msgid="8901098336658710359">"Kodu"</item>
<item msgid="869923650527136615">"Mobiil"</item>
@@ -642,7 +651,7 @@
<string name="keyguard_password_entry_touch_hint" msgid="7858547464982981384"><font size="17">"Puudutage parooli sisestamiseks"</font></string>
<string name="keyguard_password_enter_password_code" msgid="1054721668279049780">"Avamiseks sisestage parool"</string>
<string name="keyguard_password_enter_pin_password_code" msgid="6391755146112503443">"Avamiseks sisestage PIN-kood"</string>
- <string name="keyguard_password_wrong_pin_code" msgid="1295984114338107718">"Vale PIN-kood."</string>
+ <string name="keyguard_password_wrong_pin_code" msgid="2422225591006134936">"Vale PIN-kood."</string>
<string name="keyguard_label_text" msgid="861796461028298424">"Avamiseks vajutage menüüklahvi, seejärel klahvi 0."</string>
<string name="emergency_call_dialog_number_for_display" msgid="696192103195090970">"Hädaabinumber"</string>
<string name="lockscreen_carrier_default" msgid="8963839242565653192">"Teenus puudub."</string>
@@ -655,6 +664,7 @@
<string name="lockscreen_pattern_correct" msgid="9039008650362261237">"Õige."</string>
<string name="lockscreen_pattern_wrong" msgid="4317955014948108794">"Proovige uuesti"</string>
<string name="lockscreen_password_wrong" msgid="5737815393253165301">"Proovige uuesti"</string>
+ <string name="faceunlock_multiple_failures" msgid="754137583022792429">"Maksimaalne teenusega Face Unlock avamise katsete arv on ületatud"</string>
<string name="lockscreen_plugged_in" msgid="8057762828355572315">"Laadimine, <xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
<string name="lockscreen_charged" msgid="4938930459620989972">"Laetud."</string>
<string name="lockscreen_battery_short" msgid="3617549178603354656">"<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
@@ -688,14 +698,14 @@
<string name="lockscreen_too_many_failed_attempts_countdown" msgid="6251480343394389665">"Proovige uuesti <xliff:g id="NUMBER">%d</xliff:g> sekundi pärast."</string>
<string name="lockscreen_forgot_pattern_button_text" msgid="2626999449610695930">"Kas unustasite mustri?"</string>
<string name="lockscreen_glogin_forgot_pattern" msgid="2588521501166032747">"Konto avamine"</string>
- <string name="lockscreen_glogin_too_many_attempts" msgid="2446246026221678244">"Liiga palju mustrikatseid."</string>
- <string name="lockscreen_glogin_instructions" msgid="1816635201812207709">"Avamiseks logige sisse oma Google\'i kontoga"</string>
+ <string name="lockscreen_glogin_too_many_attempts" msgid="2751368605287288808">"Liiga palju mustrikatseid"</string>
+ <string name="lockscreen_glogin_instructions" msgid="3931816256100707784">"Avamiseks logige sisse oma Google\'i kontoga."</string>
<string name="lockscreen_glogin_username_hint" msgid="8846881424106484447">"Kasutajanimi (e-post)"</string>
<string name="lockscreen_glogin_password_hint" msgid="5958028383954738528">"Parool"</string>
<string name="lockscreen_glogin_submit_button" msgid="7130893694795786300">"Logi sisse"</string>
<string name="lockscreen_glogin_invalid_input" msgid="1364051473347485908">"Vale kasutajanimi või parool."</string>
- <string name="lockscreen_glogin_account_recovery_hint" msgid="8253152905532900548">"Kas unustasite oma kasutajanime või parooli?"\n"Külastage aadressi "<b>"google.com/accounts/recovery"</b></string>
- <string name="lockscreen_glogin_checking_password" msgid="6758890536332363322">"Kontrollimine ..."</string>
+ <string name="lockscreen_glogin_account_recovery_hint" msgid="1696924763690379073">"Kas unustasite oma kasutajanime või parooli?"\n"Külastage aadressi "<b>"google.com/accounts/recovery"</b>"."</string>
+ <string name="lockscreen_glogin_checking_password" msgid="7114627351286933867">"Kontrollimine ..."</string>
<string name="lockscreen_unlock_label" msgid="737440483220667054">"Ava"</string>
<string name="lockscreen_sound_on_label" msgid="9068877576513425970">"Heli sisse"</string>
<string name="lockscreen_sound_off_label" msgid="996822825154319026">"Heli välja"</string>
@@ -712,13 +722,13 @@
<string name="factorytest_not_system" msgid="4435201656767276723">"Toimingut FACTORY_TEST toetatakse ainult kausta \\system\\app installitud pakettide puhul."</string>
<string name="factorytest_no_action" msgid="872991874799998561">"Ei leitud ühtegi paketti, mis võimaldaks toimingut FACTORY_TEST."</string>
<string name="factorytest_reboot" msgid="6320168203050791643">"Taaskäivita"</string>
- <string name="js_dialog_title" msgid="8143918455087008109">"Veebileht aadressil <xliff:g id="TITLE">%s</xliff:g> ütleb:"</string>
+ <string name="js_dialog_title" msgid="1987483977834603872">"Leht „<xliff:g id="TITLE">%s</xliff:g>” ütleb järgmist."</string>
<string name="js_dialog_title_default" msgid="6961903213729667573">"JavaScript"</string>
- <string name="js_dialog_before_unload" msgid="730366588032430474">"Kas soovite sellelt lehelt lahkuda?"\n\n"<xliff:g id="MESSAGE">%s</xliff:g>"\n\n"Jätkamiseks puudutage OK, praegusele lehele jäämiseks valikut Tühista."</string>
+ <string name="js_dialog_before_unload" msgid="730366588032430474">"Kas soovite sellelt lehelt lahkuda?"\n\n"<xliff:g id="MESSAGE">%s</xliff:g>"\n\n"Jätkamiseks puudutage valikut OK, praegusele lehele jäämiseks valikut Tühista."</string>
<string name="save_password_label" msgid="6860261758665825069">"Kinnita"</string>
- <string name="double_tap_toast" msgid="2729045387923870404">"Vihje: suurendamiseks ja vähendamiseks puudutage kaks korda."</string>
- <string name="autofill_this_form" msgid="1272247532604569872">"Autom."</string>
- <string name="setup_autofill" msgid="8154593408885654044">"Aut. täit. sead."</string>
+ <string name="double_tap_toast" msgid="4595046515400268881">"Vihje: suurendamiseks ja vähendamiseks puudutage kaks korda."</string>
+ <string name="autofill_this_form" msgid="4616758841157816676">"Automaatne täitmine"</string>
+ <string name="setup_autofill" msgid="7103495070180590814">"Automaatse täitmise seadistamine"</string>
<string name="autofill_address_name_separator" msgid="2504700673286691795">" "</string>
<string name="autofill_address_summary_name_format" msgid="3268041054899214945">"$1$2$3"</string>
<string name="autofill_address_summary_separator" msgid="7483307893170324129">", "</string>
@@ -853,9 +863,9 @@
<string name="weeks" msgid="6509623834583944518">"nädalat"</string>
<string name="year" msgid="4001118221013892076">"aasta"</string>
<string name="years" msgid="6881577717993213522">"aastat"</string>
- <string name="VideoView_error_title" msgid="5927895235831021723">"Videot ei saa esitada"</string>
+ <string name="VideoView_error_title" msgid="3534509135438353077">"Probleem videoga"</string>
<string name="VideoView_error_text_invalid_progressive_playback" msgid="3186670335938670444">"See video ei sobi voogesituseks selles seadmes."</string>
- <string name="VideoView_error_text_unknown" msgid="4309847331399592194">"Seda videot ei saa esitada."</string>
+ <string name="VideoView_error_text_unknown" msgid="3450439155187810085">"Videot ei saa esitada."</string>
<string name="VideoView_error_button" msgid="2822238215100679592">"OK"</string>
<string name="relative_time" msgid="1818557177829411417">"<xliff:g id="DATE">%1$s</xliff:g>, <xliff:g id="TIME">%2$s</xliff:g>"</string>
<string name="noon" msgid="7245353528818587908">"keskpäev"</string>
@@ -891,7 +901,7 @@
<string name="whichApplication" msgid="4533185947064773386">"Lõpetage toiming rakendusega"</string>
<string name="alwaysUse" msgid="4583018368000610438">"Kasuta vaikimisi selleks toiminguks."</string>
<string name="clearDefaultHintMsg" msgid="3252584689512077257">"Tühjendage vaikeandmed valikutes Süsteemiseaded > Rakendused > Allalaaditud."</string>
- <string name="chooseActivity" msgid="1009246475582238425">"Valige toiming"</string>
+ <string name="chooseActivity" msgid="7486876147751803333">"Toimingu valimine"</string>
<string name="chooseUsbActivity" msgid="6894748416073583509">"USB-seadme jaoks rakenduse valimine"</string>
<string name="noApplications" msgid="2991814273936504689">"Ükski rakendus ei saa seda toimingut teostada."</string>
<string name="aerr_title" msgid="1905800560317137752"></string>
@@ -905,6 +915,7 @@
<string name="force_close" msgid="8346072094521265605">"OK"</string>
<string name="report" msgid="4060218260984795706">"Teata"</string>
<string name="wait" msgid="7147118217226317732">"Oodake"</string>
+ <string name="webpage_unresponsive" msgid="3272758351138122503">"Leht ei reageeri."\n\n"Kas soovite selle sulgeda?"</string>
<string name="launch_warning_title" msgid="1547997780506713581">"Rakendus on ümber suunatud"</string>
<string name="launch_warning_replace" msgid="6202498949970281412">"<xliff:g id="APP_NAME">%1$s</xliff:g> on nüüd käivitunud."</string>
<string name="launch_warning_original" msgid="188102023021668683">"Algselt käivitati rakendus <xliff:g id="APP_NAME">%1$s</xliff:g>."</string>
@@ -925,11 +936,11 @@
<string name="old_app_description" msgid="2082094275580358049">"Ärge käivitage uut rakendust."</string>
<string name="new_app_action" msgid="5472756926945440706">"Käivitage rakendus <xliff:g id="OLD_APP">%1$s</xliff:g>"</string>
<string name="new_app_description" msgid="1932143598371537340">"Peatage vana rakendus salvestamata."</string>
- <string name="sendText" msgid="5132506121645618310">"Valige teksti jaoks toiming"</string>
+ <string name="sendText" msgid="5209874571959469142">"Valige teksti jaoks toiming"</string>
<string name="volume_ringtone" msgid="6885421406845734650">"Helina helitugevus"</string>
<string name="volume_music" msgid="5421651157138628171">"Meediumi helitugevus"</string>
<string name="volume_music_hint_playing_through_bluetooth" msgid="9165984379394601533">"Esitatakse Bluetoothi kaudu"</string>
- <string name="volume_music_hint_silent_ringtone_selected" msgid="6158339745293431194">"Valitud on hääletu helin"</string>
+ <string name="volume_music_hint_silent_ringtone_selected" msgid="8310739960973156272">"Valitud on hääletu märguanne"</string>
<string name="volume_call" msgid="3941680041282788711">"Kõne helitugevus"</string>
<string name="volume_bluetooth_call" msgid="2002891926351151534">"Bluetoothi kõne helitugevus"</string>
<string name="volume_alarm" msgid="1985191616042689100">"Alarmi helitugevus"</string>
@@ -953,17 +964,22 @@
<item quantity="one" msgid="1634101450343277345">"Avatud WiFi võrk on saadaval"</item>
<item quantity="other" msgid="7915895323644292768">"Avatud WiFi-võrgud on saadaval"</item>
</plurals>
- <string name="wifi_available_sign_in" msgid="9157196203958866662">"Logi sisse WiFi-võrku"</string>
+ <string name="wifi_available_sign_in" msgid="4029489716605255386">"Logige sisse WiFi-võrku"</string>
<!-- no translation found for wifi_available_sign_in_detailed (6797764740339907572) -->
<skip />
<string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Ei saanud WiFi-ga ühendust"</string>
- <string name="wifi_watchdog_network_disabled_detailed" msgid="4917472096696322767">" on halb Interneti-ühendus."</string>
+ <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" on halb Interneti-ühendus."</string>
<string name="wifi_p2p_dialog_title" msgid="97611782659324517">"WiFi Direct"</string>
- <string name="wifi_p2p_turnon_message" msgid="2804722042556269129">"Käivitage WiFi Directi töö. See lülitab WiFi-kliendi/-tööpunkti töö välja."</string>
- <string name="wifi_p2p_failed_message" msgid="1820097493844848281">"Otsese WiFi-ühenduse käivitamine ebaõnnestus"</string>
- <string name="wifi_p2p_pbc_go_negotiation_request_message" msgid="3170321684621420428">"WiFi Directi ühenduse seadistamise taotlus seadmelt <xliff:g id="P2P_DEVICE_ADDRESS">%1$s</xliff:g>. Nõustumiseks klõpsake OK."</string>
- <string name="wifi_p2p_pin_go_negotiation_request_message" msgid="5177412094633377308">"WiFi Directi ühenduse seadistuse taotlus seadmelt <xliff:g id="P2P_DEVICE_ADDRESS">%1$s</xliff:g>. Jätkamiseks sisestage PIN-kood."</string>
- <string name="wifi_p2p_pin_display_message" msgid="2834049169114922902">"Jätkamiseks tuleb ühenduse seadistamise eesmärgil sisestada partnerseadmesse <xliff:g id="P2P_CLIENT_ADDRESS">%2$s</xliff:g> WPS-i PIN-kood <xliff:g id="P2P_WPS_PIN">%1$s</xliff:g>."</string>
+ <string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"Käivitage WiFi otseühendus. See lülitab välja WiFi kliendi/leviala."</string>
+ <string name="wifi_p2p_failed_message" msgid="3763669677935623084">"WiFi otseühenduse käivitamine ebaõnnestus."</string>
+ <string name="accept" msgid="1645267259272829559">"Nõustu"</string>
+ <string name="decline" msgid="2112225451706137894">"Keeldu"</string>
+ <string name="wifi_p2p_invitation_sent_title" msgid="1318975185112070734">"Kutse on saadetud"</string>
+ <string name="wifi_p2p_invitation_to_connect_title" msgid="4958803948658533637">"Kutse ühendamiseks"</string>
+ <string name="wifi_p2p_from_message" msgid="570389174731951769">"Saatja:"</string>
+ <string name="wifi_p2p_to_message" msgid="248968974522044099">"Saaja:"</string>
+ <string name="wifi_p2p_enter_pin_message" msgid="5920929550367828970">"Sisestage nõutav PIN-kood:"</string>
+ <string name="wifi_p2p_show_pin_message" msgid="8530563323880921094">"PIN-kood:"</string>
<string name="wifi_p2p_enabled_notification_title" msgid="2068321881673734886">"WiFi Direct on sees"</string>
<string name="wifi_p2p_enabled_notification_message" msgid="1638949953993894335">"Puuted seadete jaoks"</string>
<string name="select_character" msgid="3365550120617701745">"Sisesta tähemärk"</string>
@@ -976,7 +992,7 @@
<string name="sim_removed_message" msgid="2333164559970958645">"Mobiilsidevõrk ei ole saadaval, kuni sisestate kehtiva SIM-kaardi ja taaskäivitate seadme."</string>
<string name="sim_done_button" msgid="827949989369963775">"Valmis"</string>
<string name="sim_added_title" msgid="3719670512889674693">"SIM-kaart lisatud"</string>
- <string name="sim_added_message" msgid="1209265974048554242">"Mobiilsidevõrku pääsemiseks peate oma seadme taaskäivitama."</string>
+ <string name="sim_added_message" msgid="6599945301141050216">"Mobiilsidevõrku pääsemiseks taaskäivitage seade."</string>
<string name="sim_restart_button" msgid="4722407842815232347">"Taaskäivita"</string>
<string name="time_picker_dialog_title" msgid="8349362623068819295">"Kellaaja määramine"</string>
<string name="date_picker_dialog_title" msgid="5879450659453782278">"Kuupäeva määramine"</string>
@@ -985,31 +1001,31 @@
<string name="no_permissions" msgid="7283357728219338112">"Lube pole vaja"</string>
<string name="perms_hide" msgid="7283915391320676226"><b>"Peida"</b></string>
<string name="perms_show_all" msgid="2671791163933091180"><b>"Näita kõiki"</b></string>
- <string name="usb_storage_activity_title" msgid="2399289999608900443">"USB-massmälu"</string>
+ <string name="usb_storage_activity_title" msgid="4465055157209648641">"USB-massmälu"</string>
<string name="usb_storage_title" msgid="5901459041398751495">"USB ühendatud"</string>
- <string name="usb_storage_message" product="nosdcard" msgid="6631094834151575841">"Olete arvutiga USB kaudu ühendatud. Puudutage allolevat nuppu, kui soovite faile arvuti ja Androidi USB-mäluseadme vahel kopeerida."</string>
- <string name="usb_storage_message" product="default" msgid="4510858346516069238">"Olete arvutiga USB kaudu ühendatud. Puudutage allolevat nuppu, kui soovite faile arvuti ja Androidi SD-kaardi vahel kopeerida."</string>
+ <string name="usb_storage_message" product="nosdcard" msgid="3308538094316477839">"Teil on arvutiga ühendus USB kaudu. Puudutage allolevat nuppu, kui soovite faile arvuti ja Androidi USB-salvestusruumi vahel kopeerida."</string>
+ <string name="usb_storage_message" product="default" msgid="805351000446037811">"Olete arvutiga ühendatud USB kaudu. Puudutage allolevat nuppu, kui soovite faile arvuti ja Androidi SD-kaardi vahel kopeerida."</string>
<string name="usb_storage_button_mount" msgid="1052259930369508235">"Lülita USB-mäluseade sisse"</string>
- <string name="usb_storage_error_message" product="nosdcard" msgid="3276413764430468454">"Probleem USB-mäluseadme kasutamisel USB-mäluseadmena."</string>
- <string name="usb_storage_error_message" product="default" msgid="120810397713773275">"Probleem SD-kaardi kasutamisel USB-mäluseadmena."</string>
+ <string name="usb_storage_error_message" product="nosdcard" msgid="3017045217365540658">"Probleem USB-salvestusruumi kasutamisel USB-mäluseadmena."</string>
+ <string name="usb_storage_error_message" product="default" msgid="2876018512716970313">"Probleem SD-kaardi kasutamisel USB-mäluseadmena."</string>
<string name="usb_storage_notification_title" msgid="8175892554757216525">"USB ühendatud"</string>
- <string name="usb_storage_notification_message" msgid="7380082404288219341">"Valige failide kopeerimiseks arvutist/arvutisse."</string>
+ <string name="usb_storage_notification_message" msgid="939822783828183763">"Puudutage, et kopeerida faile arvutist/arvutisse."</string>
<string name="usb_storage_stop_notification_title" msgid="2336058396663516017">"Lülita USB-mäluseade välja"</string>
- <string name="usb_storage_stop_notification_message" msgid="2591813490269841539">"Valige USB-mäluseadme väljalülitamiseks."</string>
+ <string name="usb_storage_stop_notification_message" msgid="1656852098555623822">"USB-salvestusruumi väljalülitamiseks puudutage."</string>
<string name="usb_storage_stop_title" msgid="660129851708775853">"USB kasutusel"</string>
- <string name="usb_storage_stop_message" product="nosdcard" msgid="1368842269463745067">"Enne USB-mäluseadme väljalülitamist veenduge, et olete oma Androidi USB-mäluseadme arvutist eemaldanud (väljutanud)."</string>
- <string name="usb_storage_stop_message" product="default" msgid="3613713396426604104">"Enne USB-seadme väljalülitamist veenduge, et olete oma Androidi SD-kaardi arvutist eemaldanud (“väljutanud“)."</string>
+ <string name="usb_storage_stop_message" product="nosdcard" msgid="4264025280777219521">"Enne USB-salvestusruumi väljalülitamist eraldage (väljutage) Androidi USB-salvestusruum arvutist."</string>
+ <string name="usb_storage_stop_message" product="default" msgid="8043969782460613114">"Enne USB-salvestusruumi väljalülitamist eemaldage (väljutage) Androidi SD-kaart arvutist."</string>
<string name="usb_storage_stop_button_mount" msgid="7060218034900696029">"Lülita USB-mäluseade välja"</string>
- <string name="usb_storage_stop_error_message" msgid="143881914840412108">"USB-mäluseadme väljalülitamisel ilmnes probleem. Veenduge, et olete USB-hosti eemaldanud ja proovige siis uuesti."</string>
+ <string name="usb_storage_stop_error_message" msgid="1970374898263063836">"Tekkis probleem USB-salvestusruumi väljalülitamisega. Kontrollige, kas olete USB-hosti eemaldanud, ja proovige seejärel uuesti."</string>
<string name="dlg_confirm_kill_storage_users_title" msgid="963039033470478697">"Lülita USB-mäluseade sisse"</string>
- <string name="dlg_confirm_kill_storage_users_text" msgid="6206212680430268343">"USB-seadme sisselülitamisel peatuvad mõned teie kasutatavad rakendused ja on võimalik, et neid ei saa kasutada seni, kuni USB-seadme välja lülitate."</string>
+ <string name="dlg_confirm_kill_storage_users_text" msgid="5100428757107469454">"Kui lülitate USB-salvestusruumi sisse, võivad mõned kasutatavad rakendused peatuda ega pruugi olla saadaval enne USB-salvestusruumi väljalülitamist."</string>
<string name="dlg_error_title" msgid="7323658469626514207">"USB toiming ebaõnnestus"</string>
<string name="dlg_ok" msgid="7376953167039865701">"OK"</string>
<string name="usb_mtp_notification_title" msgid="3699913097391550394">"Ühendatud meediumiseadmena"</string>
<string name="usb_ptp_notification_title" msgid="1960817192216064833">"Ühendatud kaamerana"</string>
<string name="usb_cd_installer_notification_title" msgid="6774712827892090754">"Ühendatud installijana"</string>
<string name="usb_accessory_notification_title" msgid="7848236974087653666">"Ühendatud USB-lisaseadmega"</string>
- <string name="usb_notification_message" msgid="4447869605109736382">"Puudutage teiste USB-valikute kuvamiseks"</string>
+ <string name="usb_notification_message" msgid="2290859399983720271">"Puudutage teisi USB valikuid."</string>
<string name="extmedia_format_title" product="nosdcard" msgid="9020092196061007262">"Vormind. USB-seade?"</string>
<string name="extmedia_format_title" product="default" msgid="3648415921526526069">"Kas vormindada SD-kaart?"</string>
<string name="extmedia_format_message" product="nosdcard" msgid="3934016853425761078">"Kõik USB-mäluseadmele salvestatud failid kustutatakse. Seda toimingut ei saa tagasi võtta."</string>
@@ -1027,12 +1043,12 @@
<string name="ext_media_checking_notification_message" msgid="8287319882926737053">"Vigade kontrollimine."</string>
<string name="ext_media_nofs_notification_title" product="nosdcard" msgid="7788040745686229307">"Tühi USB-mäluseade"</string>
<string name="ext_media_nofs_notification_title" product="default" msgid="780477838241212997">"Tühi SD-kaart"</string>
- <string name="ext_media_nofs_notification_message" product="nosdcard" msgid="8623130522556087311">"USB-mäluseade on tühi või toetuseta failisüsteemiga."</string>
- <string name="ext_media_nofs_notification_message" product="default" msgid="3817704088027829380">"SD-kaart on tühi või toetuseta failisüsteemiga."</string>
+ <string name="ext_media_nofs_notification_message" product="nosdcard" msgid="7840121067427269500">"USB-salvestusruum on tühi või ei toeta failisüsteemi."</string>
+ <string name="ext_media_nofs_notification_message" product="default" msgid="8641065641786923604">"SD-kaart on tühi või ei toetata selle failisüsteemi."</string>
<string name="ext_media_unmountable_notification_title" product="nosdcard" msgid="2090046769532713563">"Kahjustatud USB-mäluseade"</string>
<string name="ext_media_unmountable_notification_title" product="default" msgid="6410723906019100189">"Kahjustatud SD-kaart"</string>
- <string name="ext_media_unmountable_notification_message" product="nosdcard" msgid="529021299294450667">"USB-mäluseade on kahjustatud. Võib-olla peate selle uuesti vormindama."</string>
- <string name="ext_media_unmountable_notification_message" product="default" msgid="6902531775948238989">"SD-kaart on kahjustatud. Võib-olla peale selle uuesti vormindama."</string>
+ <string name="ext_media_unmountable_notification_message" product="nosdcard" msgid="1795917578395333280">"USB-salvestusruum on kahjustatud. Proovige uuesti vormindada."</string>
+ <string name="ext_media_unmountable_notification_message" product="default" msgid="1753898567525568253">"SD-kaart on kahjustatud. Proovige uuesti vormindada."</string>
<string name="ext_media_badremoval_notification_title" product="nosdcard" msgid="1661683031330951073">"USB-seade eemaldati ootamatult"</string>
<string name="ext_media_badremoval_notification_title" product="default" msgid="6872152882604407837">"SD-kaart on ootamatult eemaldatud"</string>
<string name="ext_media_badremoval_notification_message" product="nosdcard" msgid="4329848819865594241">"Andmekao vältimiseks lahutage USB-mäluseade enne eemaldamist."</string>
@@ -1045,13 +1061,13 @@
<string name="ext_media_nomedia_notification_title" product="default" msgid="8902518030404381318">"Eemaldatud SD-kaart"</string>
<string name="ext_media_nomedia_notification_message" product="nosdcard" msgid="6921126162580574143">"USB-mäluseade eemaldatud. Sisestage uus meedium."</string>
<string name="ext_media_nomedia_notification_message" product="default" msgid="3870120652983659641">"SD-kaart on eemaldatud. Sisestage uus."</string>
- <string name="activity_list_empty" msgid="4168820609403385789">"Sobivat tegevust ei leitud"</string>
+ <string name="activity_list_empty" msgid="1675388330786841066">"Sobivat tegevust ei leitud"</string>
<string name="permlab_pkgUsageStats" msgid="8787352074326748892">"värskenda komponentide kasutusstatistikat"</string>
<string name="permdesc_pkgUsageStats" msgid="1106612424254277630">"Võimaldab rakendusel muuta komponendi kohta kogutud kasutusstatistikat. Mitte kasutada tavarakenduste puhul."</string>
<string name="permlab_copyProtectedData" msgid="4341036311211406692">"Sisu kopeerimine"</string>
<string name="permdesc_copyProtectedData" msgid="4390697124288317831">"Võimaldab rakendusel võtta sisu kopeerimiseks appi vaikekonteinerteenuse. Mitte kasutada tavarakenduste puhul."</string>
<string name="tutorial_double_tap_to_zoom_message_short" msgid="4070433208160063538">"Suumi juhtimiseks puudutage kaks korda"</string>
- <string name="gadget_host_error_inflating" msgid="2613287218853846830">"Viga vidina täitmisel"</string>
+ <string name="gadget_host_error_inflating" msgid="4882004314906466162">"Vidinat ei saanud lisada."</string>
<string name="ime_action_go" msgid="8320845651737369027">"Mine"</string>
<string name="ime_action_search" msgid="658110271822807811">"Otsing"</string>
<string name="ime_action_send" msgid="2316166556349314424">"Saada"</string>
@@ -1063,35 +1079,35 @@
<string name="create_contact_using" msgid="4947405226788104538">"Loo kontakt"\n"numbriga <xliff:g id="NUMBER">%s</xliff:g>"</string>
<string name="grant_credentials_permission_message_header" msgid="2106103817937859662">"Üks või mitu rakendust taotlevad luba pääseda nüüd ja edaspidi teie kontole juurde."</string>
<string name="grant_credentials_permission_message_footer" msgid="3125211343379376561">"Kas soovite taotluse lubada?"</string>
- <string name="grant_permissions_header_text" msgid="2722567482180797717">"Juurdepääsutaotlus"</string>
+ <string name="grant_permissions_header_text" msgid="6874497408201826708">"Juurdepääsutaotlus"</string>
<string name="allow" msgid="7225948811296386551">"Luba"</string>
<string name="deny" msgid="2081879885755434506">"Keela"</string>
- <string name="permission_request_notification_title" msgid="5390555465778213840">"Luba taotletud"</string>
- <string name="permission_request_notification_with_subtitle" msgid="4325409589686688000">"Luba taotletud"\n"kontole <xliff:g id="ACCOUNT">%s</xliff:g>"</string>
+ <string name="permission_request_notification_title" msgid="6486759795926237907">"Taotletud luba"</string>
+ <string name="permission_request_notification_with_subtitle" msgid="8530393139639560189">"Luba on taotletud"\n"kontole <xliff:g id="ACCOUNT">%s</xliff:g>."</string>
<string name="input_method_binding_label" msgid="1283557179944992649">"Sisestusmeetod"</string>
<string name="sync_binding_label" msgid="3687969138375092423">"Sünkroonimine"</string>
<string name="accessibility_binding_label" msgid="4148120742096474641">"Juurdepääsetavus"</string>
<string name="wallpaper_binding_label" msgid="1240087844304687662">"Taustapilt"</string>
<string name="chooser_wallpaper" msgid="7873476199295190279">"Muutke taustapilti"</string>
- <string name="vpn_title" msgid="8219003246858087489">"VPN on aktiveeritud."</string>
+ <string name="vpn_title" msgid="19615213552042827">"VPN on aktiveeritud"</string>
<string name="vpn_title_long" msgid="6400714798049252294">"VPN-i aktiveeris <xliff:g id="APP">%s</xliff:g>"</string>
- <string name="vpn_text" msgid="1610714069627824309">"Koputage võrgu haldamiseks."</string>
- <string name="vpn_text_long" msgid="4907843483284977618">"Ühendatud seansiga <xliff:g id="SESSION">%s</xliff:g>. Koputage võrgu haldamiseks"</string>
+ <string name="vpn_text" msgid="3011306607126450322">"Võrgu haldamiseks puudutage."</string>
+ <string name="vpn_text_long" msgid="6407351006249174473">"Ühendatud seansiga <xliff:g id="SESSION">%s</xliff:g>. Võrgu haldamiseks puudutage."</string>
<string name="upload_file" msgid="2897957172366730416">"Valige fail"</string>
<string name="no_file_chosen" msgid="6363648562170759465">"Ühtegi faili pole valitud"</string>
<string name="reset" msgid="2448168080964209908">"Lähtesta"</string>
<string name="submit" msgid="1602335572089911941">"Saada"</string>
<string name="car_mode_disable_notification_title" msgid="3164768212003864316">"Autorežiim lubatud"</string>
- <string name="car_mode_disable_notification_message" msgid="668663626721675614">"Valige autorežiimist väljumiseks."</string>
+ <string name="car_mode_disable_notification_message" msgid="8035230537563503262">"Autorežiimist väljumiseks puudutage."</string>
<string name="tethered_notification_title" msgid="3146694234398202601">"Jagamine või tööpunkt on aktiivne"</string>
- <string name="tethered_notification_message" msgid="3067108323903048927">"Puudutage seadistamiseks"</string>
+ <string name="tethered_notification_message" msgid="6857031760103062982">"Seadistamiseks puudutage."</string>
<string name="back_button_label" msgid="2300470004503343439">"Tagasi"</string>
<string name="next_button_label" msgid="1080555104677992408">"Järgmine"</string>
<string name="skip_button_label" msgid="1275362299471631819">"Jäta vahele"</string>
<string name="throttle_warning_notification_title" msgid="4890894267454867276">"Kõrge mobiilse andmeside kasutus"</string>
- <string name="throttle_warning_notification_message" msgid="2609734763845705708">"Puudutage, et saada lisateavet mobiilse andmeside kasutamise kohta"</string>
+ <string name="throttle_warning_notification_message" msgid="3340822228599337743">"Mobiilse andmeside kasutamise kohta lisateabe saamiseks puudutage."</string>
<string name="throttled_notification_title" msgid="6269541897729781332">"Mobiili andmemahupiirang ületatud"</string>
- <string name="throttled_notification_message" msgid="4712369856601275146">"Puudutage, et saada lisateavet mobiilse andmeside kasutamise kohta"</string>
+ <string name="throttled_notification_message" msgid="5443457321354907181">"Mobiilse andmeside kasutamise kohta lisateabe saamiseks puudutage."</string>
<string name="no_matches" msgid="8129421908915840737">"Vasted puuduvad"</string>
<string name="find_on_page" msgid="1946799233822820384">"Otsige lehelt"</string>
<plurals name="matches_found">
@@ -1099,10 +1115,10 @@
<item quantity="other" msgid="4641872797067609177">"<xliff:g id="INDEX">%d</xliff:g>/<xliff:g id="TOTAL">%d</xliff:g>"</item>
</plurals>
<string name="action_mode_done" msgid="7217581640461922289">"Valmis"</string>
- <string name="progress_unmounting" product="nosdcard" msgid="535863554318797377">"USB-mäluseadme lahutamine ..."</string>
- <string name="progress_unmounting" product="default" msgid="5556813978958789471">"SD-kaardi lahutamine ..."</string>
- <string name="progress_erasing" product="nosdcard" msgid="4183664626203056915">"USB-mäluseadme kustutamine ..."</string>
- <string name="progress_erasing" product="default" msgid="2115214724367534095">"SD-kaardi kustutamine ..."</string>
+ <string name="progress_unmounting" product="nosdcard" msgid="3923810448507612746">"USB-salvestusruumi eemaldamine ..."</string>
+ <string name="progress_unmounting" product="default" msgid="1327894998409537190">"SD-kaardi eemaldamine ..."</string>
+ <string name="progress_erasing" product="nosdcard" msgid="4521573321524340058">"USB-salvestusruumi kustutamine ..."</string>
+ <string name="progress_erasing" product="default" msgid="6596988875507043042">"SD-kaardi kustutamine ..."</string>
<string name="format_error" product="nosdcard" msgid="6299769563624776948">"USB-mäluseadme tühjendamine ebaõnnestus."</string>
<string name="format_error" product="default" msgid="7315248696644510935">"SD-kaardi kustutamine ebaõnnestus."</string>
<string name="media_bad_removal" msgid="7960864061016603281">"SD-kaart eemaldati enne lahutamist."</string>
@@ -1121,17 +1137,17 @@
<string name="gpsVerifYes" msgid="2346566072867213563">"Jah"</string>
<string name="gpsVerifNo" msgid="1146564937346454865">"Ei"</string>
<string name="sync_too_many_deletes" msgid="5296321850662746890">"Kustutamiste piirarv on ületatud"</string>
- <string name="sync_too_many_deletes_desc" msgid="7030265992955132593">"Sünkroonimise tüübi <xliff:g id="TYPE_OF_SYNC">%2$s</xliff:g> konto <xliff:g id="ACCOUNT_NAME">%3$s</xliff:g> kohta on <xliff:g id="NUMBER_OF_DELETED_ITEMS">%1$d</xliff:g> kustutatud üksust. Mida te teha sooviksite?"</string>
- <string name="sync_really_delete" msgid="8933566316059338692">"Kustuta üksused."</string>
- <string name="sync_undo_deletes" msgid="8610996708225006328">"Kustutamiste tagasivõtmine"</string>
- <string name="sync_do_nothing" msgid="8717589462945226869">"Ära tee praegu midagi."</string>
+ <string name="sync_too_many_deletes_desc" msgid="496551671008694245">"Kustutatavad üksused kontol <xliff:g id="ACCOUNT_NAME">%3$s</xliff:g> sünkroonimistüübi <xliff:g id="TYPE_OF_SYNC">%2$s</xliff:g> jaoks: <xliff:g id="NUMBER_OF_DELETED_ITEMS">%1$d</xliff:g>. Mida soovite teha?"</string>
+ <string name="sync_really_delete" msgid="2572600103122596243">"Kustuta üksused"</string>
+ <string name="sync_undo_deletes" msgid="2941317360600338602">"Võtke kustutamised tagasi"</string>
+ <string name="sync_do_nothing" msgid="3743764740430821845">"Ära tee praegu midagi"</string>
<string name="choose_account_label" msgid="5655203089746423927">"Konto valimine"</string>
<string name="add_account_label" msgid="2935267344849993553">"Konto lisamine"</string>
- <string name="choose_account_text" msgid="6891230675141555481">"Millist kontot sooviksite kasutada?"</string>
+ <string name="choose_account_text" msgid="6303348737197849675">"Millist kontot soovite kasutada?"</string>
<string name="add_account_button_label" msgid="3611982894853435874">"Lisa konto"</string>
<string name="number_picker_increment_button" msgid="4830170763103463443">"Suurenda"</string>
<string name="number_picker_decrement_button" msgid="2576606679160067262">"Vähenda"</string>
- <string name="number_picker_increment_scroll_mode" msgid="1343063395404990189">"<xliff:g id="VALUE">%s</xliff:g> – puudutage ja hoidke all."</string>
+ <string name="number_picker_increment_scroll_mode" msgid="3073101067441638428">"<xliff:g id="VALUE">%s</xliff:g> puudutage ja hoidke."</string>
<string name="number_picker_increment_scroll_action" msgid="4628981789985093179">"Suurendamiseks lohistage üles, vähendamiseks alla."</string>
<string name="time_picker_increment_minute_button" msgid="2843066823236250329">"Minutite arvu suurendamine"</string>
<string name="time_picker_decrement_minute_button" msgid="4357907223628449595">"Minutite arvu vähendamine"</string>
@@ -1173,29 +1189,29 @@
<string name="description_target_silent" msgid="893551287746522182">"Hääletu"</string>
<string name="description_target_soundon" msgid="30052466675500172">"Heli on sees"</string>
<string name="description_target_unlock_tablet" msgid="3833195335629795055">"Avamiseks tõmmake sõrmega."</string>
- <string name="keyboard_headset_required_to_hear_password" msgid="5913502399391940888">"Ühendage peakomplekt, et kuulata paroole."</string>
+ <string name="keyboard_headset_required_to_hear_password" msgid="7011927352267668657">"Paroolide kuulamiseks ühendage peakomplekt."</string>
<string name="keyboard_password_character_no_headset" msgid="2859873770886153678">"Punkt."</string>
<string name="action_bar_home_description" msgid="5293600496601490216">"Liigu avalehele"</string>
<string name="action_bar_up_description" msgid="2237496562952152589">"Liigu üles"</string>
<string name="action_menu_overflow_description" msgid="2295659037509008453">"Rohkem valikuid"</string>
- <string name="storage_internal" msgid="7556050805474115618">"Sisemälu"</string>
- <string name="storage_sd_card" msgid="8921771478629812343">"SD-kaart"</string>
+ <string name="storage_internal" msgid="4891916833657929263">"Sisemine salvestusruum"</string>
+ <string name="storage_sd_card" msgid="3282948861378286745">"SD-kaart"</string>
<string name="storage_usb" msgid="3017954059538517278">"USB-mäluseade"</string>
- <string name="extract_edit_menu_button" msgid="302060189057163906">"Muuda ..."</string>
+ <string name="extract_edit_menu_button" msgid="8940478730496610137">"Muuda"</string>
<string name="data_usage_warning_title" msgid="1955638862122232342">"Andmete kasutamise hoiatus"</string>
- <string name="data_usage_warning_body" msgid="7217480745540055170">"Kas./sätete vaatamiseks puud.-ge"</string>
+ <string name="data_usage_warning_body" msgid="2814673551471969954">"Kasutuse/sätete vaat. puudutage."</string>
<string name="data_usage_3g_limit_title" msgid="7093334419518706686">"2G–3G-andmeside on keelatud"</string>
<string name="data_usage_4g_limit_title" msgid="7636489436819470761">"4G-andmeside on keelatud"</string>
<string name="data_usage_mobile_limit_title" msgid="7869402519391631884">"Mobiilne andmeside on keelatud"</string>
<string name="data_usage_wifi_limit_title" msgid="8992154736441284865">"WiFi-andmed on keelatud"</string>
- <string name="data_usage_limit_body" msgid="4313857592916426843">"Puudutage lubamiseks"</string>
+ <string name="data_usage_limit_body" msgid="3317964706973601386">"Lubamiseks puudutage."</string>
<string name="data_usage_3g_limit_snoozed_title" msgid="7026739121138005231">"2G-3G andmemahupiirang ületatud"</string>
<string name="data_usage_4g_limit_snoozed_title" msgid="1106562779311209039">"4G andmemahupiirang ületatud"</string>
<string name="data_usage_mobile_limit_snoozed_title" msgid="279240572165412168">"Mobiilne andmemahupiirang ületatud"</string>
<string name="data_usage_wifi_limit_snoozed_title" msgid="8743856006384825974">"WiFi-andmete piir on ületatud"</string>
- <string name="data_usage_limit_snoozed_body" msgid="2932736326652880660">"<xliff:g id="SIZE">%s</xliff:g> üle kindlaksmääratud piirmäära"</string>
+ <string name="data_usage_limit_snoozed_body" msgid="7035490278298441767">"<xliff:g id="SIZE">%s</xliff:g> üle määratud piirmäära."</string>
<string name="data_usage_restricted_title" msgid="5965157361036321914">"Taustandmed on piiratud"</string>
- <string name="data_usage_restricted_body" msgid="5087354814839059798">"Puudutage piirangu eemaldamiseks"</string>
+ <string name="data_usage_restricted_body" msgid="6741521330997452990">"Piirangu eemaldamiseks puudut."</string>
<string name="ssl_certificate" msgid="6510040486049237639">"Turvasertifikaat"</string>
<string name="ssl_certificate_is_valid" msgid="6825263250774569373">"See sertifikaat on kehtiv."</string>
<string name="issued_to" msgid="454239480274921032">"Väljastatud subjektile:"</string>
@@ -1212,7 +1228,10 @@
<string name="sha1_fingerprint" msgid="7930330235269404581">"SHA-1 sõrmejälg:"</string>
<string name="activity_chooser_view_see_all" msgid="4292569383976636200">"Kuva kõik"</string>
<string name="activity_chooser_view_dialog_title_default" msgid="4710013864974040615">"Tegevuse valimine"</string>
- <string name="share_action_provider_share_with" msgid="5247684435979149216">"Jagamine kasutajaga"</string>
+ <string name="share_action_provider_share_with" msgid="5247684435979149216">"Jagamine rakendusega:"</string>
<string name="status_bar_device_locked" msgid="3092703448690669768">"Seade lukustatud."</string>
<string name="list_delimeter" msgid="3975117572185494152">", "</string>
+ <string name="sending" msgid="3245653681008218030">"Saatmine ..."</string>
+ <string name="launchBrowserDefault" msgid="2057951947297614725">"Kas käivitada brauser?"</string>
+ <string name="SetupCallDefault" msgid="5834948469253758575">"Kas vastata kõnele?"</string>
</resources>
diff --git a/core/res/res/values-fa/strings.xml b/core/res/res/values-fa/strings.xml
index e2448f9..7097e43 100644
--- a/core/res/res/values-fa/strings.xml
+++ b/core/res/res/values-fa/strings.xml
@@ -915,6 +915,7 @@
<string name="force_close" msgid="8346072094521265605">"تأیید"</string>
<string name="report" msgid="4060218260984795706">"گزارش"</string>
<string name="wait" msgid="7147118217226317732">"منتظر بمانید"</string>
+ <string name="webpage_unresponsive" msgid="3272758351138122503">"این صفحه پاسخ نمیدهد."\n\n"آیا میخواهید آن را ببندید؟"</string>
<string name="launch_warning_title" msgid="1547997780506713581">"برنامه مجدداً هدایت شد"</string>
<string name="launch_warning_replace" msgid="6202498949970281412">"<xliff:g id="APP_NAME">%1$s</xliff:g> اکنون در حال اجرا است."</string>
<string name="launch_warning_original" msgid="188102023021668683">"<xliff:g id="APP_NAME">%1$s</xliff:g> از ابتدا راه اندازی شد."</string>
diff --git a/core/res/res/values-fi/strings.xml b/core/res/res/values-fi/strings.xml
index 27a9bf4..0a60adb 100644
--- a/core/res/res/values-fi/strings.xml
+++ b/core/res/res/values-fi/strings.xml
@@ -915,6 +915,7 @@
<string name="force_close" msgid="8346072094521265605">"OK"</string>
<string name="report" msgid="4060218260984795706">"Ilmoita"</string>
<string name="wait" msgid="7147118217226317732">"Odota"</string>
+ <string name="webpage_unresponsive" msgid="3272758351138122503">"Sivu ei vastaa."\n\n"Haluatko sulkea sen?"</string>
<string name="launch_warning_title" msgid="1547997780506713581">"Sovelluksen uud.ohjaus"</string>
<string name="launch_warning_replace" msgid="6202498949970281412">"<xliff:g id="APP_NAME">%1$s</xliff:g> on nyt käynnissä."</string>
<string name="launch_warning_original" msgid="188102023021668683">"<xliff:g id="APP_NAME">%1$s</xliff:g> käynnistettiin alun perin."</string>
diff --git a/core/res/res/values-fr/strings.xml b/core/res/res/values-fr/strings.xml
index c647570..d32f487 100644
--- a/core/res/res/values-fr/strings.xml
+++ b/core/res/res/values-fr/strings.xml
@@ -915,6 +915,7 @@
<string name="force_close" msgid="8346072094521265605">"OK"</string>
<string name="report" msgid="4060218260984795706">"Rapport"</string>
<string name="wait" msgid="7147118217226317732">"Attendre"</string>
+ <string name="webpage_unresponsive" msgid="3272758351138122503">"La page ne répond pas."\n" "\n"Voulez-vous la fermer ?"</string>
<string name="launch_warning_title" msgid="1547997780506713581">"Application redirigée"</string>
<string name="launch_warning_replace" msgid="6202498949970281412">"<xliff:g id="APP_NAME">%1$s</xliff:g> est maintenant lancée."</string>
<string name="launch_warning_original" msgid="188102023021668683">"Application lancée initialement : <xliff:g id="APP_NAME">%1$s</xliff:g>."</string>
diff --git a/core/res/res/values-hi/strings.xml b/core/res/res/values-hi/strings.xml
index 3e440ca..7a4f706 100644
--- a/core/res/res/values-hi/strings.xml
+++ b/core/res/res/values-hi/strings.xml
@@ -915,6 +915,7 @@
<string name="force_close" msgid="8346072094521265605">"ठीक"</string>
<string name="report" msgid="4060218260984795706">"रिपोर्ट करें"</string>
<string name="wait" msgid="7147118217226317732">"प्रतीक्षा करें"</string>
+ <string name="webpage_unresponsive" msgid="3272758351138122503">"पृष्ठ प्रतिसाद नहीं दे रहा है."\n\n"क्या आप इसे बंद करना चाहते हैं?"</string>
<string name="launch_warning_title" msgid="1547997780506713581">"एप्लि. रीडायरेक्ट किया गया"</string>
<string name="launch_warning_replace" msgid="6202498949970281412">"<xliff:g id="APP_NAME">%1$s</xliff:g> अभी चल रहा है."</string>
<string name="launch_warning_original" msgid="188102023021668683">"<xliff:g id="APP_NAME">%1$s</xliff:g> को वास्तविक रूप से लॉन्च किया गया था."</string>
diff --git a/core/res/res/values-hr/strings.xml b/core/res/res/values-hr/strings.xml
index 460ec88..e37be22 100644
--- a/core/res/res/values-hr/strings.xml
+++ b/core/res/res/values-hr/strings.xml
@@ -915,6 +915,7 @@
<string name="force_close" msgid="8346072094521265605">"U redu"</string>
<string name="report" msgid="4060218260984795706">"Izvješće"</string>
<string name="wait" msgid="7147118217226317732">"Pričekaj"</string>
+ <string name="webpage_unresponsive" msgid="3272758351138122503">"Stranica ne reagira."\n\n"Želite li ju zatvoriti?"</string>
<string name="launch_warning_title" msgid="1547997780506713581">"Aplikacija preusmjerena"</string>
<string name="launch_warning_replace" msgid="6202498949970281412">"<xliff:g id="APP_NAME">%1$s</xliff:g> se izvodi sada."</string>
<string name="launch_warning_original" msgid="188102023021668683">"Aplikacija <xliff:g id="APP_NAME">%1$s</xliff:g> pokrenuta je prva."</string>
diff --git a/core/res/res/values-hu/strings.xml b/core/res/res/values-hu/strings.xml
index 9278bde..9b3eb54 100644
--- a/core/res/res/values-hu/strings.xml
+++ b/core/res/res/values-hu/strings.xml
@@ -915,6 +915,7 @@
<string name="force_close" msgid="8346072094521265605">"OK"</string>
<string name="report" msgid="4060218260984795706">"Jelentés"</string>
<string name="wait" msgid="7147118217226317732">"Várakozás"</string>
+ <string name="webpage_unresponsive" msgid="3272758351138122503">"Az oldal nem válaszol."\n\n"Szeretné bezárni?"</string>
<string name="launch_warning_title" msgid="1547997780506713581">"Alkalmazás átirányítva"</string>
<string name="launch_warning_replace" msgid="6202498949970281412">"<xliff:g id="APP_NAME">%1$s</xliff:g> éppen fut."</string>
<string name="launch_warning_original" msgid="188102023021668683">"<xliff:g id="APP_NAME">%1$s</xliff:g> volt eredetileg elindítva."</string>
diff --git a/core/res/res/values-in/strings.xml b/core/res/res/values-in/strings.xml
index 30fb875..b61fb42 100644
--- a/core/res/res/values-in/strings.xml
+++ b/core/res/res/values-in/strings.xml
@@ -915,6 +915,7 @@
<string name="force_close" msgid="8346072094521265605">"OK"</string>
<string name="report" msgid="4060218260984795706">"Laporkan"</string>
<string name="wait" msgid="7147118217226317732">"Tunggu"</string>
+ <string name="webpage_unresponsive" msgid="3272758351138122503">"Laman ini tidak menanggapi."\n\n"Apakah Anda ingin menutupnya?"</string>
<string name="launch_warning_title" msgid="1547997780506713581">"Apl dialihkan"</string>
<string name="launch_warning_replace" msgid="6202498949970281412">"<xliff:g id="APP_NAME">%1$s</xliff:g> sedang berjalan."</string>
<string name="launch_warning_original" msgid="188102023021668683">"<xliff:g id="APP_NAME">%1$s</xliff:g> telah diluncurkan aslinya."</string>
diff --git a/core/res/res/values-it/strings.xml b/core/res/res/values-it/strings.xml
index 2cc182f..ebf7223 100644
--- a/core/res/res/values-it/strings.xml
+++ b/core/res/res/values-it/strings.xml
@@ -915,6 +915,7 @@
<string name="force_close" msgid="8346072094521265605">"OK"</string>
<string name="report" msgid="4060218260984795706">"Segnala"</string>
<string name="wait" msgid="7147118217226317732">"Attendi"</string>
+ <string name="webpage_unresponsive" msgid="3272758351138122503">"La pagina non risponde più."\n\n"Vuoi chiuderla?"</string>
<string name="launch_warning_title" msgid="1547997780506713581">"Applicazione reindirizzata"</string>
<string name="launch_warning_replace" msgid="6202498949970281412">"<xliff:g id="APP_NAME">%1$s</xliff:g> è ora in esecuzione."</string>
<string name="launch_warning_original" msgid="188102023021668683">"<xliff:g id="APP_NAME">%1$s</xliff:g> già avviata."</string>
diff --git a/core/res/res/values-iw/strings.xml b/core/res/res/values-iw/strings.xml
index e9dd004..69d506e 100644
--- a/core/res/res/values-iw/strings.xml
+++ b/core/res/res/values-iw/strings.xml
@@ -915,6 +915,7 @@
<string name="force_close" msgid="8346072094521265605">"אישור"</string>
<string name="report" msgid="4060218260984795706">"שלח דוח"</string>
<string name="wait" msgid="7147118217226317732">"המתן"</string>
+ <string name="webpage_unresponsive" msgid="3272758351138122503">"הדף אינו מגיב."\n\n"האם אתה רוצה לסגור אותו?"</string>
<string name="launch_warning_title" msgid="1547997780506713581">"הפנייה מחדש של יישום"</string>
<string name="launch_warning_replace" msgid="6202498949970281412">"<xliff:g id="APP_NAME">%1$s</xliff:g> פועל כעת."</string>
<string name="launch_warning_original" msgid="188102023021668683">"<xliff:g id="APP_NAME">%1$s</xliff:g> הופעל במקור."</string>
diff --git a/core/res/res/values-ja/strings.xml b/core/res/res/values-ja/strings.xml
index 234f64c..cb958e4 100644
--- a/core/res/res/values-ja/strings.xml
+++ b/core/res/res/values-ja/strings.xml
@@ -915,6 +915,7 @@
<string name="force_close" msgid="8346072094521265605">"OK"</string>
<string name="report" msgid="4060218260984795706">"レポート"</string>
<string name="wait" msgid="7147118217226317732">"待機"</string>
+ <string name="webpage_unresponsive" msgid="3272758351138122503">"ページが応答しません。"\n\n"ページを閉じますか?"</string>
<string name="launch_warning_title" msgid="1547997780506713581">"アプリのリダイレクト"</string>
<string name="launch_warning_replace" msgid="6202498949970281412">"<xliff:g id="APP_NAME">%1$s</xliff:g>が実行中です。"</string>
<string name="launch_warning_original" msgid="188102023021668683">"<xliff:g id="APP_NAME">%1$s</xliff:g>が最初に起動していました。"</string>
diff --git a/core/res/res/values-ko/strings.xml b/core/res/res/values-ko/strings.xml
index 804110c..216ac76 100644
--- a/core/res/res/values-ko/strings.xml
+++ b/core/res/res/values-ko/strings.xml
@@ -915,6 +915,7 @@
<string name="force_close" msgid="8346072094521265605">"확인"</string>
<string name="report" msgid="4060218260984795706">"신고"</string>
<string name="wait" msgid="7147118217226317732">"대기"</string>
+ <string name="webpage_unresponsive" msgid="3272758351138122503">"페이지가 응답하지 않습니다."\n\n"페이지를 닫으시겠습니까?"</string>
<string name="launch_warning_title" msgid="1547997780506713581">"앱 리디렉션됨"</string>
<string name="launch_warning_replace" msgid="6202498949970281412">"<xliff:g id="APP_NAME">%1$s</xliff:g>이(가) 실행 중입니다."</string>
<string name="launch_warning_original" msgid="188102023021668683">"원래 <xliff:g id="APP_NAME">%1$s</xliff:g>을(를) 실행했습니다."</string>
diff --git a/core/res/res/values-lt/strings.xml b/core/res/res/values-lt/strings.xml
index 9d6bd77..7f0370f 100644
--- a/core/res/res/values-lt/strings.xml
+++ b/core/res/res/values-lt/strings.xml
@@ -915,6 +915,7 @@
<string name="force_close" msgid="8346072094521265605">"Gerai"</string>
<string name="report" msgid="4060218260984795706">"Ataskaita"</string>
<string name="wait" msgid="7147118217226317732">"Palaukti"</string>
+ <string name="webpage_unresponsive" msgid="3272758351138122503">"Puslapis neatsako."\n\n"Ar norite jį uždaryti?"</string>
<string name="launch_warning_title" msgid="1547997780506713581">"Programa peradresuota"</string>
<string name="launch_warning_replace" msgid="6202498949970281412">"„<xliff:g id="APP_NAME">%1$s</xliff:g>“ dabar vykdoma."</string>
<string name="launch_warning_original" msgid="188102023021668683">"„<xliff:g id="APP_NAME">%1$s</xliff:g>“ buvo iš pradžių paleista."</string>
diff --git a/core/res/res/values-lv/strings.xml b/core/res/res/values-lv/strings.xml
index 195059c..a052481 100644
--- a/core/res/res/values-lv/strings.xml
+++ b/core/res/res/values-lv/strings.xml
@@ -915,6 +915,7 @@
<string name="force_close" msgid="8346072094521265605">"Labi"</string>
<string name="report" msgid="4060218260984795706">"Pārskats"</string>
<string name="wait" msgid="7147118217226317732">"Gaidīt"</string>
+ <string name="webpage_unresponsive" msgid="3272758351138122503">"No lapas netiek saņemta atbilde."\n\n"Vai vēlaties to aizvērt?"</string>
<string name="launch_warning_title" msgid="1547997780506713581">"Lietotne ir novirzīta"</string>
<string name="launch_warning_replace" msgid="6202498949970281412">"<xliff:g id="APP_NAME">%1$s</xliff:g> tagad darbojas."</string>
<string name="launch_warning_original" msgid="188102023021668683">"Sākotnēji tika palaista lietojumprogramma <xliff:g id="APP_NAME">%1$s</xliff:g>."</string>
diff --git a/core/res/res/values-ms/strings.xml b/core/res/res/values-ms/strings.xml
index a8e733f..f6189f2 100644
--- a/core/res/res/values-ms/strings.xml
+++ b/core/res/res/values-ms/strings.xml
@@ -915,6 +915,7 @@
<string name="force_close" msgid="8346072094521265605">"OK"</string>
<string name="report" msgid="4060218260984795706">"Laporkan"</string>
<string name="wait" msgid="7147118217226317732">"Tunggu"</string>
+ <string name="webpage_unresponsive" msgid="3272758351138122503">"Laman ini tidak bertindak balas. "\n\n"Adakah anda mahu menutupnya?"</string>
<string name="launch_warning_title" msgid="1547997780506713581">"Apl diubah hala"</string>
<string name="launch_warning_replace" msgid="6202498949970281412">"<xliff:g id="APP_NAME">%1$s</xliff:g> kini sedang berjalan."</string>
<string name="launch_warning_original" msgid="188102023021668683">"<xliff:g id="APP_NAME">%1$s</xliff:g> pada asalnya telah dilancarkan."</string>
diff --git a/core/res/res/values-nb/strings.xml b/core/res/res/values-nb/strings.xml
index 7e3fb86..e03b735 100644
--- a/core/res/res/values-nb/strings.xml
+++ b/core/res/res/values-nb/strings.xml
@@ -915,6 +915,7 @@
<string name="force_close" msgid="8346072094521265605">"OK"</string>
<string name="report" msgid="4060218260984795706">"Rapportér"</string>
<string name="wait" msgid="7147118217226317732">"Vent"</string>
+ <string name="webpage_unresponsive" msgid="3272758351138122503">"Siden svarer ikke."\n\n"Vil du lukke den?"</string>
<string name="launch_warning_title" msgid="1547997780506713581">"Appen er viderekoblet"</string>
<string name="launch_warning_replace" msgid="6202498949970281412">"<xliff:g id="APP_NAME">%1$s</xliff:g> kjører nå."</string>
<string name="launch_warning_original" msgid="188102023021668683">"<xliff:g id="APP_NAME">%1$s</xliff:g> ble opprinnelig startet."</string>
diff --git a/core/res/res/values-nl/strings.xml b/core/res/res/values-nl/strings.xml
index b956433..3a43b8e 100644
--- a/core/res/res/values-nl/strings.xml
+++ b/core/res/res/values-nl/strings.xml
@@ -915,6 +915,7 @@
<string name="force_close" msgid="8346072094521265605">"OK"</string>
<string name="report" msgid="4060218260984795706">"Rapport"</string>
<string name="wait" msgid="7147118217226317732">"Wachten"</string>
+ <string name="webpage_unresponsive" msgid="3272758351138122503">"De pagina reageert niet meer."\n\n"Wilt u de pagina sluiten?"</string>
<string name="launch_warning_title" msgid="1547997780506713581">"App verplaatst"</string>
<string name="launch_warning_replace" msgid="6202498949970281412">"<xliff:g id="APP_NAME">%1$s</xliff:g> is nu actief."</string>
<string name="launch_warning_original" msgid="188102023021668683">"<xliff:g id="APP_NAME">%1$s</xliff:g> was het eerst gestart."</string>
diff --git a/core/res/res/values-pl/strings.xml b/core/res/res/values-pl/strings.xml
index 9c713aa..e73f7d6 100644
--- a/core/res/res/values-pl/strings.xml
+++ b/core/res/res/values-pl/strings.xml
@@ -908,13 +908,14 @@
<string name="aerr_application" msgid="932628488013092776">"Niestety, aplikacja <xliff:g id="APPLICATION">%1$s</xliff:g> została zatrzymana."</string>
<string name="aerr_process" msgid="4507058997035697579">"Niestety, proces <xliff:g id="PROCESS">%1$s</xliff:g> został zatrzymany."</string>
<string name="anr_title" msgid="4351948481459135709"></string>
- <string name="anr_activity_application" msgid="1904477189057199066">"Aplikacja <xliff:g id="APPLICATION">%2$s</xliff:g> nie odpowiada."\n\n"Czy chcesz ją zamknąć?"</string>
+ <string name="anr_activity_application" msgid="1904477189057199066">"Aplikacja <xliff:g id="APPLICATION">%2$s</xliff:g> nie reaguje."\n\n"Czy chcesz ją zamknąć?"</string>
<string name="anr_activity_process" msgid="5776209883299089767">"Działanie <xliff:g id="ACTIVITY">%1$s</xliff:g> nie odpowiada."\n\n"Czy chcesz je zakończyć?"</string>
- <string name="anr_application_process" msgid="8941757607340481057">"Aplikacja <xliff:g id="APPLICATION">%1$s</xliff:g> nie odpowiada. Czy chcesz ją zamknąć?"</string>
+ <string name="anr_application_process" msgid="8941757607340481057">"Aplikacja <xliff:g id="APPLICATION">%1$s</xliff:g> nie reaguje. Czy chcesz ją zamknąć?"</string>
<string name="anr_process" msgid="6513209874880517125">"Proces <xliff:g id="PROCESS">%1$s</xliff:g> nie odpowiada."\n\n"Czy chcesz go zakończyć?"</string>
<string name="force_close" msgid="8346072094521265605">"OK"</string>
<string name="report" msgid="4060218260984795706">"Zgłoś"</string>
<string name="wait" msgid="7147118217226317732">"Czekaj"</string>
+ <string name="webpage_unresponsive" msgid="3272758351138122503">"Strona nie odpowiada na żądania."\n\n"Zamknąć ją?"</string>
<string name="launch_warning_title" msgid="1547997780506713581">"Aplikacja przekierowana"</string>
<string name="launch_warning_replace" msgid="6202498949970281412">"Aplikacja <xliff:g id="APP_NAME">%1$s</xliff:g> jest uruchomiona."</string>
<string name="launch_warning_original" msgid="188102023021668683">"Aplikacja <xliff:g id="APP_NAME">%1$s</xliff:g> została pierwotnie uruchomiona."</string>
@@ -1214,12 +1215,12 @@
<string name="ssl_certificate" msgid="6510040486049237639">"Certyfikat zabezpieczeń"</string>
<string name="ssl_certificate_is_valid" msgid="6825263250774569373">"Certyfikat jest ważny."</string>
<string name="issued_to" msgid="454239480274921032">"Wystawiony dla:"</string>
- <string name="common_name" msgid="2233209299434172646">"Nazwa pospolita (CN):"</string>
+ <string name="common_name" msgid="2233209299434172646">"Nazwa (CN):"</string>
<string name="org_name" msgid="6973561190762085236">"Organizacja:"</string>
<string name="org_unit" msgid="7265981890422070383">"Jednostka organizacyjna:"</string>
<string name="issued_by" msgid="2647584988057481566">"Wystawca:"</string>
<string name="validity_period" msgid="8818886137545983110">"Ważność:"</string>
- <string name="issued_on" msgid="5895017404361397232">"Data wystawienia:"</string>
+ <string name="issued_on" msgid="5895017404361397232">"Wystawiony:"</string>
<string name="expires_on" msgid="3676242949915959821">"Wygasa:"</string>
<string name="serial_number" msgid="758814067660862493">"Numer seryjny:"</string>
<string name="fingerprints" msgid="4516019619850763049">"Odciski cyfrowe:"</string>
diff --git a/core/res/res/values-pt-rPT/strings.xml b/core/res/res/values-pt-rPT/strings.xml
index c5e470c..800013d 100644
--- a/core/res/res/values-pt-rPT/strings.xml
+++ b/core/res/res/values-pt-rPT/strings.xml
@@ -915,6 +915,7 @@
<string name="force_close" msgid="8346072094521265605">"OK"</string>
<string name="report" msgid="4060218260984795706">"Relatório"</string>
<string name="wait" msgid="7147118217226317732">"Esperar"</string>
+ <string name="webpage_unresponsive" msgid="3272758351138122503">"A página deixou de responder. "\n" "\n" Pretende fechá-la?"</string>
<string name="launch_warning_title" msgid="1547997780506713581">"Aplicação redirecionada"</string>
<string name="launch_warning_replace" msgid="6202498949970281412">"<xliff:g id="APP_NAME">%1$s</xliff:g> está agora a ser executado."</string>
<string name="launch_warning_original" msgid="188102023021668683">"<xliff:g id="APP_NAME">%1$s</xliff:g> foi originalmente iniciado."</string>
diff --git a/core/res/res/values-pt/strings.xml b/core/res/res/values-pt/strings.xml
index 10ac03f..c907929 100644
--- a/core/res/res/values-pt/strings.xml
+++ b/core/res/res/values-pt/strings.xml
@@ -915,6 +915,7 @@
<string name="force_close" msgid="8346072094521265605">"OK"</string>
<string name="report" msgid="4060218260984795706">"Informar"</string>
<string name="wait" msgid="7147118217226317732">"Aguardar"</string>
+ <string name="webpage_unresponsive" msgid="3272758351138122503">"A página não responde."\n\n"Deseja fechá-la?"</string>
<string name="launch_warning_title" msgid="1547997780506713581">"Aplicativo redirecionado"</string>
<string name="launch_warning_replace" msgid="6202498949970281412">"<xliff:g id="APP_NAME">%1$s</xliff:g> não está em execução."</string>
<string name="launch_warning_original" msgid="188102023021668683">"<xliff:g id="APP_NAME">%1$s</xliff:g> foi iniciado."</string>
diff --git a/core/res/res/values-rm/strings.xml b/core/res/res/values-rm/strings.xml
index 4d40ddc..bc8d4fb 100644
--- a/core/res/res/values-rm/strings.xml
+++ b/core/res/res/values-rm/strings.xml
@@ -27,7 +27,8 @@
<string name="terabyteShort" msgid="231613018159186962">"TB"</string>
<string name="petabyteShort" msgid="5637816680144990219">"PB"</string>
<string name="fileSizeSuffix" msgid="7670819340156489359">"<xliff:g id="NUMBER">%1$s</xliff:g><xliff:g id="UNIT">%2$s</xliff:g>"</string>
- <!-- outdated translation 6071602020171759109 --> <string name="untitled" msgid="4638956954852782576">"<senza titel>"</string>
+ <!-- no translation found for untitled (4638956954852782576) -->
+ <skip />
<string name="ellipsis" msgid="7899829516048813237">"…"</string>
<!-- no translation found for ellipsis_two_dots (1228078994866030736) -->
<skip />
@@ -44,9 +45,12 @@
<string name="serviceErased" msgid="1288584695297200972">"Stizzà cun success."</string>
<string name="passwordIncorrect" msgid="7612208839450128715">"Il pled-clav è nuncorrect."</string>
<string name="mmiComplete" msgid="8232527495411698359">"MMI terminà."</string>
- <!-- outdated translation 5085454289896032547 --> <string name="badPin" msgid="9015277645546710014">"Il code PIN vegl che Vus avais endatà è nuncorrect."</string>
- <!-- outdated translation 5702522162746042460 --> <string name="badPuk" msgid="5487257647081132201">"Il PUK che Vus avais tippà è nuncorrect."</string>
- <!-- outdated translation 3695902225843339274 --> <string name="mismatchPin" msgid="609379054496863419">"Ils codes PIN che Vus avais endatà n\'èn betg identics."</string>
+ <!-- no translation found for badPin (9015277645546710014) -->
+ <skip />
+ <!-- no translation found for badPuk (5487257647081132201) -->
+ <skip />
+ <!-- no translation found for mismatchPin (609379054496863419) -->
+ <skip />
<string name="invalidPin" msgid="3850018445187475377">"Endatai in code PIN che cuntegna 4 fin 8 cifras."</string>
<!-- no translation found for invalidPuk (8761456210898036513) -->
<skip />
@@ -70,16 +74,20 @@
<string name="CLIRDefaultOffNextCallOn" msgid="6179425182856418465">"La ID dal telefonader n\'è betg limitada tenor configuraziun predefinida. Proxim clom: limitada."</string>
<string name="CLIRDefaultOffNextCallOff" msgid="2567998633124408552">"La ID dal telefonader n\'è betg limitada tenor configuraziun predefinida. Proxim clom: betg limitada."</string>
<string name="serviceNotProvisioned" msgid="8614830180508686666">"Quest servetsch na vegn betg sustegnì."</string>
- <!-- outdated translation 5460892159398802465 --> <string name="CLIRPermanent" msgid="3377371145926835671">"Il parameter per la ID dal telefonader na po betg vegnir modifitgà."</string>
+ <!-- no translation found for CLIRPermanent (3377371145926835671) -->
+ <skip />
<string name="RestrictedChangedTitle" msgid="5592189398956187498">"L\'access limità è vegnì modifitgà."</string>
<string name="RestrictedOnData" msgid="8653794784690065540">"Il servetsch da datas è bloccà."</string>
<string name="RestrictedOnEmergency" msgid="6581163779072833665">"Il servetsch da cloms d\'urgenza è bloccà."</string>
<string name="RestrictedOnNormal" msgid="4953867011389750673">"Il servetsch vocal è bloccà."</string>
- <string name="RestrictedOnAllVoice" msgid="1459318899842232234">"Tut ils servetschs vocals èn bloccads."</string>
+ <!-- no translation found for RestrictedOnAllVoice (3396963652108151260) -->
+ <skip />
<string name="RestrictedOnSms" msgid="8314352327461638897">"Il servetsch SMS è bloccà."</string>
- <string name="RestrictedOnVoiceData" msgid="8244438624660371717">"Ils servetschs vocals/da datas èn bloccads."</string>
+ <!-- no translation found for RestrictedOnVoiceData (996636487106171320) -->
+ <skip />
<string name="RestrictedOnVoiceSms" msgid="1888588152792023873">"Ils servetschs vocals/dad SMS èn bloccads."</string>
- <string name="RestrictedOnAll" msgid="2714924667937117304">"Tut ils servetschs vocals/da datas/da SMS èn bloccads."</string>
+ <!-- no translation found for RestrictedOnAll (5643028264466092821) -->
+ <skip />
<string name="serviceClassVoice" msgid="1258393812335258019">"Vusch"</string>
<string name="serviceClassData" msgid="872456782077937893">"Datas"</string>
<string name="serviceClassFAX" msgid="5566624998840486475">"FAX"</string>
@@ -110,35 +118,56 @@
<string name="fcComplete" msgid="3118848230966886575">"Code da servetsch terminà"</string>
<string name="fcError" msgid="3327560126588500777">"Problem da connexiun u code da funcziun nunvalid"</string>
<string name="httpErrorOk" msgid="1191919378083472204">"OK"</string>
- <!-- outdated translation 2567300624552921790 --> <string name="httpError" msgid="6603022914760066338">"La pagina d\'internet cuntegna ina errur."</string>
- <string name="httpErrorLookup" msgid="4517085806977851374">"Impussibel da chattar la URL."</string>
- <!-- outdated translation 2781440683514730227 --> <string name="httpErrorUnsupportedAuthScheme" msgid="6299980280442076799">"Il schema d\'autentificaziun da la site na vegn betg sustegnì."</string>
- <string name="httpErrorAuth" msgid="7293960746955020542">"L\'autentificaziun n\'è betg reussida."</string>
+ <!-- no translation found for httpError (7956392511146698522) -->
+ <skip />
+ <!-- no translation found for httpErrorLookup (4711687456111963163) -->
+ <skip />
+ <!-- no translation found for httpErrorUnsupportedAuthScheme (6299980280442076799) -->
+ <skip />
+ <!-- no translation found for httpErrorAuth (1435065629438044534) -->
+ <skip />
<string name="httpErrorProxyAuth" msgid="1788207010559081331">"L\'autentificaziun cun agid dad in proxy server n\'è betg reussida."</string>
- <string name="httpErrorConnect" msgid="7623096283505770433">"Betg reussì da connectar cun il server."</string>
- <!-- outdated translation 5047872902739125260 --> <string name="httpErrorIO" msgid="4270874999047767599">"La communicaziun cun il server n\'è betg reussida. Empruvai pli tard anc ina giada."</string>
+ <!-- no translation found for httpErrorConnect (8714273236364640549) -->
+ <skip />
+ <!-- no translation found for httpErrorIO (2340558197489302188) -->
+ <skip />
<string name="httpErrorTimeout" msgid="4743403703762883954">"Surpassà il temp cun connectar al server."</string>
<string name="httpErrorRedirectLoop" msgid="8679596090392779516">"Questa pagina cuntegna memia blers renviaments da server."</string>
- <!-- outdated translation 5257172771607996054 --> <string name="httpErrorUnsupportedScheme" msgid="5015730812906192208">"Quest protocol na vegn betg sustegnì."</string>
- <string name="httpErrorFailedSslHandshake" msgid="3088290300440289771">"Impussibel da stabilir ina connexiun segira."</string>
- <string name="httpErrorBadUrl" msgid="6088183159988619736">"Impussibel dad avrir la pagina. La URL è nunvalida."</string>
- <string name="httpErrorFile" msgid="8250549644091165175">"Impussibel d\'acceder a la datoteca."</string>
- <string name="httpErrorFileNotFound" msgid="5588380756326017105">"La datoteca dumandada n\'è betg vegnida chattada."</string>
+ <!-- no translation found for httpErrorUnsupportedScheme (5015730812906192208) -->
+ <skip />
+ <!-- no translation found for httpErrorFailedSslHandshake (96549606000658641) -->
+ <skip />
+ <!-- no translation found for httpErrorBadUrl (3636929722728881972) -->
+ <skip />
+ <!-- no translation found for httpErrorFile (2170788515052558676) -->
+ <skip />
+ <!-- no translation found for httpErrorFileNotFound (6203856612042655084) -->
+ <skip />
<string name="httpErrorTooManyRequests" msgid="1235396927087188253">"Actualmain vegnan memia bleras dumondas elavuradas. Empruvai pli tard anc ina giada."</string>
- <string name="notification_title" msgid="1259940370369187045">"Errur cun connectar al conto <xliff:g id="ACCOUNT">%1$s</xliff:g>"</string>
+ <!-- no translation found for notification_title (8967710025036163822) -->
+ <skip />
<string name="contentServiceSync" msgid="8353523060269335667">"Sincronisar"</string>
<string name="contentServiceSyncNotificationTitle" msgid="397743349191901458">"Sincronisar"</string>
<string name="contentServiceTooManyDeletesNotificationDesc" msgid="8100981435080696431">"Memia blers cuntegns stizzads (<xliff:g id="CONTENT_TYPE">%s</xliff:g>)."</string>
- <!-- outdated translation 6632412458436461203 --> <string name="low_memory" product="tablet" msgid="2292820184396262278">"La memoria dal telefon è occupada! Stizzai datotecas per crear capacitad da memorisar."</string>
- <string name="low_memory" product="default" msgid="6632412458436461203">"La memoria dal telefon è occupada! Stizzai datotecas per crear capacitad da memorisar."</string>
+ <!-- no translation found for low_memory (6494019234102154896) -->
+ <skip />
+ <!-- no translation found for low_memory (3475999286680000541) -->
+ <skip />
<string name="me" msgid="6545696007631404292">"Jau"</string>
- <!-- outdated translation 1319919075463988638 --> <string name="power_dialog" product="tablet" msgid="8545351420865202853">"Opziuns dal telefon"</string>
+ <!-- no translation found for power_dialog (8545351420865202853) -->
+ <skip />
<string name="power_dialog" product="default" msgid="1319919075463988638">"Opziuns dal telefon"</string>
<string name="silent_mode" msgid="7167703389802618663">"Modus silenzius"</string>
<string name="turn_on_radio" msgid="3912793092339962371">"Activar il modus senza fil"</string>
<string name="turn_off_radio" msgid="8198784949987062346">"Deactivar il modus senza fil"</string>
<string name="screen_lock" msgid="799094655496098153">"Bloccaziun dal visur"</string>
<string name="power_off" msgid="4266614107412865048">"Serrar"</string>
+ <!-- no translation found for silent_mode_silent (319298163018473078) -->
+ <skip />
+ <!-- no translation found for silent_mode_vibrate (7072043388581551395) -->
+ <skip />
+ <!-- no translation found for silent_mode_ring (8592241816194074353) -->
+ <skip />
<string name="shutdown_progress" msgid="2281079257329981203">"Vegn serrà..."</string>
<!-- no translation found for shutdown_confirm (3385745179555731470) -->
<skip />
@@ -147,8 +176,10 @@
<!-- no translation found for shutdown_confirm_question (2906544768881136183) -->
<skip />
<string name="recent_tasks_title" msgid="3691764623638127888">"Utilisà sco ultim"</string>
- <!-- outdated translation 279702952298056674 --> <string name="no_recent_tasks" msgid="8794906658732193473">"Naginas applicaziuns utilisadas dacurt"</string>
- <!-- outdated translation 2406416831541615258 --> <string name="global_actions" product="tablet" msgid="408477140088053665">"Opziuns dal telefon"</string>
+ <!-- no translation found for no_recent_tasks (8794906658732193473) -->
+ <skip />
+ <!-- no translation found for global_actions (408477140088053665) -->
+ <skip />
<string name="global_actions" product="default" msgid="2406416831541615258">"Opziuns dal telefon"</string>
<string name="global_action_lock" msgid="2844945191792119712">"Bloccaziun dal visur"</string>
<string name="global_action_power_off" msgid="4471879440839879722">"Metter ord funcziun"</string>
@@ -163,16 +194,21 @@
<string name="safeMode" msgid="2788228061547930246">"Modus segirà"</string>
<string name="android_system_label" msgid="6577375335728551336">"Sistem Android"</string>
<string name="permgrouplab_costMoney" msgid="5429808217861460401">"Servetschs che custan"</string>
- <!-- outdated translation 8193824940620517189 --> <string name="permgroupdesc_costMoney" msgid="8596717365335027057">"Permetta ad applicaziuns dad exequir acziuns che custan eventualmain."</string>
+ <!-- no translation found for permgroupdesc_costMoney (3293301903409869495) -->
+ <skip />
<string name="permgrouplab_messages" msgid="7521249148445456662">"Voss messadis"</string>
- <!-- outdated translation 7045736972019211994 --> <string name="permgroupdesc_messages" msgid="7821999071003699236">"\"Leger e scriver Voss SMS, e-mails ed auters messadis.\""</string>
+ <!-- no translation found for permgroupdesc_messages (7821999071003699236) -->
+ <skip />
<string name="permgrouplab_personalInfo" msgid="3519163141070533474">"Vossas infurmaziuns persunalas"</string>
- <!-- outdated translation 5488050357388806068 --> <string name="permgroupdesc_personalInfo" product="tablet" msgid="6975389054186265786">"Acceder directamain als contacts ed al chalender memorisà sin il telefonin."</string>
+ <!-- no translation found for permgroupdesc_personalInfo (6975389054186265786) -->
+ <skip />
<string name="permgroupdesc_personalInfo" product="default" msgid="5488050357388806068">"Acceder directamain als contacts ed al chalender memorisà sin il telefonin."</string>
<string name="permgrouplab_location" msgid="635149742436692049">"Vossa posiziun"</string>
- <string name="permgroupdesc_location" msgid="2430258821648348660">"suandar Vossa posiziun geografica"</string>
+ <!-- no translation found for permgroupdesc_location (5704679763124170100) -->
+ <skip />
<string name="permgrouplab_network" msgid="5808983377727109831">"Communicaziun rait"</string>
- <!-- outdated translation 5035763698958415998 --> <string name="permgroupdesc_network" msgid="4917593670797570584">"Permetta ad applicaziuns l\'access a differentas funcziuns da la rait."</string>
+ <!-- no translation found for permgroupdesc_network (4478299413241861987) -->
+ <skip />
<string name="permgrouplab_accounts" msgid="3359646291125325519">"Voss contos"</string>
<string name="permgroupdesc_accounts" msgid="4948732641827091312">"Access als contos disponibels"</string>
<string name="permgrouplab_hardwareControls" msgid="7998214968791599326">"Cumonds da la hardware"</string>
@@ -182,62 +218,90 @@
<string name="permgrouplab_systemTools" msgid="4652191644082714048">"Utensils da sistem"</string>
<string name="permgroupdesc_systemTools" msgid="8162102602190734305">"Access e controlla sin nivel datiers al sistem."</string>
<string name="permgrouplab_developmentTools" msgid="3446164584710596513">"Utensils per sviluppaders"</string>
- <!-- outdated translation 9056431193893809814 --> <string name="permgroupdesc_developmentTools" msgid="7058828032358142018">"Questas funcziunalitads èn mo previsas per ils sviluppaders dad applicaziuns."</string>
+ <!-- no translation found for permgroupdesc_developmentTools (7058828032358142018) -->
+ <skip />
<string name="permgrouplab_storage" msgid="1971118770546336966">"Memoria"</string>
- <!-- outdated translation 9203302214915355774 --> <string name="permgroupdesc_storage" product="nosdcard" msgid="7442318502446874999">"Access a la carta SD."</string>
+ <!-- no translation found for permgroupdesc_storage (7442318502446874999) -->
+ <skip />
<string name="permgroupdesc_storage" product="default" msgid="9203302214915355774">"Access a la carta SD."</string>
<string name="permlab_statusBar" msgid="7417192629601890791">"deactivar u modifitgar la trav da status"</string>
- <!-- outdated translation 1365473595331989732 --> <string name="permdesc_statusBar" msgid="8434669549504290975">"Permetta a l\'applicaziun da deactivar l\'indicatur da status u agiuntar ed allontanar simbols dal sistem."</string>
+ <!-- no translation found for permdesc_statusBar (8434669549504290975) -->
+ <skip />
<string name="permlab_statusBarService" msgid="7247281911387931485">"trav da status"</string>
- <!-- outdated translation 4097605867643520920 --> <string name="permdesc_statusBarService" msgid="716113660795976060">"Permetta a l\'applicaziun dad esser la trav da status."</string>
+ <!-- no translation found for permdesc_statusBarService (716113660795976060) -->
+ <skip />
<string name="permlab_expandStatusBar" msgid="1148198785937489264">"expander/reducir la trav da status"</string>
- <!-- outdated translation 7088604400110768665 --> <string name="permdesc_expandStatusBar" msgid="6917549437129401132">"Permetta a l\'applicaziun da mussar u zuppentar la trav da status."</string>
+ <!-- no translation found for permdesc_expandStatusBar (6917549437129401132) -->
+ <skip />
<string name="permlab_processOutgoingCalls" msgid="1136262550878335980">"interceptar cloms sortints"</string>
- <!-- outdated translation 2228988201852654461 --> <string name="permdesc_processOutgoingCalls" msgid="1152111671618301044">"\"Permetta ad ina applicaziun dad elavurar ils cloms sortints e da modifitgar il numer che duai vegnir cumponì. Applicaziuns donnegiusas pon uschia eventualmain survegliar, renviar u evitar cloms sortints.\""</string>
+ <!-- no translation found for permdesc_processOutgoingCalls (1152111671618301044) -->
+ <skip />
<string name="permlab_receiveSms" msgid="2697628268086208535">"retschaiver SMS"</string>
- <!-- outdated translation 6298292335965966117 --> <string name="permdesc_receiveSms" msgid="8107887121893611793">"Permetta a l\'applicaziun da retschaiver ed elavurar SMS. Applicaziuns donnegiusas pon uschia survegliar Voss messadis u als stizzar avant ch\'els vegnan mussads."</string>
+ <!-- no translation found for permdesc_receiveSms (8107887121893611793) -->
+ <skip />
<string name="permlab_receiveMms" msgid="8894700916188083287">"retschaiver MMS"</string>
- <!-- outdated translation 4563346832000174373 --> <string name="permdesc_receiveMms" msgid="1424805308566612086">"Permetta a l\'applicaziun da retschaiver ed elavurar MMS. Applicaziuns donnegiusas pon uschia survegliar Voss messadis u als stizzar avant ch\'els vegnan mussads."</string>
+ <!-- no translation found for permdesc_receiveMms (1424805308566612086) -->
+ <skip />
<!-- no translation found for permlab_receiveEmergencyBroadcast (1803477660846288089) -->
<skip />
<!-- no translation found for permdesc_receiveEmergencyBroadcast (848524070262431974) -->
<skip />
<string name="permlab_sendSms" msgid="5600830612147671529">"trametter messadis SMS"</string>
- <!-- outdated translation 1946540351763502120 --> <string name="permdesc_sendSms" msgid="906546667507626156">"Permetta ad applicaziuns da trametter messadis SMS. Applicaziuns donnegiusas pon chaschunar custs cun trametter messadis senza As dumandar."</string>
+ <!-- no translation found for permdesc_sendSms (906546667507626156) -->
+ <skip />
<!-- no translation found for permlab_sendSmsNoConfirmation (4781483105951730228) -->
<skip />
<!-- no translation found for permdesc_sendSmsNoConfirmation (3437759207020400204) -->
<skip />
<string name="permlab_readSms" msgid="4085333708122372256">"leger SMS u MMS"</string>
- <!-- outdated translation 3002170087197294591 --> <string name="permdesc_readSms" product="tablet" msgid="2341692916884515613">"Permetta ad ina applicaziun da leger ils SMS memorisads sin Voss telefonin u sin Vossa carta SIM. Applicaziuns donnegiusas legian uschia eventualmain Voss messadis confidenzials."</string>
- <!-- outdated translation 3002170087197294591 --> <string name="permdesc_readSms" product="default" msgid="5653850482025875493">"Permetta ad ina applicaziun da leger ils SMS memorisads sin Voss telefonin u sin Vossa carta SIM. Applicaziuns donnegiusas legian uschia eventualmain Voss messadis confidenzials."</string>
+ <!-- no translation found for permdesc_readSms (2341692916884515613) -->
+ <skip />
+ <!-- no translation found for permdesc_readSms (5653850482025875493) -->
+ <skip />
<string name="permlab_writeSms" msgid="6881122575154940744">"modifitgar SMS u MMS"</string>
- <!-- outdated translation 6299398896177548095 --> <string name="permdesc_writeSms" product="tablet" msgid="5160413947794501538">"Permetta ad ina applicaziun da modifitgar SMS memorisads sin Voss telefonin u Vossa carta SIM. Applicaziuns donnegiusas stizzan uschia eventualmain Voss messadis."</string>
- <!-- outdated translation 6299398896177548095 --> <string name="permdesc_writeSms" product="default" msgid="7268668709052328567">"Permetta ad ina applicaziun da modifitgar SMS memorisads sin Voss telefonin u Vossa carta SIM. Applicaziuns donnegiusas stizzan uschia eventualmain Voss messadis."</string>
+ <!-- no translation found for permdesc_writeSms (5160413947794501538) -->
+ <skip />
+ <!-- no translation found for permdesc_writeSms (7268668709052328567) -->
+ <skip />
<string name="permlab_receiveWapPush" msgid="8258226427716551388">"retschaiver messadis WAP"</string>
- <!-- outdated translation 5979623826128082171 --> <string name="permdesc_receiveWapPush" msgid="7983455145335316872">"Permetta a l\'applicaziun da retschaiver ed elavurar messadis WAP. Applicaziuns donnegiusas pon uschia survegliar Voss messadis u als stizzar avant ch\'els vegnan mussads."</string>
- <!-- outdated translation 5005277531132573353 --> <string name="permlab_getTasks" msgid="6466095396623933906">"recuperaziun da las applicaziuns exequidas"</string>
- <!-- outdated translation 7048711358713443341 --> <string name="permdesc_getTasks" msgid="6608159250520381359">"Permetta a l\'applicaziun da recuperar infurmaziuns davart incumbensas che vegnan exequidas u èn gist vegnidas exequidas. Applicaziuns donnegiusas pon uschia obtegnair infurmaziuns privatas concernent autras applicaziuns."</string>
- <!-- outdated translation 5669588525059921549 --> <string name="permlab_reorderTasks" msgid="2018575526934422779">"reorganisar las applicaziuns che vegnan exequidas"</string>
- <!-- outdated translation 126252774270522835 --> <string name="permdesc_reorderTasks" msgid="4175137612205663399">"Permetta ad ina applicaziun da spustar las incumbensas en il fund davant u en il fund davos. Applicaziuns donnegiusas pon sa mussar en il fund davant senza Vossa autorisaziun."</string>
+ <!-- no translation found for permdesc_receiveWapPush (7983455145335316872) -->
+ <skip />
+ <!-- no translation found for permlab_getTasks (6466095396623933906) -->
+ <skip />
+ <!-- no translation found for permdesc_getTasks (6608159250520381359) -->
+ <skip />
+ <!-- no translation found for permlab_reorderTasks (2018575526934422779) -->
+ <skip />
+ <!-- no translation found for permdesc_reorderTasks (4175137612205663399) -->
+ <skip />
<!-- no translation found for permlab_removeTasks (6821513401870377403) -->
<skip />
- <!-- no translation found for permdesc_removeTasks (1000226123143185094) -->
+ <!-- no translation found for permdesc_removeTasks (1394714352062635493) -->
<skip />
- <!-- outdated translation 4339730312925176742 --> <string name="permlab_setDebugApp" msgid="3022107198686584052">"activar il debugging da l\'applicaziun"</string>
- <!-- outdated translation 5584310661711990702 --> <string name="permdesc_setDebugApp" msgid="6215654419903651172">"Permetta ad ina applicaziun dad activar il debugging per autras applicaziuns. Applicaziuns donnegiusas pon uschia serrar autras applicaziuns."</string>
+ <!-- no translation found for permlab_setDebugApp (3022107198686584052) -->
+ <skip />
+ <!-- no translation found for permdesc_setDebugApp (4474512416299013256) -->
+ <skip />
<string name="permlab_changeConfiguration" msgid="8214475779521218295">"modifitgar ils parameters da la UI"</string>
- <!-- outdated translation 3465121501528064399 --> <string name="permdesc_changeConfiguration" msgid="4104052649900380324">"Permetta ad ina applicaziun da modifitgar la configuraziun actuala (per exempel la grondezza da la scrittira ed ils parameters regiunals)."</string>
+ <!-- no translation found for permdesc_changeConfiguration (4372223873154296076) -->
+ <skip />
<string name="permlab_enableCarMode" msgid="5684504058192921098">"activar il modus dad auto"</string>
- <!-- outdated translation 5673461159384850628 --> <string name="permdesc_enableCarMode" msgid="4853187425751419467">"Permetta ad ina applicaziun dad activar il modus dad auto."</string>
+ <!-- no translation found for permdesc_enableCarMode (4853187425751419467) -->
+ <skip />
<string name="permlab_killBackgroundProcesses" msgid="8373714752793061963">"interrumper ils process en il fund davos"</string>
- <!-- outdated translation 2908829602869383753 --> <string name="permdesc_killBackgroundProcesses" msgid="931129103262126617">"Permetta ad ina applicaziun da serrar process en il fund davos dad autras applicaziuns era en cas da memoria suffizienta."</string>
- <!-- outdated translation 1447830113260156236 --> <string name="permlab_forceStopPackages" msgid="2329627428832067700">"serrar autras applicaziuns cun forza"</string>
- <!-- outdated translation 7263036616161367402 --> <string name="permdesc_forceStopPackages" msgid="5253157296183940812">"Permetta ad ina applicaziun da sfurzar autras applicaziuns da serrar."</string>
- <!-- outdated translation 1804196839880393631 --> <string name="permlab_forceBack" msgid="652935204072584616">"serrar l\'applicaziun cun forza"</string>
- <!-- outdated translation 6534109744159919013 --> <string name="permdesc_forceBack" msgid="3892295830419513623">"Permetta ad ina applicaziun da serrar tut las activitads che vegnan exequidas en il fund davant e da las spustar en il fund davos. Betg previs per applicaziuns normalas."</string>
+ <!-- no translation found for permdesc_killBackgroundProcesses (931129103262126617) -->
+ <skip />
+ <!-- no translation found for permlab_forceStopPackages (2329627428832067700) -->
+ <skip />
+ <!-- no translation found for permdesc_forceStopPackages (5253157296183940812) -->
+ <skip />
+ <!-- no translation found for permlab_forceBack (652935204072584616) -->
+ <skip />
+ <!-- no translation found for permdesc_forceBack (3892295830419513623) -->
+ <skip />
<string name="permlab_dump" msgid="1681799862438954752">"verifitgar il status intern dal sistem"</string>
- <!-- outdated translation 2198776174276275220 --> <string name="permdesc_dump" msgid="1778299088692290329">"\"Permetta ad ina applicaziun da vesair il status intern dal sistem. Applicaziuns donnegiusas pon uschia obtegnair numerusas infurmaziuns privatas u segiradas, a las qualas ellas na dastgassan normalmain mai acceder.\""</string>
+ <!-- no translation found for permdesc_dump (1778299088692290329) -->
+ <skip />
<!-- no translation found for permlab_retrieve_window_content (8022588608994589938) -->
<skip />
<!-- no translation found for permdesc_retrieve_window_content (3193269069469700265) -->
@@ -245,42 +309,62 @@
<string name="permlab_shutdown" msgid="7185747824038909016">"serrar parzialmain"</string>
<string name="permdesc_shutdown" msgid="7046500838746291775">"Metta l\'administratur dad activitads en in stadi da pausa. El na vegn betg serrà dal tut."</string>
<string name="permlab_stopAppSwitches" msgid="4138608610717425573">"evitar il midar tranter applicaziuns"</string>
- <!-- outdated translation 3857886086919033794 --> <string name="permdesc_stopAppSwitches" msgid="8262195802582255021">"Impedescha che l\'utilisader midia ad ina autra applicaziun."</string>
- <!-- outdated translation 7811586187574696296 --> <string name="permlab_runSetActivityWatcher" msgid="892239094867182656">"survegliar e controllar l\'aviar dad applicaziuns"</string>
- <!-- outdated translation 3228701938345388092 --> <string name="permdesc_runSetActivityWatcher" msgid="6003603162578577406">"Permetta ad ina applicaziun da survegliar e controllar l\'aviar dad activitads dal sistem. Applicaziuns donnegiusas pon uschia periclitar l\'entir sistem. Questa permissiun è mo previsa per process da svilup e mai per il diever normal dal telefonin."</string>
+ <!-- no translation found for permdesc_stopAppSwitches (8262195802582255021) -->
+ <skip />
+ <!-- no translation found for permlab_runSetActivityWatcher (892239094867182656) -->
+ <skip />
+ <!-- no translation found for permdesc_runSetActivityWatcher (6003603162578577406) -->
+ <skip />
<string name="permlab_broadcastPackageRemoved" msgid="2576333434893532475">"trametter in broadcast senza pachet"</string>
- <!-- outdated translation 3453286591439891260 --> <string name="permdesc_broadcastPackageRemoved" msgid="6621901216207931089">"Permetta ad ina applicaziun da trametter in avis cura ch\'in pachet d\'applicaziun è vegnì stizzà. Applicaziuns donnegiusas pon utilisar questa funcziunalitad per interrumper l\'execuziun dad autras applicaziuns."</string>
+ <!-- no translation found for permdesc_broadcastPackageRemoved (6621901216207931089) -->
+ <skip />
<string name="permlab_broadcastSmsReceived" msgid="5689095009030336593">"trametter in broadcast retschavì per SMS"</string>
- <!-- outdated translation 9122419277306740155 --> <string name="permdesc_broadcastSmsReceived" msgid="4152037720034365492">"Permetta ad ina applicaziun da trametter in avis cura ch\'in messadi vegn retschavì. Applicaziuns donnegiusas pon utilisar questa funcziunalitad per dar da crair ch\'in messadi saja arrivà."</string>
+ <!-- no translation found for permdesc_broadcastSmsReceived (4152037720034365492) -->
+ <skip />
<string name="permlab_broadcastWapPush" msgid="3145347413028582371">"trametter in broadcast retschavì da WAP-PUSH"</string>
- <!-- outdated translation 3955303669461378091 --> <string name="permdesc_broadcastWapPush" msgid="4783402525039442729">"Permetta ad ina applicaziun da trametter in avis cura ch\'in messadi WAP PUSH vegn retschavì. Applicaziuns donnegiusas pon utilisar questa funcziunalitad per dar da crair ch\'in MMS saja arrivà u per remplazzar il cuntegn da mintga pagina d\'internet cun datas donnegiusas."</string>
+ <!-- no translation found for permdesc_broadcastWapPush (4783402525039442729) -->
+ <skip />
<string name="permlab_setProcessLimit" msgid="2451873664363662666">"limitar il dumber maximal da process exequids"</string>
- <!-- outdated translation 7824786028557379539 --> <string name="permdesc_setProcessLimit" msgid="7318061314040879542">"Permetta ad ina applicaziun da controllar il dumber maximal da process che pon vegnir exequids a medem temp. Betg previs per applicaziuns normalas."</string>
- <!-- outdated translation 5342837862439543783 --> <string name="permlab_setAlwaysFinish" msgid="238828158465736054">"serrar tut las applicaziuns en il fund davos"</string>
- <!-- outdated translation 8773936403987091620 --> <string name="permdesc_setAlwaysFinish" msgid="7471310652868841499">"Permetta ad ina applicaziun da controllar schebain activitads vegnan adina terminadas sch\'ellas vegnan stuschadas en il fund davos. Betg previs per applicaziuns normalas."</string>
+ <!-- no translation found for permdesc_setProcessLimit (7318061314040879542) -->
+ <skip />
+ <!-- no translation found for permlab_setAlwaysFinish (238828158465736054) -->
+ <skip />
+ <!-- no translation found for permdesc_setAlwaysFinish (7471310652868841499) -->
+ <skip />
<string name="permlab_batteryStats" msgid="7863923071360031652">"modifitgar las datas da l\'accu"</string>
- <!-- outdated translation 5847319823772230560 --> <string name="permdesc_batteryStats" msgid="6835186932305744068">"Permetta da modifitgar las datas statisticas da l\'accu. Betg previs per applicaziuns normalas."</string>
+ <!-- no translation found for permdesc_batteryStats (6835186932305744068) -->
+ <skip />
<string name="permlab_backup" msgid="470013022865453920">"controllar las copias da segirezza e la restauraziun dal sistem"</string>
- <!-- outdated translation 4837493065154256525 --> <string name="permdesc_backup" msgid="6912230525140589891">"Permetta a l\'applicaziun da controllar il mecanissem da copias da segirezza e da restauraziun dal sistem. Betg previs per applicaziuns normalas."</string>
+ <!-- no translation found for permdesc_backup (6912230525140589891) -->
+ <skip />
<!-- no translation found for permlab_confirm_full_backup (5557071325804469102) -->
<skip />
<!-- no translation found for permdesc_confirm_full_backup (1748762171637699562) -->
<skip />
<string name="permlab_internalSystemWindow" msgid="2148563628140193231">"mussar fanestras betg autorisadas"</string>
- <!-- outdated translation 5895082268284998469 --> <string name="permdesc_internalSystemWindow" msgid="6510907081810231374">"Permetta da crear fanestras destinadas per l\'utilisaziun da l\'interfatscha d\'utilisader interna dal sistem. Questa funcziun n\'è betg previsa per applicaziuns normalas."</string>
+ <!-- no translation found for permdesc_internalSystemWindow (7458387759461466397) -->
+ <skip />
<string name="permlab_systemAlertWindow" msgid="3372321942941168324">"mussar avertiments dal sistem"</string>
- <!-- outdated translation 5109622689323490558 --> <string name="permdesc_systemAlertWindow" msgid="8507863469978066409">"Permetta ad ina applicaziun da mussar fanestras cun avertiments dal sistem. Applicaziuns donnegiusas pon uschia occupar l\'entir visur dal telefonin."</string>
+ <!-- no translation found for permdesc_systemAlertWindow (8507863469978066409) -->
+ <skip />
<string name="permlab_setAnimationScale" msgid="2805103241153907174">"modifitgar la sveltezza globala da las animaziuns"</string>
- <!-- outdated translation 7181522138912391988 --> <string name="permdesc_setAnimationScale" msgid="6505093307223395456">"Permetta ad ina applicaziun da modifitgar da tut temp la sveltezza generala da las animaziuns (per las pudair far ir pli svelt u pli plaun)."</string>
- <!-- outdated translation 17124341698093865 --> <string name="permlab_manageAppTokens" msgid="1286505717050121370">"administrar tokens dad applicaziuns"</string>
- <!-- outdated translation 977127907524195988 --> <string name="permdesc_manageAppTokens" msgid="8043431713014395671">"Permetta ad applicaziuns da crear ed administrar lur agens tokens cun ignorar lur urden da zavrar Z normal. Betg previs per applicaziuns normalas."</string>
+ <!-- no translation found for permdesc_setAnimationScale (7690063428924343571) -->
+ <skip />
+ <!-- no translation found for permlab_manageAppTokens (1286505717050121370) -->
+ <skip />
+ <!-- no translation found for permdesc_manageAppTokens (8043431713014395671) -->
+ <skip />
<string name="permlab_injectEvents" msgid="1378746584023586600">"smatgar tastas e tastas da controlla"</string>
- <!-- outdated translation 3946098050410874715 --> <string name="permdesc_injectEvents" product="tablet" msgid="206352565599968632">"Permetta ad ina applicaziun da furnir ses agens cumonds (tastas smatgadas etc.) ad autras applicaziuns. Applicaziuns donnegiusas pon utilisar questa funcziunalitad per surpigliar la controlla da Voss telefonin."</string>
- <!-- outdated translation 3946098050410874715 --> <string name="permdesc_injectEvents" product="default" msgid="653128057572326253">"Permetta ad ina applicaziun da furnir ses agens cumonds (tastas smatgadas etc.) ad autras applicaziuns. Applicaziuns donnegiusas pon utilisar questa funcziunalitad per surpigliar la controlla da Voss telefonin."</string>
+ <!-- no translation found for permdesc_injectEvents (206352565599968632) -->
+ <skip />
+ <!-- no translation found for permdesc_injectEvents (653128057572326253) -->
+ <skip />
<string name="permlab_readInputState" msgid="469428900041249234">"registrar endataziuns sur la tastatura ed acziuns"</string>
- <!-- outdated translation 5132879321450325445 --> <string name="permdesc_readInputState" msgid="8387754901688728043">"\"Permetta ad ina applicaziun dad identifitgar las tastas che Vus smatgais, era durant l\'utilisaziun dad in auter program (durant l\'endataziun dad in pled-clav, per exempel). Applicaziuns normalas na duessan betg avair access a questa funcziun.\""</string>
+ <!-- no translation found for permdesc_readInputState (8387754901688728043) -->
+ <skip />
<string name="permlab_bindInputMethod" msgid="3360064620230515776">"associar cun ina metoda d\'endataziun"</string>
- <!-- outdated translation 3734838321027317228 --> <string name="permdesc_bindInputMethod" msgid="3250440322807286331">"Permetta da sa fixar al nivel d\'interfatscha pli aut dad ina metoda d\'endataziun. Betg previs per applicaziuns normalas."</string>
+ <!-- no translation found for permdesc_bindInputMethod (3250440322807286331) -->
+ <skip />
<!-- no translation found for permlab_bindTextService (7358378401915287938) -->
<skip />
<!-- no translation found for permdesc_bindTextService (8151968910973998670) -->
@@ -290,66 +374,112 @@
<!-- no translation found for permdesc_bindVpnService (2067845564581693905) -->
<skip />
<string name="permlab_bindWallpaper" msgid="8716400279937856462">"sa fixar vid in fund davos"</string>
- <!-- outdated translation 5287754520361915347 --> <string name="permdesc_bindWallpaper" msgid="7108428692595491668">"Permetta da sa fixar al nivel d\'interfatscha pli aut dad ina metoda d\'endataziun. Betg previs per applicaziuns normalas."</string>
+ <!-- no translation found for permdesc_bindWallpaper (7108428692595491668) -->
+ <skip />
<!-- no translation found for permlab_bindRemoteViews (5697987759897367099) -->
<skip />
<!-- no translation found for permdesc_bindRemoteViews (4717987810137692572) -->
<skip />
<string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"interacziun cun in administratur dad apparats"</string>
- <!-- outdated translation 8714424333082216979 --> <string name="permdesc_bindDeviceAdmin" msgid="569715419543907930">"Permetta al possessur da trametter intenziuns a l\'administratur dal apparat periferic. Betg previs per applicaziuns normalas."</string>
+ <!-- no translation found for permdesc_bindDeviceAdmin (569715419543907930) -->
+ <skip />
<string name="permlab_setOrientation" msgid="3365947717163866844">"midar l\'orientaziun dal visur"</string>
- <!-- outdated translation 6335814461615851863 --> <string name="permdesc_setOrientation" msgid="3046126619316671476">"Permetta a l\'applicaziun da midar da tut temp la orientaziun dal visur. Betg previs per applicaziuns normalas."</string>
+ <!-- no translation found for permdesc_setOrientation (3046126619316671476) -->
+ <skip />
<!-- no translation found for permlab_setPointerSpeed (9175371613322562934) -->
<skip />
<!-- no translation found for permdesc_setPointerSpeed (6866563234274104233) -->
<skip />
- <!-- outdated translation 4255467255488653854 --> <string name="permlab_signalPersistentProcesses" msgid="4539002991947376659">"trametter signals Linux a las applicaziuns"</string>
- <!-- outdated translation 3565530463215015289 --> <string name="permdesc_signalPersistentProcesses" msgid="4896992079182649141">"Permetta a l\'applicaziun da pretender ch\'il signal furnì vegnia tramess a tut ils process persistents."</string>
- <!-- outdated translation 8659652042401085862 --> <string name="permlab_persistentActivity" msgid="8841113627955563938">"exequir permanentamain applicaziuns"</string>
- <!-- outdated translation 5037199778265006008 --> <string name="permdesc_persistentActivity" msgid="4909910271316074418">"Permetta ad ina applicaziun da render persistent atgnas cumponentas per ch\'il sistem na po betg utilisar questas per autras applicaziuns."</string>
- <!-- outdated translation 3343439331576348805 --> <string name="permlab_deletePackages" msgid="184385129537705938">"stizzar applicaziuns"</string>
- <!-- outdated translation 3634943677518723314 --> <string name="permdesc_deletePackages" msgid="7411480275167205081">"Permetta ad ina applicaziun da stizzar pachets da datas Android. Applicaziuns donnegiusas pon utilisar questa funcziun per stizzar applicaziuns impurtantas."</string>
- <!-- outdated translation 2192134353540277878 --> <string name="permlab_clearAppUserData" msgid="274109191845842756">"stizzar datas dad ina autra applicaziun"</string>
- <!-- outdated translation 7546345080434325456 --> <string name="permdesc_clearAppUserData" msgid="4625323684125459488">"Permetta ad ina applicaziun da stizzar las datas da l\'utilisader."</string>
- <!-- outdated translation 1518556602634276725 --> <string name="permlab_deleteCacheFiles" msgid="3128665571837408675">"stizzar ils caches dad autras applicaziuns"</string>
- <!-- outdated translation 2283074077168165971 --> <string name="permdesc_deleteCacheFiles" msgid="3812998599006730196">"Permetta ad ina applicaziun da stizzar las datotecas en il cache."</string>
- <!-- outdated translation 4799785352306641460 --> <string name="permlab_getPackageSize" msgid="7472921768357981986">"evaluar la capacitad da memoria occupada da l\'applicaziun"</string>
- <!-- outdated translation 5557253039670753437 --> <string name="permdesc_getPackageSize" msgid="3921068154420738296">"\"Permetta ad ina applicaziun dad obtegnair la grondezza dal code, da las datas e dal cache.\""</string>
- <!-- outdated translation 335800214119051089 --> <string name="permlab_installPackages" msgid="2199128482820306924">"installar directamain applicaziuns"</string>
- <!-- outdated translation 526669220850066132 --> <string name="permdesc_installPackages" msgid="5628530972548071284">"Permetta ad ina applicaziun dad installar pachets novs u actualisads dad Android. Applicaziuns donnegiusas pon utilisar questa funcziunalitad per agiuntar novas applicaziuns che han tut las permissiuns pussaivlas."</string>
- <!-- outdated translation 4747698311163766540 --> <string name="permlab_clearAppCache" msgid="7487279391723526815">"stizzar las datas dal cache da tut las applicaziuns"</string>
- <!-- outdated translation 7740465694193671402 --> <string name="permdesc_clearAppCache" product="tablet" msgid="3523396284474042284">"Permetta ad ina applicaziun da dar liber capacitad da memorisar dal telefonin cun stizzar datotecas en l\'ordinatur da cache da l\'applicaziun. L\'access è per regla limità a process da sistem."</string>
- <!-- outdated translation 7740465694193671402 --> <string name="permdesc_clearAppCache" product="default" msgid="5067988373366292186">"Permetta ad ina applicaziun da dar liber capacitad da memorisar dal telefonin cun stizzar datotecas en l\'ordinatur da cache da l\'applicaziun. L\'access è per regla limità a process da sistem."</string>
- <!-- outdated translation 728454979946503926 --> <string name="permlab_movePackage" msgid="3289890271645921411">"Spustar resursas d\'applicaziun"</string>
- <!-- outdated translation 6323049291923925277 --> <string name="permdesc_movePackage" msgid="319562217778244524">"Permetta ad ina applicaziun da spustar resursas d\'applicaziun dad in medium intern ad in medium extern e viceversa."</string>
- <!-- outdated translation 4811921703882532070 --> <string name="permlab_readLogs" msgid="6615778543198967614">"leger datotecas da protocol dal sistem"</string>
- <!-- outdated translation 2257937955580475902 --> <string name="permdesc_readLogs" product="tablet" msgid="82061313293455151">"Permetta ad ina applicaziun da leger las differentas datotecas da protocol dal sistem. Quai pussibilitescha dad obtegnair infurmaziuns generalas davart il diever da Voss telefon che na duessan betg cuntegnair datas persunalas u privatas."</string>
- <!-- outdated translation 2257937955580475902 --> <string name="permdesc_readLogs" product="default" msgid="2063438140241560443">"Permetta ad ina applicaziun da leger las differentas datotecas da protocol dal sistem. Quai pussibilitescha dad obtegnair infurmaziuns generalas davart il diever da Voss telefon che na duessan betg cuntegnair datas persunalas u privatas."</string>
+ <!-- no translation found for permlab_signalPersistentProcesses (4539002991947376659) -->
+ <skip />
+ <!-- no translation found for permdesc_signalPersistentProcesses (4896992079182649141) -->
+ <skip />
+ <!-- no translation found for permlab_persistentActivity (8841113627955563938) -->
+ <skip />
+ <!-- no translation found for permdesc_persistentActivity (4909910271316074418) -->
+ <skip />
+ <!-- no translation found for permlab_deletePackages (184385129537705938) -->
+ <skip />
+ <!-- no translation found for permdesc_deletePackages (7411480275167205081) -->
+ <skip />
+ <!-- no translation found for permlab_clearAppUserData (274109191845842756) -->
+ <skip />
+ <!-- no translation found for permdesc_clearAppUserData (4625323684125459488) -->
+ <skip />
+ <!-- no translation found for permlab_deleteCacheFiles (3128665571837408675) -->
+ <skip />
+ <!-- no translation found for permdesc_deleteCacheFiles (3812998599006730196) -->
+ <skip />
+ <!-- no translation found for permlab_getPackageSize (7472921768357981986) -->
+ <skip />
+ <!-- no translation found for permdesc_getPackageSize (3921068154420738296) -->
+ <skip />
+ <!-- no translation found for permlab_installPackages (2199128482820306924) -->
+ <skip />
+ <!-- no translation found for permdesc_installPackages (5628530972548071284) -->
+ <skip />
+ <!-- no translation found for permlab_clearAppCache (7487279391723526815) -->
+ <skip />
+ <!-- no translation found for permdesc_clearAppCache (3523396284474042284) -->
+ <skip />
+ <!-- no translation found for permdesc_clearAppCache (5067988373366292186) -->
+ <skip />
+ <!-- no translation found for permlab_movePackage (3289890271645921411) -->
+ <skip />
+ <!-- no translation found for permdesc_movePackage (319562217778244524) -->
+ <skip />
+ <!-- no translation found for permlab_readLogs (6615778543198967614) -->
+ <skip />
+ <!-- no translation found for permdesc_readLogs (82061313293455151) -->
+ <skip />
+ <!-- no translation found for permdesc_readLogs (2063438140241560443) -->
+ <skip />
+ <!-- no translation found for permlab_anyCodecForPlayback (715805555823881818) -->
+ <skip />
+ <!-- no translation found for permdesc_anyCodecForPlayback (8283912488433189010) -->
+ <skip />
<string name="permlab_diagnostic" msgid="8076743953908000342">"leger/scriver en resursas che appartegnan a diagnostics"</string>
- <!-- outdated translation 3121238373951637049 --> <string name="permdesc_diagnostic" msgid="6608295692002452283">"Permetta ad ina applicaziun da leger e modifitgar tut ils elements ella gruppa da diagnosa (per exempel las datotecas en /dev). Quai po avair consequenzas negativas per la stabilitad e la segirezza dal sistem e duess vegnir permess mo a programs da diagnosa specifics per la hardware mess a disposiziun dal producider u dal gestiunari da la rait."</string>
- <!-- outdated translation 79425198834329406 --> <string name="permlab_changeComponentState" msgid="6335576775711095931">"activar u deactivar cumponentas dad applicaziuns"</string>
- <!-- outdated translation 4569107043246700630 --> <string name="permdesc_changeComponentState" product="tablet" msgid="8887435740982237294">"\"Permetta ad ina applicaziun dad activar u deactivar cumponentas dad autras applicaziuns. Applicaziuns donnegiusas pon uschia deactivar funcziuns impurtantas dal telefonin. Faschai attenziun cun permetter l\'access a questa funcziun perquai ch\'ella permetta da render nunduvrablas, incoerentas ed instabilas las cumponentas da las applicaziuns.\""</string>
- <!-- outdated translation 4569107043246700630 --> <string name="permdesc_changeComponentState" product="default" msgid="1827232484416505615">"\"Permetta ad ina applicaziun dad activar u deactivar cumponentas dad autras applicaziuns. Applicaziuns donnegiusas pon uschia deactivar funcziuns impurtantas dal telefonin. Faschai attenziun cun permetter l\'access a questa funcziun perquai ch\'ella permetta da render nunduvrablas, incoerentas ed instabilas las cumponentas da las applicaziuns.\""</string>
- <!-- outdated translation 3393305202145172005 --> <string name="permlab_setPreferredApplications" msgid="8463181628695396391">"definir las applicaziuns preferidas"</string>
- <!-- outdated translation 760008293501937546 --> <string name="permdesc_setPreferredApplications" msgid="4973986762241783712">"Permetta ad ina applicaziun da modifitgar Vossas applicaziuns preferidas. Applicaziuns donnegiusas pon uschia remplazzar en il zuppà applicaziuns che vegnan gist exequidas ed imitar Vossas applicaziuns existentas cun la finamira da rimnar datas persunalas da Vus."</string>
+ <!-- no translation found for permdesc_diagnostic (6608295692002452283) -->
+ <skip />
+ <!-- no translation found for permlab_changeComponentState (6335576775711095931) -->
+ <skip />
+ <!-- no translation found for permdesc_changeComponentState (8887435740982237294) -->
+ <skip />
+ <!-- no translation found for permdesc_changeComponentState (1827232484416505615) -->
+ <skip />
+ <!-- no translation found for permlab_setPreferredApplications (8463181628695396391) -->
+ <skip />
+ <!-- no translation found for permdesc_setPreferredApplications (4973986762241783712) -->
+ <skip />
<string name="permlab_writeSettings" msgid="1365523497395143704">"modifitgar parameters generals dal sistem"</string>
- <!-- outdated translation 838789419871034696 --> <string name="permdesc_writeSettings" msgid="7775723441558907181">"Permetta ad ina applicaziun da modifitgar las datas dals parameters dal sistem. Applicaziuns donnegiusas pon utilisar questa funcziun per donnegiar la configuraziun da Voss sistem."</string>
+ <!-- no translation found for permdesc_writeSettings (7775723441558907181) -->
+ <skip />
<string name="permlab_writeSecureSettings" msgid="204676251876718288">"modifitgar ils parameters da segirezza dal sistem"</string>
- <!-- outdated translation 5497873143539034724 --> <string name="permdesc_writeSecureSettings" msgid="8159535613020137391">"Permetta ad ina applicaziun da modifitgar las datas da configuraziun da segirezza dal sistem. Betg previs per applicaziuns normalas."</string>
+ <!-- no translation found for permdesc_writeSecureSettings (8159535613020137391) -->
+ <skip />
<string name="permlab_writeGservices" msgid="2149426664226152185">"modifitgar Google Services Map"</string>
- <!-- outdated translation 6602362746516676175 --> <string name="permdesc_writeGservices" msgid="1287309437638380229">"Permetta ad ina applicaziun da modifitgar la charta da servetschs Google. Betg previs per applicaziuns normalas."</string>
+ <!-- no translation found for permdesc_writeGservices (1287309437638380229) -->
+ <skip />
<string name="permlab_receiveBootCompleted" msgid="7776779842866993377">"aviar automaticamain suenter ch\'il sistem è avià"</string>
- <!-- outdated translation 698336728415008796 --> <string name="permdesc_receiveBootCompleted" product="tablet" msgid="7390304664116880704">"\"Permetta ad ina applicaziun dad aviar sasez suenter ch\'il sistem è vegnì avià. Qua tras po l\'aviar dal telefonin durar pli ditg, ultra da quai po l\'entir sistem vegnir retardà cun l\'activitad permanenta da l\'applicaziun.\""</string>
- <!-- outdated translation 698336728415008796 --> <string name="permdesc_receiveBootCompleted" product="default" msgid="513950589102617504">"\"Permetta ad ina applicaziun dad aviar sasez suenter ch\'il sistem è vegnì avià. Qua tras po l\'aviar dal telefonin durar pli ditg, ultra da quai po l\'entir sistem vegnir retardà cun l\'activitad permanenta da l\'applicaziun.\""</string>
+ <!-- no translation found for permdesc_receiveBootCompleted (7390304664116880704) -->
+ <skip />
+ <!-- no translation found for permdesc_receiveBootCompleted (513950589102617504) -->
+ <skip />
<string name="permlab_broadcastSticky" msgid="7919126372606881614">"trametter in broadcast permanent"</string>
- <!-- outdated translation 1920045289234052219 --> <string name="permdesc_broadcastSticky" product="tablet" msgid="1181582512022829259">"Permetta ad ina applicaziun da trametter broadcasts persistents che na sa serran betg a la fin dal broadcast. Applicaziuns donnegiusas pon uschia render plaun ed instabil il telefonin cun occupar memia blera memoria."</string>
- <!-- outdated translation 1920045289234052219 --> <string name="permdesc_broadcastSticky" product="default" msgid="3287869131621514325">"Permetta ad ina applicaziun da trametter broadcasts persistents che na sa serran betg a la fin dal broadcast. Applicaziuns donnegiusas pon uschia render plaun ed instabil il telefonin cun occupar memia blera memoria."</string>
+ <!-- no translation found for permdesc_broadcastSticky (1181582512022829259) -->
+ <skip />
+ <!-- no translation found for permdesc_broadcastSticky (3287869131621514325) -->
+ <skip />
<string name="permlab_readContacts" msgid="6219652189510218240">"leger las datas da contact"</string>
- <!-- outdated translation 3371591512896545975 --> <string name="permdesc_readContacts" product="tablet" msgid="4028657556924039119">"Permetta ad ina applicaziun da leger tut las datas da contacts (adressas) memorisadas sin Voss telefonin. Applicaziuns donnegiusas pon utilisar questa funcziun per trametter Vossas datas ad autras persunas."</string>
- <!-- outdated translation 3371591512896545975 --> <string name="permdesc_readContacts" product="default" msgid="2032222056456498547">"Permetta ad ina applicaziun da leger tut las datas da contacts (adressas) memorisadas sin Voss telefonin. Applicaziuns donnegiusas pon utilisar questa funcziun per trametter Vossas datas ad autras persunas."</string>
+ <!-- no translation found for permdesc_readContacts (4028657556924039119) -->
+ <skip />
+ <!-- no translation found for permdesc_readContacts (2032222056456498547) -->
+ <skip />
<string name="permlab_writeContacts" msgid="644616215860933284">"scriver datas da contact"</string>
- <!-- outdated translation 3924383579108183601 --> <string name="permdesc_writeContacts" product="tablet" msgid="988969759110632978">"Permetta ad ina applicaziun da modifitgar tut las datas da contact (adressas) memorisadas sin Voss telefonin. Applicaziuns donnegiusas pon utilisar questa funcziun per stizzar u modifitgar Vossas datas da contact."</string>
- <!-- outdated translation 3924383579108183601 --> <string name="permdesc_writeContacts" product="default" msgid="5075164818647934067">"Permetta ad ina applicaziun da modifitgar tut las datas da contact (adressas) memorisadas sin Voss telefonin. Applicaziuns donnegiusas pon utilisar questa funcziun per stizzar u modifitgar Vossas datas da contact."</string>
+ <!-- no translation found for permdesc_writeContacts (988969759110632978) -->
+ <skip />
+ <!-- no translation found for permdesc_writeContacts (5075164818647934067) -->
+ <skip />
<!-- no translation found for permlab_readProfile (6824681438529842282) -->
<skip />
<!-- no translation found for permdesc_readProfile (94520753797630679) -->
@@ -366,59 +496,96 @@
<skip />
<!-- no translation found for permdesc_writeSocialStream (3496277176955721451) -->
<skip />
- <!-- outdated translation 6898987798303840534 --> <string name="permlab_readCalendar" msgid="5972727560257612398">"leger eveniments da chalender"</string>
- <!-- outdated translation 5533029139652095734 --> <string name="permdesc_readCalendar" product="tablet" msgid="2338414551004122687">"Permetta ad ina applicaziun da leger tut ils eveniments da chalender memorisads sin Voss telefonin. Applicaziuns donnegiusas pon uschia trametter Voss eveniments da chalender ad autras persunas."</string>
- <!-- outdated translation 5533029139652095734 --> <string name="permdesc_readCalendar" product="default" msgid="5693933067751827753">"Permetta ad ina applicaziun da leger tut ils eveniments da chalender memorisads sin Voss telefonin. Applicaziuns donnegiusas pon uschia trametter Voss eveniments da chalender ad autras persunas."</string>
- <!-- outdated translation 3894879352594904361 --> <string name="permlab_writeCalendar" msgid="8438874755193825647">"agiuntar u modifitgar eveniments en il chalender e trametter e-mails als envidads"</string>
- <!-- outdated translation 2988871373544154221 --> <string name="permdesc_writeCalendar" msgid="2243771395254848873">"Permetta ad ina applicaziun dad agiuntar u modifitgar eveniments en Voss chalender che pon trametter e-mails ad envidads. Applicaziuns donnegiusas pon uschia stizzar u modifitgar las datas en Voss chalender u trametter e-mails ad envidads."</string>
+ <!-- no translation found for permlab_readCalendar (5972727560257612398) -->
+ <skip />
+ <!-- no translation found for permdesc_readCalendar (2338414551004122687) -->
+ <skip />
+ <!-- no translation found for permdesc_readCalendar (5693933067751827753) -->
+ <skip />
+ <!-- no translation found for permlab_writeCalendar (8438874755193825647) -->
+ <skip />
+ <!-- no translation found for permdesc_writeCalendar (2243771395254848873) -->
+ <skip />
<string name="permlab_accessMockLocation" msgid="8688334974036823330">"creaziun da funtaunas da posiziun fictivas per motivs da test"</string>
- <!-- outdated translation 7648286063459727252 --> <string name="permdesc_accessMockLocation" msgid="7577931556422993949">"Permetta da crear funtaunas da localisaziun fictivas per motivs da test. Applicaziuns donnegiusas pon uschia remplazzar la posiziun ed il status returnà da las vairas funtaunas sco GPS u Voss gestiunari da la rait."</string>
+ <!-- no translation found for permdesc_accessMockLocation (7577931556422993949) -->
+ <skip />
<string name="permlab_accessLocationExtraCommands" msgid="2836308076720553837">"access als cumonds supplementars da purschiders da posiziuns geograficas"</string>
- <!-- outdated translation 1948144701382451721 --> <string name="permdesc_accessLocationExtraCommands" msgid="6737736970602176133">"Permetta d\'acceder a cumonds supplementars da purschiders da posiziuns geograficas. Applicaziuns donnegiusas pon uschia eventualmain disturbar il funcziunament da GPS u autras funtaunas da localisaziun geografica."</string>
+ <!-- no translation found for permdesc_accessLocationExtraCommands (6737736970602176133) -->
+ <skip />
<string name="permlab_installLocationProvider" msgid="6578101199825193873">"permetter l\'installaziun d\'in purschider da servetschs da localisaziun"</string>
- <!-- outdated translation 5449175116732002106 --> <string name="permdesc_installLocationProvider" msgid="1742577679350078373">"Crear funtaunas da localisaziun fictivas per motivs da test. Applicaziuns donnegiusas pon uschia remplazzar la posiziun ed il status returnads da las funtaunas vairas sco GPS u Voss gestiunari da la rait u survegliar Vossa posiziun geografica e la transmetter ad ina funtauna externa."</string>
+ <!-- no translation found for permdesc_installLocationProvider (1742577679350078373) -->
+ <skip />
<string name="permlab_accessFineLocation" msgid="8116127007541369477">"posiziun exacta (GPS)"</string>
- <!-- outdated translation 7411213317434337331 --> <string name="permdesc_accessFineLocation" product="tablet" msgid="5326423948268164934">"Permetta d\'acceder a funtaunas da localisaziun exactas sco GPS (Global Positioning System) sche in tal è disponibel. Applicaziuns donnegiusas pon uschia identifitgar Vossa posiziun geografica e consumar energia supplementara da l\'accu."</string>
- <!-- outdated translation 7411213317434337331 --> <string name="permdesc_accessFineLocation" product="default" msgid="7130267914433890869">"Permetta d\'acceder a funtaunas da localisaziun exactas sco GPS (Global Positioning System) sche in tal è disponibel. Applicaziuns donnegiusas pon uschia identifitgar Vossa posiziun geografica e consumar energia supplementara da l\'accu."</string>
+ <!-- no translation found for permdesc_accessFineLocation (5326423948268164934) -->
+ <skip />
+ <!-- no translation found for permdesc_accessFineLocation (7130267914433890869) -->
+ <skip />
<string name="permlab_accessCoarseLocation" msgid="4642255009181975828">"Posiziun geografica approximativa (sin basa da la rait)"</string>
- <!-- outdated translation 8235655958070862293 --> <string name="permdesc_accessCoarseLocation" product="tablet" msgid="5460726396318105483">"\"Acceda a funtaunas approximativas da localisaziun (per exempel bancas da datas da raits mobilas) per determinar la posiziun geografica dal telefonin, sche questa opziun è disponibla. Applicaziuns donnegiusas pon utilisar questa funcziun per vegnir a savair nua che Vus sa chattais circa.\""</string>
- <!-- outdated translation 8235655958070862293 --> <string name="permdesc_accessCoarseLocation" product="default" msgid="8900795778057579522">"\"Acceda a funtaunas approximativas da localisaziun (per exempel bancas da datas da raits mobilas) per determinar la posiziun geografica dal telefonin, sche questa opziun è disponibla. Applicaziuns donnegiusas pon utilisar questa funcziun per vegnir a savair nua che Vus sa chattais circa.\""</string>
+ <!-- no translation found for permdesc_accessCoarseLocation (5460726396318105483) -->
+ <skip />
+ <!-- no translation found for permdesc_accessCoarseLocation (8900795778057579522) -->
+ <skip />
<string name="permlab_accessSurfaceFlinger" msgid="2363969641792388947">"access a SurfaceFlinger"</string>
- <!-- outdated translation 6805241830020733025 --> <string name="permdesc_accessSurfaceFlinger" msgid="1041619516733293551">"Permetta ad ina applicaziun dad utilisar las funcziuns SurfaceFlinger datiers al nivel dal sistem."</string>
+ <!-- no translation found for permdesc_accessSurfaceFlinger (1041619516733293551) -->
+ <skip />
<string name="permlab_readFrameBuffer" msgid="6690504248178498136">"leger il paraculp da frame"</string>
- <!-- outdated translation 5777679658669057819 --> <string name="permdesc_readFrameBuffer" msgid="4937405521809454680">"Permetta ad ina applicaziun da leger il cuntegn dal paraculp da frame."</string>
+ <!-- no translation found for permdesc_readFrameBuffer (4937405521809454680) -->
+ <skip />
<string name="permlab_modifyAudioSettings" msgid="6095859937069146086">"modifitgar Voss parameters audio"</string>
- <!-- outdated translation 5793461287365991922 --> <string name="permdesc_modifyAudioSettings" msgid="7343951185408396919">"Permetta a l\'applicaziun da modifitgar ils parameters generals dad audio (per exempel il volumen e routing)."</string>
+ <!-- no translation found for permdesc_modifyAudioSettings (7343951185408396919) -->
+ <skip />
<string name="permlab_recordAudio" msgid="3876049771427466323">"registrar audio"</string>
- <!-- outdated translation 6493228261176552356 --> <string name="permdesc_recordAudio" msgid="2387462233976248635">"Permetta a l\'applicaziun dad acceder a la via d\'access per registraziuns dad audio."</string>
+ <!-- no translation found for permdesc_recordAudio (2387462233976248635) -->
+ <skip />
<string name="permlab_camera" msgid="3616391919559751192">"fotografar e registrar videos"</string>
- <!-- outdated translation 6004878235852154239 --> <string name="permdesc_camera" msgid="1507407407002492176">"Permetta a l\'applicaziun da fotografar e da registrar videos cun la camera. Uschia po l\'applicaziun rimnar da tut temp maletgs fatgs cun la camera."</string>
- <!-- outdated translation 8337817093326370537 --> <string name="permlab_brick" product="tablet" msgid="2961292205764488304">"deactivar permanentamain il telefonin"</string>
+ <!-- no translation found for permdesc_camera (1507407407002492176) -->
+ <skip />
+ <!-- no translation found for permlab_brick (2961292205764488304) -->
+ <skip />
<string name="permlab_brick" product="default" msgid="8337817093326370537">"deactivar permanentamain il telefonin"</string>
- <!-- outdated translation 5569526552607599221 --> <string name="permdesc_brick" product="tablet" msgid="4334818808001699530">"Permetta ad ina applicaziun da deactivar definitivamain il telefon. Questa autorisaziun è fitg privlusa."</string>
- <!-- outdated translation 5569526552607599221 --> <string name="permdesc_brick" product="default" msgid="5788903297627283099">"Permetta ad ina applicaziun da deactivar definitivamain il telefon. Questa autorisaziun è fitg privlusa."</string>
- <!-- outdated translation 2898560872462638242 --> <string name="permlab_reboot" product="tablet" msgid="3436634972561795002">"sfurzar il telefonin da reaviar"</string>
+ <!-- no translation found for permdesc_brick (4334818808001699530) -->
+ <skip />
+ <!-- no translation found for permdesc_brick (5788903297627283099) -->
+ <skip />
+ <!-- no translation found for permlab_reboot (3436634972561795002) -->
+ <skip />
<string name="permlab_reboot" product="default" msgid="2898560872462638242">"sfurzar il telefonin da reaviar"</string>
- <!-- outdated translation 7914933292815491782 --> <string name="permdesc_reboot" product="tablet" msgid="8172056180063700741">"Permetta a l\'applicaziun da sfurzar il telefonin da reaviar."</string>
- <!-- outdated translation 7914933292815491782 --> <string name="permdesc_reboot" product="default" msgid="5326008124289989969">"Permetta a l\'applicaziun da sfurzar il telefonin da reaviar."</string>
+ <!-- no translation found for permdesc_reboot (8172056180063700741) -->
+ <skip />
+ <!-- no translation found for permdesc_reboot (5326008124289989969) -->
+ <skip />
<string name="permlab_mount_unmount_filesystems" msgid="1761023272170956541">"montar e demontar sistems da datotecas"</string>
- <!-- outdated translation 6253263792535859767 --> <string name="permdesc_mount_unmount_filesystems" msgid="1829290701658992347">"Permetta a l\'applicaziun da montar e demontar sistems da datotecas per apparats periferics da memoria mobila."</string>
+ <!-- no translation found for permdesc_mount_unmount_filesystems (1829290701658992347) -->
+ <skip />
<string name="permlab_mount_format_filesystems" msgid="5523285143576718981">"formataziun da la memoria externa"</string>
- <!-- outdated translation 574060044906047386 --> <string name="permdesc_mount_format_filesystems" msgid="8784268246779198627">"Permetta a l\'applicaziun da formatar memoria mobila."</string>
- <!-- outdated translation 1070364079249834666 --> <string name="permlab_asec_access" msgid="3411338632002193846">"obtegnair infurmaziuns davart la memoria segira"</string>
- <!-- outdated translation 7691616292170590244 --> <string name="permdesc_asec_access" msgid="3094563844593878548">"Permetta a l\'applicaziun dad obtegnair infurmaziuns davart la memoria segira."</string>
- <!-- outdated translation 7312078032326928899 --> <string name="permlab_asec_create" msgid="6414757234789336327">"crear ina memoria segira"</string>
- <!-- outdated translation 7041802322759014035 --> <string name="permdesc_asec_create" msgid="4558869273585856876">"Permetta a l\'applicaziun da crear ina memoria segira."</string>
- <!-- outdated translation 7787322878955261006 --> <string name="permlab_asec_destroy" msgid="526928328301618022">"allontanar la memoria segira"</string>
- <!-- outdated translation 5740754114967893169 --> <string name="permdesc_asec_destroy" msgid="7218749286145526537">"Permetta a l\'applicaziun dad allontanar la memoria segira."</string>
- <!-- outdated translation 7517449694667828592 --> <string name="permlab_asec_mount_unmount" msgid="8877998101944999386">"montar/demontar la memoria segira"</string>
- <!-- outdated translation 5438078121718738625 --> <string name="permdesc_asec_mount_unmount" msgid="3451360114902490929">"Permetta a l\'applicaziun da montar/demontar la memoria segira."</string>
- <!-- outdated translation 5685344390439934495 --> <string name="permlab_asec_rename" msgid="7496633954080472417">"renumnar la memoria segira"</string>
- <!-- outdated translation 1387881770708872470 --> <string name="permdesc_asec_rename" msgid="1794757588472127675">"Permetta a l\'applicaziun da renumnar la memoria segira."</string>
+ <!-- no translation found for permdesc_mount_format_filesystems (8784268246779198627) -->
+ <skip />
+ <!-- no translation found for permlab_asec_access (3411338632002193846) -->
+ <skip />
+ <!-- no translation found for permdesc_asec_access (3094563844593878548) -->
+ <skip />
+ <!-- no translation found for permlab_asec_create (6414757234789336327) -->
+ <skip />
+ <!-- no translation found for permdesc_asec_create (4558869273585856876) -->
+ <skip />
+ <!-- no translation found for permlab_asec_destroy (526928328301618022) -->
+ <skip />
+ <!-- no translation found for permdesc_asec_destroy (7218749286145526537) -->
+ <skip />
+ <!-- no translation found for permlab_asec_mount_unmount (8877998101944999386) -->
+ <skip />
+ <!-- no translation found for permdesc_asec_mount_unmount (3451360114902490929) -->
+ <skip />
+ <!-- no translation found for permlab_asec_rename (7496633954080472417) -->
+ <skip />
+ <!-- no translation found for permdesc_asec_rename (1794757588472127675) -->
+ <skip />
<string name="permlab_vibrate" msgid="7768356019980849603">"controllar la vibraziun"</string>
- <!-- outdated translation 2886677177257789187 --> <string name="permdesc_vibrate" msgid="6284989245902300945">"Permetta a l\'applicaziun da controllar la vibraziun."</string>
+ <!-- no translation found for permdesc_vibrate (6284989245902300945) -->
+ <skip />
<string name="permlab_flashlight" msgid="2155920810121984215">"controllar la glischina"</string>
- <!-- outdated translation 6433045942283802309 --> <string name="permdesc_flashlight" msgid="6522284794568368310">"Permetta a l\'applicaziun da controllar la glischina."</string>
+ <!-- no translation found for permdesc_flashlight (6522284794568368310) -->
+ <skip />
<!-- no translation found for permlab_manageUsb (1113453430645402723) -->
<skip />
<!-- no translation found for permdesc_manageUsb (7776155430218239833) -->
@@ -428,112 +595,180 @@
<!-- no translation found for permdesc_accessMtp (6532961200486791570) -->
<skip />
<string name="permlab_hardware_test" msgid="4148290860400659146">"testar la hardware"</string>
- <!-- outdated translation 3668894686500081699 --> <string name="permdesc_hardware_test" msgid="6597964191208016605">"Permetta ad ina applicaziun da controllar differents apparats periferics per motivs da test da hardware."</string>
+ <!-- no translation found for permdesc_hardware_test (6597964191208016605) -->
+ <skip />
<string name="permlab_callPhone" msgid="3925836347681847954">"telefonar directamain a numers da telefon"</string>
- <!-- outdated translation 3369867353692722456 --> <string name="permdesc_callPhone" msgid="6396463004110544744">"Permetta a l\'applicaziun da far telefons senza Vossa intervenziun. Applicaziuns donnegiusas pon uschia chaschunar telefons nunspetgads sin Voss quint da telefon. Questa funcziun permetta dentant betg da telefonar a numers d\'urgenza."</string>
+ <!-- no translation found for permdesc_callPhone (6396463004110544744) -->
+ <skip />
<string name="permlab_callPrivileged" msgid="4198349211108497879">"telefonar directamain a mintga numer"</string>
- <!-- outdated translation 244405067160028452 --> <string name="permdesc_callPrivileged" msgid="1689024901509996810">"Permetta a l\'applicaziun da cumponer mintga numer (inclus numers d\'urgenza) senza Vossa intervenziun. Applicaziuns donnegiusas pon uschia far telefons nunnecessaris ed illegals a numers d\'urgenza."</string>
- <!-- outdated translation 5604848095315421425 --> <string name="permlab_performCdmaProvisioning" product="tablet" msgid="4842576994144604821">"aviar directamain la configuraziun dal telefonin CDMA"</string>
+ <!-- no translation found for permdesc_callPrivileged (1689024901509996810) -->
+ <skip />
+ <!-- no translation found for permlab_performCdmaProvisioning (4842576994144604821) -->
+ <skip />
<string name="permlab_performCdmaProvisioning" product="default" msgid="5604848095315421425">"aviar directamain la configuraziun dal telefonin CDMA"</string>
- <!-- outdated translation 6457447676108355905 --> <string name="permdesc_performCdmaProvisioning" msgid="1994193538802314186">"Permetta a l\'applicaziun dad aviar il provediment CDMA. Applicaziuns donnegiusas pon uschia aviar inutilmain il provediment CDMA."</string>
+ <!-- no translation found for permdesc_performCdmaProvisioning (1994193538802314186) -->
+ <skip />
<string name="permlab_locationUpdates" msgid="7785408253364335740">"controllar ils avis ad actualisaziuns da la posiziun geografica"</string>
- <!-- outdated translation 2300018303720930256 --> <string name="permdesc_locationUpdates" msgid="1120741557891438876">"Permetta l\'activaziun/deactivaziun dad avis ad actualisaziuns da la posiziun geografica che derivan dal signal da radio. Betg previs per applicaziuns normalas."</string>
+ <!-- no translation found for permdesc_locationUpdates (1120741557891438876) -->
+ <skip />
<string name="permlab_checkinProperties" msgid="7855259461268734914">"access a las caracteristicas check-in"</string>
- <!-- outdated translation 7150307006141883832 --> <string name="permdesc_checkinProperties" msgid="4024526968630194128">"Permetta l\'access (leger e scriver) ad elements transmess dal servetsch check-in. Betg previs per applicaziuns normalas."</string>
+ <!-- no translation found for permdesc_checkinProperties (4024526968630194128) -->
+ <skip />
<string name="permlab_bindGadget" msgid="776905339015863471">"tscherner ils widgets"</string>
- <!-- outdated translation 2098697834497452046 --> <string name="permdesc_bindGadget" msgid="8261326938599049290">"Permetta a l\'applicaziun dad annunziar al sistem tge widgets che pon vegnir utilisads da tge applicaziun. Cun questa permissiun pon applicaziuns autorisar l\'access a datas persunalas per autras applicaziuns. Questa opziun n\'è betg previsa per applicaziuns normalas."</string>
+ <!-- no translation found for permdesc_bindGadget (8261326938599049290) -->
+ <skip />
<string name="permlab_modifyPhoneState" msgid="8423923777659292228">"modifitgar il status dal telefon"</string>
- <!-- outdated translation 3302284561346956587 --> <string name="permdesc_modifyPhoneState" msgid="1029877529007686732">"\"Permetta ad ina applicaziun da controllar las funcziunalitads telefonicas da l\'apparat. Ina applicaziun po uschia midar la rait, deactivar ed activar il signal radiofonic dal telefon etc. senza As avertir.\""</string>
+ <!-- no translation found for permdesc_modifyPhoneState (1029877529007686732) -->
+ <skip />
<string name="permlab_readPhoneState" msgid="2326172951448691631">"leger il status e l\'identitad dal telefon"</string>
- <!-- outdated translation 8987653603298258459 --> <string name="permdesc_readPhoneState" msgid="5127767618743602782">"\"Permetta a l\'applicaziun dad acceder a las funcziuns da clom dal telefonin. Ina applicaziun cun questas permissiuns po eruir il numer che quest telefonin utilisescha, schebain i vegn telefonà ed identifitgar il numer clamà etc.\""</string>
- <!-- outdated translation 573480187941496130 --> <string name="permlab_wakeLock" product="tablet" msgid="1531731435011495015">"evitar ch\'il telefon midia en il modus stand-by"</string>
+ <!-- no translation found for permdesc_readPhoneState (5127767618743602782) -->
+ <skip />
+ <!-- no translation found for permlab_wakeLock (1531731435011495015) -->
+ <skip />
<string name="permlab_wakeLock" product="default" msgid="573480187941496130">"evitar ch\'il telefon midia en il modus stand-by"</string>
- <!-- outdated translation 7584036471227467099 --> <string name="permdesc_wakeLock" product="tablet" msgid="7311319824400447868">"Permetta ad ina applicaziun dad evitar ch\'il telefon midia en il modus standby."</string>
- <!-- outdated translation 7584036471227467099 --> <string name="permdesc_wakeLock" product="default" msgid="8559100677372928754">"Permetta ad ina applicaziun dad evitar ch\'il telefon midia en il modus standby."</string>
- <!-- outdated translation 4928622470980943206 --> <string name="permlab_devicePower" product="tablet" msgid="2787034722616350417">"metter en/ord funcziun l\'apparat"</string>
+ <!-- no translation found for permdesc_wakeLock (7311319824400447868) -->
+ <skip />
+ <!-- no translation found for permdesc_wakeLock (8559100677372928754) -->
+ <skip />
+ <!-- no translation found for permlab_devicePower (2787034722616350417) -->
+ <skip />
<string name="permlab_devicePower" product="default" msgid="4928622470980943206">"metter en/ord funcziun l\'apparat"</string>
- <!-- outdated translation 4577331933252444818 --> <string name="permdesc_devicePower" product="tablet" msgid="6689862878984631831">"Permetta ad ina applicaziun dad activar u deactivar il telefonin."</string>
- <!-- outdated translation 4577331933252444818 --> <string name="permdesc_devicePower" product="default" msgid="6037057348463131032">"Permetta ad ina applicaziun dad activar u deactivar il telefonin."</string>
+ <!-- no translation found for permdesc_devicePower (6689862878984631831) -->
+ <skip />
+ <!-- no translation found for permdesc_devicePower (6037057348463131032) -->
+ <skip />
<string name="permlab_factoryTest" msgid="3715225492696416187">"exequir en il modus da test da fabrica"</string>
- <!-- outdated translation 8136644990319244802 --> <string name="permdesc_factoryTest" product="tablet" msgid="3952059318359653091">"Permetta d\'exequir sco test da fabrica datiers al nivel dal sistem cun autorisar l\'access a la hardware dal telefonin. Questa funcziunalitad è mo disponibla sch\'il telefonin sa chatta en il modus da test da fabrica."</string>
+ <!-- no translation found for permdesc_factoryTest (3952059318359653091) -->
+ <skip />
<string name="permdesc_factoryTest" product="default" msgid="8136644990319244802">"Permetta d\'exequir sco test da fabrica datiers al nivel dal sistem cun autorisar l\'access a la hardware dal telefonin. Questa funcziunalitad è mo disponibla sch\'il telefonin sa chatta en il modus da test da fabrica."</string>
<string name="permlab_setWallpaper" msgid="6627192333373465143">"definir la culissa"</string>
- <!-- outdated translation 6417041752170585837 --> <string name="permdesc_setWallpaper" msgid="7373447920977624745">"Permetta a l\'applicaziun da definir il fund davos dal sistem."</string>
+ <!-- no translation found for permdesc_setWallpaper (7373447920977624745) -->
+ <skip />
<string name="permlab_setWallpaperHints" msgid="3600721069353106851">"definir ils indicaturs da grondezza per il fund davos"</string>
- <!-- outdated translation 6019479164008079626 --> <string name="permdesc_setWallpaperHints" msgid="8235784384223730091">"Permetta a l\'applicaziun da definir la grondezza dal fund dal visur."</string>
+ <!-- no translation found for permdesc_setWallpaperHints (8235784384223730091) -->
+ <skip />
<string name="permlab_masterClear" msgid="2315750423139697397">"reinizialisar il sistem cun ses parameters originals"</string>
- <!-- outdated translation 5033465107545174514 --> <string name="permdesc_masterClear" msgid="3665380492633910226">"\"Permetta ad ina applicaziun da restaurar il stadi original dal sistem. Qua tras vegnan tut las datas, las configuraziuns e las applicaziuns installadas stizzadas.\""</string>
+ <!-- no translation found for permdesc_masterClear (3665380492633910226) -->
+ <skip />
<string name="permlab_setTime" msgid="2021614829591775646">"drizzar l\'ura"</string>
- <!-- outdated translation 667294309287080045 --> <string name="permdesc_setTime" product="tablet" msgid="1896341438151152881">"Permetta ad ina applicaziun da drizzar l\'ura dal telefonin."</string>
- <!-- outdated translation 667294309287080045 --> <string name="permdesc_setTime" product="default" msgid="1855702730738020">"Permetta ad ina applicaziun da drizzar l\'ura dal telefonin."</string>
+ <!-- no translation found for permdesc_setTime (1896341438151152881) -->
+ <skip />
+ <!-- no translation found for permdesc_setTime (1855702730738020) -->
+ <skip />
<string name="permlab_setTimeZone" msgid="2945079801013077340">"definir la zona d\'urari"</string>
- <!-- outdated translation 1902540227418179364 --> <string name="permdesc_setTimeZone" product="tablet" msgid="1676983712315827645">"Permetta ad ina applicaziun da modifitgar la zona d\'urari dal telefonin."</string>
- <!-- outdated translation 1902540227418179364 --> <string name="permdesc_setTimeZone" product="default" msgid="4499943488436633398">"Permetta ad ina applicaziun da modifitgar la zona d\'urari dal telefonin."</string>
+ <!-- no translation found for permdesc_setTimeZone (1676983712315827645) -->
+ <skip />
+ <!-- no translation found for permdesc_setTimeZone (4499943488436633398) -->
+ <skip />
<string name="permlab_accountManagerService" msgid="4829262349691386986">"agir sco administratur da contos"</string>
- <!-- outdated translation 6056903274106394752 --> <string name="permdesc_accountManagerService" msgid="2684502137670299915">"Permetta ad ina applicaziun da telefonar ad autentificaturs da contos."</string>
+ <!-- no translation found for permdesc_accountManagerService (1948455552333615954) -->
+ <skip />
<string name="permlab_getAccounts" msgid="4549918644233460103">"tschertgar contos enconuschents"</string>
- <!-- outdated translation 6839262446413155394 --> <string name="permdesc_getAccounts" product="tablet" msgid="3238360555257773358">"Permetta ad ina applicaziun da consultar la glista dals contos enconuschents al telefonin."</string>
- <!-- outdated translation 6839262446413155394 --> <string name="permdesc_getAccounts" product="default" msgid="2735689364629830348">"Permetta ad ina applicaziun da consultar la glista dals contos enconuschents al telefonin."</string>
+ <!-- no translation found for permdesc_getAccounts (3238360555257773358) -->
+ <skip />
+ <!-- no translation found for permdesc_getAccounts (2735689364629830348) -->
+ <skip />
<string name="permlab_authenticateAccounts" msgid="3940505577982882450">"agir sco autentificatur da contos"</string>
- <!-- outdated translation 4006839406474208874 --> <string name="permdesc_authenticateAccounts" msgid="5472124296908977260">"\"Permetta ad ina applicaziun dad utilisar las funcziuns d\'autentificaziun da conto da l\'administratur da contos, inclus funcziuns per crear contos ed obtegnair e definir lur pleds-clav.\""</string>
+ <!-- no translation found for permdesc_authenticateAccounts (5472124296908977260) -->
+ <skip />
<string name="permlab_manageAccounts" msgid="4440380488312204365">"administrar la glista da contos"</string>
- <!-- outdated translation 8804114016661104517 --> <string name="permdesc_manageAccounts" msgid="8698295625488292506">"Permetta ad ina applicaziun dad agiuntar ed allontanar contos e stizzar lur pleds-clav."</string>
+ <!-- no translation found for permdesc_manageAccounts (8698295625488292506) -->
+ <skip />
<string name="permlab_useCredentials" msgid="6401886092818819856">"utilisar las infurmaziuns dad autentificaziun dad in conto"</string>
- <!-- outdated translation 7416570544619546974 --> <string name="permdesc_useCredentials" msgid="7984227147403346422">"Permetta ad ina applicaziun da dumandar tokens d\'autentificaziun."</string>
+ <!-- no translation found for permdesc_useCredentials (7984227147403346422) -->
+ <skip />
<string name="permlab_accessNetworkState" msgid="6865575199464405769">"mussar il status da la rait"</string>
- <!-- outdated translation 558721128707712766 --> <string name="permdesc_accessNetworkState" msgid="479772796952547198">"Permetta ad ina applicaziun da vesair ils status da tut las raits."</string>
+ <!-- no translation found for permdesc_accessNetworkState (479772796952547198) -->
+ <skip />
<string name="permlab_createNetworkSockets" msgid="9121633680349549585">"access cumplet a l\'internet"</string>
- <!-- outdated translation 4593339106921772192 --> <string name="permdesc_createNetworkSockets" msgid="5963922297444265950">"Permetta ad ina applicaziun da crear sockets da rait."</string>
- <!-- outdated translation 7823599210086622545 --> <string name="permlab_writeApnSettings" msgid="505660159675751896">"scriver parameters per nums da puncts d\'access"</string>
- <!-- outdated translation 7443433457842966680 --> <string name="permdesc_writeApnSettings" msgid="5333798886412714193">"\"Permetta ad ina applicaziun da modifitgar ils parameters APN (num dals puncts d\'access), sco proxy ni port da mintga APN.\""</string>
+ <!-- no translation found for permdesc_createNetworkSockets (5963922297444265950) -->
+ <skip />
+ <!-- no translation found for permlab_writeApnSettings (505660159675751896) -->
+ <skip />
+ <!-- no translation found for permdesc_writeApnSettings (5333798886412714193) -->
+ <skip />
<string name="permlab_changeNetworkState" msgid="958884291454327309">"modifitgar la connectivitad da la rait"</string>
- <!-- outdated translation 4199958910396387075 --> <string name="permdesc_changeNetworkState" msgid="6789123912476416214">"Permetta ad ina applicaziun da modifitgar il status da connectivitad da la rait."</string>
- <!-- outdated translation 2702121155761140799 --> <string name="permlab_changeTetherState" msgid="5952584964373017960">"midar la connectivitad da tethering"</string>
- <!-- outdated translation 8905815579146349568 --> <string name="permdesc_changeTetherState" msgid="1524441344412319780">"Permetta ad ina applicaziun da modifitgar il status da connectivitad dal tethering."</string>
+ <!-- no translation found for permdesc_changeNetworkState (6789123912476416214) -->
+ <skip />
+ <!-- no translation found for permlab_changeTetherState (5952584964373017960) -->
+ <skip />
+ <!-- no translation found for permdesc_changeTetherState (1524441344412319780) -->
+ <skip />
<string name="permlab_changeBackgroundDataSetting" msgid="1400666012671648741">"modifitgar il parameter d\'utilisaziun da datas dal fund davos"</string>
- <!-- outdated translation 1001482853266638864 --> <string name="permdesc_changeBackgroundDataSetting" msgid="5347729578468744379">"Permetta ad ina applicaziun da modifitgar il parameters d\'utilisaziun da las datas dal fund davos."</string>
+ <!-- no translation found for permdesc_changeBackgroundDataSetting (5347729578468744379) -->
+ <skip />
<string name="permlab_accessWifiState" msgid="8100926650211034400">"mussar il status WLAN"</string>
- <!-- outdated translation 485796529139236346 --> <string name="permdesc_accessWifiState" msgid="7770452658226256831">"Permetta ad ina applicaziun da vesair las infurmaziuns concernent il status WLAN."</string>
+ <!-- no translation found for permdesc_accessWifiState (7770452658226256831) -->
+ <skip />
<string name="permlab_changeWifiState" msgid="7280632711057112137">"modifitgar il status WLAN"</string>
- <!-- outdated translation 2950383153656873267 --> <string name="permdesc_changeWifiState" msgid="7399961004537946240">"\"Permetta ad ina applicaziun da stabilir ina connexiun a puncts d\'access WLAN, da sa deconnectar da quels e da modifitgar ils parameters da raits WLAN configuradas.\""</string>
+ <!-- no translation found for permdesc_changeWifiState (7399961004537946240) -->
+ <skip />
<string name="permlab_changeWifiMulticastState" msgid="1368253871483254784">"permetter la recepziun da multicast WLAN"</string>
- <!-- outdated translation 8199464507656067553 --> <string name="permdesc_changeWifiMulticastState" msgid="7633598524564320817">"Permetta ad ina applicaziun da retschaiver pachets da datas che n\'èn betg adressads directamain a Voss apparat. Quai po esser nizzaivel per tschertgar servetschs che vegnan mess a disposiziun en il conturn. Consumescha dapli energia ch\'il modus betg-multicast."</string>
- <!-- outdated translation 1092209628459341292 --> <string name="permlab_bluetoothAdmin" msgid="3606576270792236062">"administraziun bluetooth"</string>
- <!-- outdated translation 7256289774667054555 --> <string name="permdesc_bluetoothAdmin" product="tablet" msgid="6921177471748882137">"\"Permetta ad ina applicaziun da configurar il telefon bluetooth local, dad identifitgar apparats periferics a distanza e d\'als associar cun il telefon.\""</string>
- <!-- outdated translation 7256289774667054555 --> <string name="permdesc_bluetoothAdmin" product="default" msgid="8931682159331542137">"\"Permetta ad ina applicaziun da configurar il telefon bluetooth local, dad identifitgar apparats periferics a distanza e d\'als associar cun il telefon.\""</string>
+ <!-- no translation found for permdesc_changeWifiMulticastState (7633598524564320817) -->
+ <skip />
+ <!-- no translation found for permlab_bluetoothAdmin (3606576270792236062) -->
+ <skip />
+ <!-- no translation found for permdesc_bluetoothAdmin (6921177471748882137) -->
+ <skip />
+ <!-- no translation found for permdesc_bluetoothAdmin (8931682159331542137) -->
+ <skip />
+ <!-- no translation found for permlab_accessWimaxState (1232061307208861588) -->
+ <skip />
+ <!-- no translation found for permdesc_accessWimaxState (5914958077555177749) -->
+ <skip />
+ <!-- no translation found for permlab_changeWimaxState (2405042267131496579) -->
+ <skip />
+ <!-- no translation found for permdesc_changeWimaxState (3328853825006455912) -->
+ <skip />
<string name="permlab_bluetooth" msgid="8361038707857018732">"stabilir connexiuns bluetooth"</string>
- <!-- outdated translation 762515380679392945 --> <string name="permdesc_bluetooth" product="tablet" msgid="7007851048416363446">"Permetta ad ina applicaziun dad obtegnair la configuraziun dal telefon bluetooth local e da crear ed acceptar connexiuns ad apparats associads."</string>
- <!-- outdated translation 762515380679392945 --> <string name="permdesc_bluetooth" product="default" msgid="31846362767164948">"Permetta ad ina applicaziun dad obtegnair la configuraziun dal telefon bluetooth local e da crear ed acceptar connexiuns ad apparats associads."</string>
+ <!-- no translation found for permdesc_bluetooth (7007851048416363446) -->
+ <skip />
+ <!-- no translation found for permdesc_bluetooth (31846362767164948) -->
+ <skip />
<!-- no translation found for permlab_nfc (4423351274757876953) -->
<skip />
<!-- no translation found for permdesc_nfc (7120611819401789907) -->
<skip />
<string name="permlab_disableKeyguard" msgid="4977406164311535092">"deactivar la bloccaziun da la tastatura"</string>
- <!-- outdated translation 3189763479326302017 --> <string name="permdesc_disableKeyguard" msgid="6231611286892232626">"Permetta ad ina applicaziun da deactivar la bloccaziun da la tastatura e la protecziun cun il pled-clav associada. In exempel dad ina utilisaziun legitima: La bloccaziun da la tastatura vegn deactivada sche Vus retschavais in clom ed ella vegn reactivada sche Vus finis il telefon."</string>
+ <!-- no translation found for permdesc_disableKeyguard (6231611286892232626) -->
+ <skip />
<string name="permlab_readSyncSettings" msgid="6201810008230503052">"leger ils parameters da sincronisaziun"</string>
- <!-- outdated translation 5315925706353341823 --> <string name="permdesc_readSyncSettings" msgid="5464056785274229278">"Permetta ad ina applicaziun da leger ils parameters da sincronisaziun (per exempel per savair sche la sincronisaziun da contacts è activà u betg)."</string>
+ <!-- no translation found for permdesc_readSyncSettings (5464056785274229278) -->
+ <skip />
<string name="permlab_writeSyncSettings" msgid="6297138566442486462">"scriver configuraziuns da sincronisaziun"</string>
- <!-- outdated translation 2498201614431360044 --> <string name="permdesc_writeSyncSettings" msgid="1466056564502117130">"Permetta ad ina applicaziun da modifitgar ils parameters da sincronisaziun. Uschia po ella per exempel activar e deactivar la sincronisaziun da contacts."</string>
+ <!-- no translation found for permdesc_writeSyncSettings (1466056564502117130) -->
+ <skip />
<string name="permlab_readSyncStats" msgid="7396577451360202448">"leger las statisticas da sincronisaziun"</string>
- <!-- outdated translation 7511448343374465000 --> <string name="permdesc_readSyncStats" msgid="3801971839939951678">"Permetta ad ina applicaziun da leger las statisticas da sincronisaziun (per exempel la cronologia da las sincronisaziuns exequidas)."</string>
+ <!-- no translation found for permdesc_readSyncStats (3801971839939951678) -->
+ <skip />
<string name="permlab_subscribedFeedsRead" msgid="4756609637053353318">"leger feeds abunads"</string>
- <!-- outdated translation 3622200625634207660 --> <string name="permdesc_subscribedFeedsRead" msgid="5557058907906144505">"Permetta ad ina applicaziun dad obtegnair infurmaziuns davart ils feeds actualisads dacurt."</string>
+ <!-- no translation found for permdesc_subscribedFeedsRead (5557058907906144505) -->
+ <skip />
<string name="permlab_subscribedFeedsWrite" msgid="9015246325408209296">"scriver feeds abunads"</string>
- <!-- outdated translation 8121607099326533878 --> <string name="permdesc_subscribedFeedsWrite" msgid="6928930188826089413">"Permetta ad ina applicaziun da modifitgar Voss feeds sincronisads dacurt. Applicaziuns donnegiusas pudessan uschia modifitgar Voss feeds sincronisads."</string>
- <!-- outdated translation 432535716804748781 --> <string name="permlab_readDictionary" msgid="8410247960433376352">"leger il dicziunari definì da l\'utilisader"</string>
- <!-- outdated translation 1082972603576360690 --> <string name="permdesc_readDictionary" msgid="8977815988329283705">"Permetta ad ina applicaziun da leger tut ils pleds e nums privats e las expressiuns privatas che in utilisader ha memorisà en ses dicziunari."</string>
- <!-- outdated translation 6703109511836343341 --> <string name="permlab_writeDictionary" msgid="2296383164914812772">"scriver en il dicziunari definì da l\'utilisader"</string>
- <!-- outdated translation 2241256206524082880 --> <string name="permdesc_writeDictionary" msgid="8185385716255065291">"Permetta ad ina applicaziun da scriver novs pleds en il dicziunari dal utilisader."</string>
- <!-- outdated translation 8079403759001777291 --> <string name="permlab_sdcardWrite" product="nosdcard" msgid="85430876310764752">"modifitgar/stizzar cuntegns da la carta SD"</string>
+ <!-- no translation found for permdesc_subscribedFeedsWrite (6928930188826089413) -->
+ <skip />
+ <!-- no translation found for permlab_readDictionary (8410247960433376352) -->
+ <skip />
+ <!-- no translation found for permdesc_readDictionary (8977815988329283705) -->
+ <skip />
+ <!-- no translation found for permlab_writeDictionary (2296383164914812772) -->
+ <skip />
+ <!-- no translation found for permdesc_writeDictionary (8185385716255065291) -->
+ <skip />
+ <!-- no translation found for permlab_sdcardWrite (85430876310764752) -->
+ <skip />
<string name="permlab_sdcardWrite" product="default" msgid="8079403759001777291">"modifitgar/stizzar cuntegns da la carta SD"</string>
- <!-- outdated translation 6643963204976471878 --> <string name="permdesc_sdcardWrite" product="nosdcard" msgid="6175406299445710888">"Permetta ad ina applicaziun da scriver sin la carta SD."</string>
- <!-- outdated translation 6643963204976471878 --> <string name="permdesc_sdcardWrite" product="default" msgid="4337417790936632090">"Permetta ad ina applicaziun da scriver sin la carta SD."</string>
+ <!-- no translation found for permdesc_sdcardWrite (6175406299445710888) -->
+ <skip />
+ <!-- no translation found for permdesc_sdcardWrite (4337417790936632090) -->
+ <skip />
<!-- no translation found for permlab_mediaStorageWrite (6859839199706879015) -->
<skip />
<!-- no translation found for permdesc_mediaStorageWrite (8189160597698529185) -->
<skip />
<string name="permlab_cache_filesystem" msgid="5656487264819669824">"access al sistem da datotecas da cache"</string>
- <!-- outdated translation 1624734528435659906 --> <string name="permdesc_cache_filesystem" msgid="5578967642265550955">"Permetta ad ina applicaziun da leger e da scriver en il sistem da datotecas dal cache."</string>
+ <!-- no translation found for permdesc_cache_filesystem (5578967642265550955) -->
+ <skip />
<!-- no translation found for permlab_use_sip (5986952362795870502) -->
<skip />
<!-- no translation found for permdesc_use_sip (4717632000062674294) -->
@@ -548,33 +783,44 @@
<skip />
<!-- no translation found for permlab_modifyNetworkAccounting (5088217309088729650) -->
<skip />
- <!-- no translation found for permdesc_modifyNetworkAccounting (8553240749784321765) -->
+ <!-- no translation found for permdesc_modifyNetworkAccounting (5443412866746198123) -->
<skip />
- <!-- outdated translation 4307861496302850201 --> <string name="policylab_limitPassword" msgid="4497420728857585791">"Limitar il pled-clav"</string>
- <!-- outdated translation 1719877245692318299 --> <string name="policydesc_limitPassword" msgid="9083400080861728056">"Restrenscher ils tips da pleds-clav che Vus pudais utilisar."</string>
- <!-- outdated translation 7374780712664285321 --> <string name="policylab_watchLogin" msgid="914130646942199503">"Survegliar las emprovas da s\'annunziar"</string>
- <!-- outdated translation 1961251179624843483 --> <string name="policydesc_watchLogin" product="tablet" msgid="3215729294215070072">"Survegliar las emprovas betg reussidas da s\'annunziar ad in apparat periferic / dad exequir ina acziun."</string>
- <!-- outdated translation 1961251179624843483 --> <string name="policydesc_watchLogin" product="default" msgid="5712323091846761073">"Survegliar las emprovas betg reussidas da s\'annunziar ad in apparat periferic / dad exequir ina acziun."</string>
- <!-- outdated translation 9084772090797485420 --> <string name="policylab_resetPassword" msgid="2620077191242688955">"Reinizialisar il pled-clav"</string>
- <!-- outdated translation 3332167600331799991 --> <string name="policydesc_resetPassword" msgid="5391240616981297361">"\"Definir ina nova valur per Voss pled-clav, uschia che l\'administratur As sto dar il pled-clav avant che Vus pudais s\'annunziar.\""</string>
- <!-- outdated translation 5760466025247634488 --> <string name="policylab_forceLock" msgid="2274085384704248431">"Sfurzar da bloccar"</string>
- <!-- outdated translation 2819868664946089740 --> <string name="policydesc_forceLock" msgid="5696964126226028442">"Controlla da la bloccaziun dad apparats periferics cun l\'obligaziun dad endatar danovamain il pled-clav."</string>
+ <!-- no translation found for policylab_limitPassword (4497420728857585791) -->
+ <skip />
+ <!-- no translation found for policydesc_limitPassword (3252114203919510394) -->
+ <skip />
+ <!-- no translation found for policylab_watchLogin (914130646942199503) -->
+ <skip />
+ <!-- no translation found for policydesc_watchLogin (3215729294215070072) -->
+ <skip />
+ <!-- no translation found for policydesc_watchLogin (5712323091846761073) -->
+ <skip />
+ <!-- no translation found for policylab_resetPassword (2620077191242688955) -->
+ <skip />
+ <!-- no translation found for policydesc_resetPassword (605963962301904458) -->
+ <skip />
+ <!-- no translation found for policylab_forceLock (2274085384704248431) -->
+ <skip />
+ <!-- no translation found for policydesc_forceLock (1141797588403827138) -->
+ <skip />
<string name="policylab_wipeData" msgid="3910545446758639713">"Stizzar tut las datas"</string>
- <!-- outdated translation 2314060933796396205 --> <string name="policydesc_wipeData" product="tablet" msgid="314455232799486222">"Restaurar ils parameters originals dal telefonin. Qua tras vegnan tut Vossas datas stizzadas senza dumonda da conferma."</string>
- <!-- outdated translation 2314060933796396205 --> <string name="policydesc_wipeData" product="default" msgid="7669895333814222586">"Restaurar ils parameters originals dal telefonin. Qua tras vegnan tut Vossas datas stizzadas senza dumonda da conferma."</string>
+ <!-- no translation found for policydesc_wipeData (4306184096067756876) -->
+ <skip />
+ <!-- no translation found for policydesc_wipeData (5096895604574188391) -->
+ <skip />
<string name="policylab_setGlobalProxy" msgid="2784828293747791446">"Definir il proxy global da l\'apparat"</string>
<string name="policydesc_setGlobalProxy" msgid="6387497466660154931">"Definir il proxy global da l\'apparat che duai vegnir utilisà sche la directiva è activada. Mo l\'emprim administratur dad apparats definescha il vair proxy global."</string>
<!-- no translation found for policylab_expirePassword (885279151847254056) -->
<skip />
- <!-- no translation found for policydesc_expirePassword (4844430354224822074) -->
+ <!-- no translation found for policydesc_expirePassword (1729725226314691591) -->
<skip />
<!-- no translation found for policylab_encryptedStorage (8901326199909132915) -->
<skip />
- <!-- no translation found for policydesc_encryptedStorage (8877192718681120469) -->
+ <!-- no translation found for policydesc_encryptedStorage (2637732115325316992) -->
<skip />
<!-- no translation found for policylab_disableCamera (6395301023152297826) -->
<skip />
- <!-- no translation found for policydesc_disableCamera (5680054212889413366) -->
+ <!-- no translation found for policydesc_disableCamera (2306349042834754597) -->
<skip />
<string-array name="phoneTypes">
<item msgid="8901098336658710359">"Privat"</item>
@@ -644,7 +890,8 @@
<skip />
<string name="eventTypeBirthday" msgid="2813379844211390740">"Anniversari"</string>
<string name="eventTypeAnniversary" msgid="3876779744518284000">"Anniversari"</string>
- <!-- outdated translation 5834288791948564594 --> <string name="eventTypeOther" msgid="7388178939010143077">"Termin"</string>
+ <!-- no translation found for eventTypeOther (7388178939010143077) -->
+ <skip />
<string name="emailTypeCustom" msgid="8525960257804213846">"Persunalisà"</string>
<string name="emailTypeHome" msgid="449227236140433919">"Privat"</string>
<string name="emailTypeWork" msgid="3548058059601149973">"Lavur"</string>
@@ -709,7 +956,8 @@
<skip />
<!-- no translation found for sipAddressTypeOther (4408436162950119849) -->
<skip />
- <!-- outdated translation 3731488827218876115 --> <string name="keyguard_password_enter_pin_code" msgid="3037685796058495017">"Endatar il code PIN"</string>
+ <!-- no translation found for keyguard_password_enter_pin_code (3037685796058495017) -->
+ <skip />
<!-- no translation found for keyguard_password_enter_puk_code (4800725266925845333) -->
<skip />
<!-- no translation found for keyguard_password_enter_puk_prompt (1341112146710087048) -->
@@ -718,12 +966,16 @@
<skip />
<!-- no translation found for keyguard_password_entry_touch_hint (7858547464982981384) -->
<skip />
- <!-- outdated translation 9138158344813213754 --> <string name="keyguard_password_enter_password_code" msgid="1054721668279049780">"Endatai il pled-clav per debloccar."</string>
- <!-- outdated translation 638347075625491514 --> <string name="keyguard_password_enter_pin_password_code" msgid="6391755146112503443">"Endatar il PIN per debloccar"</string>
- <string name="keyguard_password_wrong_pin_code" msgid="1295984114338107718">"Code PIN nuncorrect!"</string>
+ <!-- no translation found for keyguard_password_enter_password_code (1054721668279049780) -->
+ <skip />
+ <!-- no translation found for keyguard_password_enter_pin_password_code (6391755146112503443) -->
+ <skip />
+ <!-- no translation found for keyguard_password_wrong_pin_code (2422225591006134936) -->
+ <skip />
<string name="keyguard_label_text" msgid="861796461028298424">"Smatgai per debloccar sin la tasta Menu e lura sin 0."</string>
<string name="emergency_call_dialog_number_for_display" msgid="696192103195090970">"Numer d\'urgenza"</string>
- <!-- outdated translation 8812714795156374435 --> <string name="lockscreen_carrier_default" msgid="8963839242565653192">"(nagin servetsch)"</string>
+ <!-- no translation found for lockscreen_carrier_default (8963839242565653192) -->
+ <skip />
<string name="lockscreen_screen_locked" msgid="7288443074806832904">"Visur bloccà."</string>
<string name="lockscreen_instructions_when_pattern_enabled" msgid="46154051614126049">"Smatgai la tasta Menu per debloccar il telefonin u telefonar sin in numer d\'urgenza."</string>
<string name="lockscreen_instructions_when_pattern_disabled" msgid="686260028797158364">"Smatgar la tasta da menu per debloccar."</string>
@@ -731,17 +983,23 @@
<string name="lockscreen_emergency_call" msgid="5347633784401285225">"Numer d\'urgenza"</string>
<string name="lockscreen_return_to_call" msgid="5244259785500040021">"Enavos al clom"</string>
<string name="lockscreen_pattern_correct" msgid="9039008650362261237">"Correct!"</string>
- <!-- outdated translation 4817583279053112312 --> <string name="lockscreen_pattern_wrong" msgid="4317955014948108794">"Quai ans displascha. Empruvai anc ina giada."</string>
- <!-- outdated translation 6237443657358168819 --> <string name="lockscreen_password_wrong" msgid="5737815393253165301">"\"Perstgisai, empruvai anc ina giada.\""</string>
+ <!-- no translation found for lockscreen_pattern_wrong (4317955014948108794) -->
+ <skip />
+ <!-- no translation found for lockscreen_password_wrong (5737815393253165301) -->
+ <skip />
+ <!-- no translation found for faceunlock_multiple_failures (754137583022792429) -->
+ <skip />
<!-- no translation found for lockscreen_plugged_in (8057762828355572315) -->
<skip />
<string name="lockscreen_charged" msgid="4938930459620989972">"Chargià"</string>
<string name="lockscreen_battery_short" msgid="3617549178603354656">"<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
<string name="lockscreen_low_battery" msgid="1482873981919249740">"Connectai Voss chargiader."</string>
<string name="lockscreen_missing_sim_message_short" msgid="7381499217732227295">"Nagina carta SIM."</string>
- <!-- outdated translation 2186920585695169078 --> <string name="lockscreen_missing_sim_message" product="tablet" msgid="151659196095791474">"En il telefon na sa chatta nagina carta SIM."</string>
+ <!-- no translation found for lockscreen_missing_sim_message (151659196095791474) -->
+ <skip />
<string name="lockscreen_missing_sim_message" product="default" msgid="2186920585695169078">"En il telefon na sa chatta nagina carta SIM."</string>
- <!-- outdated translation 8874620818937719067 --> <string name="lockscreen_missing_sim_instructions" msgid="5372787138023272615">"Inseri per plaschair ina carta SIM."</string>
+ <!-- no translation found for lockscreen_missing_sim_instructions (5372787138023272615) -->
+ <skip />
<!-- no translation found for lockscreen_missing_sim_instructions_long (3526573099019319472) -->
<skip />
<!-- no translation found for lockscreen_permanent_disabled_sim_instructions (910904643433151371) -->
@@ -760,7 +1018,8 @@
<string name="lockscreen_network_locked_message" msgid="143389224986028501">"Rait bloccada"</string>
<!-- no translation found for lockscreen_sim_puk_locked_message (7441797339976230) -->
<skip />
- <!-- outdated translation 635967534992394321 --> <string name="lockscreen_sim_puk_locked_instructions" msgid="8127916255245181063">"Ulteriuras infurmaziuns chattais Vus en il manual u che Vus pudais contactar il servetsch da clientella."</string>
+ <!-- no translation found for lockscreen_sim_puk_locked_instructions (8127916255245181063) -->
+ <skip />
<string name="lockscreen_sim_locked_message" msgid="8066660129206001039">"La carta SIM è bloccada."</string>
<string name="lockscreen_sim_unlock_progress_dialog_message" msgid="595323214052881264">"Debloccar la carta SIM..."</string>
<!-- no translation found for lockscreen_too_many_failed_attempts_dialog_message (6481623830344107222) -->
@@ -784,15 +1043,18 @@
<string name="lockscreen_too_many_failed_attempts_countdown" msgid="6251480343394389665">"Empruvar anc ina giada en <xliff:g id="NUMBER">%d</xliff:g> secundas."</string>
<string name="lockscreen_forgot_pattern_button_text" msgid="2626999449610695930">"Emblidà il schema?"</string>
<string name="lockscreen_glogin_forgot_pattern" msgid="2588521501166032747">"Debloccaziun dal conto"</string>
- <string name="lockscreen_glogin_too_many_attempts" msgid="2446246026221678244">"Memia bleras tentativas!"</string>
- <string name="lockscreen_glogin_instructions" msgid="1816635201812207709">"S\'annunziai cun Voss conto Google per debloccar il telefonin."</string>
+ <!-- no translation found for lockscreen_glogin_too_many_attempts (2751368605287288808) -->
+ <skip />
+ <!-- no translation found for lockscreen_glogin_instructions (3931816256100707784) -->
+ <skip />
<string name="lockscreen_glogin_username_hint" msgid="8846881424106484447">"Num d\'utilisader (e-mail)"</string>
<string name="lockscreen_glogin_password_hint" msgid="5958028383954738528">"Pled-clav"</string>
<string name="lockscreen_glogin_submit_button" msgid="7130893694795786300">"S\'annunziar"</string>
<string name="lockscreen_glogin_invalid_input" msgid="1364051473347485908">"Num d\'utilisader u pled-clav nunvalid."</string>
- <!-- no translation found for lockscreen_glogin_account_recovery_hint (8253152905532900548) -->
+ <!-- no translation found for lockscreen_glogin_account_recovery_hint (1696924763690379073) -->
<skip />
- <string name="lockscreen_glogin_checking_password" msgid="6758890536332363322">"Verifitgar..."</string>
+ <!-- no translation found for lockscreen_glogin_checking_password (7114627351286933867) -->
+ <skip />
<string name="lockscreen_unlock_label" msgid="737440483220667054">"Debloccar"</string>
<string name="lockscreen_sound_on_label" msgid="9068877576513425970">"Tun activà"</string>
<string name="lockscreen_sound_off_label" msgid="996822825154319026">"Tun deactivà"</string>
@@ -813,15 +1075,17 @@
<string name="factorytest_not_system" msgid="4435201656767276723">"L\'acziun FACTORY_TEST vegn mo sustegnida per pachets installads en /system/app."</string>
<string name="factorytest_no_action" msgid="872991874799998561">"Betg chattà in pachet che porscha l\'acziun FACTORY_TEST."</string>
<string name="factorytest_reboot" msgid="6320168203050791643">"Reaviar il sistem"</string>
- <string name="js_dialog_title" msgid="8143918455087008109">"La pagina \'<xliff:g id="TITLE">%s</xliff:g>\' annunzia:"</string>
+ <!-- no translation found for js_dialog_title (1987483977834603872) -->
+ <skip />
<string name="js_dialog_title_default" msgid="6961903213729667573">"JavaScript"</string>
<!-- no translation found for js_dialog_before_unload (730366588032430474) -->
<skip />
<string name="save_password_label" msgid="6860261758665825069">"Confermar"</string>
- <!-- outdated translation 1068216937244567247 --> <string name="double_tap_toast" msgid="2729045387923870404">"Tip: Smatgar duas giadas per zoomar pli datiers u zoomar pli lontan."</string>
- <!-- no translation found for autofill_this_form (1272247532604569872) -->
+ <!-- no translation found for double_tap_toast (4595046515400268881) -->
<skip />
- <!-- no translation found for setup_autofill (8154593408885654044) -->
+ <!-- no translation found for autofill_this_form (4616758841157816676) -->
+ <skip />
+ <!-- no translation found for setup_autofill (7103495070180590814) -->
<skip />
<!-- no translation found for autofill_address_name_separator (2504700673286691795) -->
<skip />
@@ -856,10 +1120,13 @@
<!-- no translation found for autofill_emirate (2893880978835698818) -->
<skip />
<string name="permlab_readHistoryBookmarks" msgid="1284843728203412135">"leger la cronologia ed ils segnapaginas dal navigatur"</string>
- <!-- outdated translation 4981489815467617191 --> <string name="permdesc_readHistoryBookmarks" msgid="4577476392604595921">"\"Permetta a l\'applicaziun da leger tut las URLs visitadas, sco era ils segnapaginas dal navigatur.\""</string>
+ <!-- no translation found for permdesc_readHistoryBookmarks (4577476392604595921) -->
+ <skip />
<string name="permlab_writeHistoryBookmarks" msgid="9009434109836280374">"scriver en la cronologia ed en ils segnapaginas dal navigatur"</string>
- <!-- outdated translation 945571990357114950 --> <string name="permdesc_writeHistoryBookmarks" product="tablet" msgid="1757103804824209530">"\"Permetta ad ina applicaziun da modifitgar la cronologia u ils segnapaginas dal navigatur, memorisads sin Voss telefonin. Applicaziuns donnegiusas pon uschia stizzar u modifitgar las datas da Voss navigatur.\""</string>
- <!-- outdated translation 945571990357114950 --> <string name="permdesc_writeHistoryBookmarks" product="default" msgid="6693764355720719197">"\"Permetta ad ina applicaziun da modifitgar la cronologia u ils segnapaginas dal navigatur, memorisads sin Voss telefonin. Applicaziuns donnegiusas pon uschia stizzar u modifitgar las datas da Voss navigatur.\""</string>
+ <!-- no translation found for permdesc_writeHistoryBookmarks (1757103804824209530) -->
+ <skip />
+ <!-- no translation found for permdesc_writeHistoryBookmarks (6693764355720719197) -->
+ <skip />
<!-- no translation found for permlab_setAlarm (5924401328803615165) -->
<skip />
<!-- no translation found for permdesc_setAlarm (316392039157473848) -->
@@ -868,8 +1135,10 @@
<skip />
<!-- no translation found for permdesc_addVoicemail (6604508651428252437) -->
<skip />
- <!-- outdated translation 4715212655598275532 --> <string name="permlab_writeGeolocationPermissions" msgid="5962224158955273932">"Modifitgar las autorisaziuns da geolocalisaziun dal navigatur"</string>
- <!-- outdated translation 4011908282980861679 --> <string name="permdesc_writeGeolocationPermissions" msgid="1083743234522638747">"Permetta ad ina applicaziun da modifitgar las permissiuns da geolocalisaziun dal navigatur. Applicaziuns donnegiusas pon utilisar questa funcziun per trametter datas da posiziun a websites arbitraras."</string>
+ <!-- no translation found for permlab_writeGeolocationPermissions (5962224158955273932) -->
+ <skip />
+ <!-- no translation found for permdesc_writeGeolocationPermissions (1083743234522638747) -->
+ <skip />
<!-- no translation found for permlab_packageVerificationAgent (5568139100645829117) -->
<skip />
<!-- no translation found for permdesc_packageVerificationAgent (8437590190990843381) -->
@@ -882,7 +1151,8 @@
<string name="save_password_notnow" msgid="6389675316706699758">"Betg ussa"</string>
<string name="save_password_remember" msgid="6491879678996749466">"Memorisar"</string>
<string name="save_password_never" msgid="8274330296785855105">"Mai"</string>
- <!-- outdated translation 5661861460947222274 --> <string name="open_permission_deny" msgid="7374036708316629800">"Vus n\'avais betg las permissiuns necessarias per avrir questa pagina."</string>
+ <!-- no translation found for open_permission_deny (7374036708316629800) -->
+ <skip />
<string name="text_copied" msgid="4985729524670131385">"Il text è vegnì copià en l\'archiv provisoric."</string>
<string name="more_item_label" msgid="4650918923083320495">"Dapli"</string>
<string name="prepend_shortcut_label" msgid="2572214461676015642">"Menu+"</string>
@@ -986,9 +1256,12 @@
<string name="weeks" msgid="6509623834583944518">"emnas"</string>
<string name="year" msgid="4001118221013892076">"onn"</string>
<string name="years" msgid="6881577717993213522">"onns"</string>
- <!-- outdated translation 3359437293118172396 --> <string name="VideoView_error_title" msgid="5927895235831021723">"Betg reussì da reproducir il video."</string>
- <!-- outdated translation 897920883624437033 --> <string name="VideoView_error_text_invalid_progressive_playback" msgid="3186670335938670444">"\"Perstgisai, deplorablamain n\'è quest video betg valid per il streaming sin quest apparat.\""</string>
- <!-- outdated translation 710301040038083944 --> <string name="VideoView_error_text_unknown" msgid="4309847331399592194">"\"Perstgisai, impussibel da leger quest video.\""</string>
+ <!-- no translation found for VideoView_error_title (3534509135438353077) -->
+ <skip />
+ <!-- no translation found for VideoView_error_text_invalid_progressive_playback (3186670335938670444) -->
+ <skip />
+ <!-- no translation found for VideoView_error_text_unknown (3450439155187810085) -->
+ <skip />
<string name="VideoView_error_button" msgid="2822238215100679592">"OK"</string>
<string name="relative_time" msgid="1818557177829411417">"\"<xliff:g id="DATE">%1$s</xliff:g>, <xliff:g id="TIME">%2$s</xliff:g>\""</string>
<string name="noon" msgid="7245353528818587908">"mezdi"</string>
@@ -1006,10 +1279,9 @@
<!-- no translation found for delete (6098684844021697789) -->
<skip />
<string name="copyUrl" msgid="2538211579596067402">"Copiar l\'URL"</string>
- <!-- outdated translation 6738556348861347240 --> <string name="selectTextMode" msgid="1018691815143165326">"Selecziunar text…"</string>
- <string name="textSelectionCABTitle" msgid="5236850394370820357">"Selecziun da text"</string>
- <!-- unknown placeholder WORD in addToDictionary -->
+ <!-- no translation found for selectTextMode (1018691815143165326) -->
<skip />
+ <string name="textSelectionCABTitle" msgid="5236850394370820357">"Selecziun da text"</string>
<!-- no translation found for addToDictionary (9090375111134433012) -->
<skip />
<!-- no translation found for deleteText (7070985395199629156) -->
@@ -1017,23 +1289,28 @@
<string name="inputMethod" msgid="1653630062304567879">"Metoda d\'endataziun"</string>
<string name="editTextMenuTitle" msgid="4909135564941815494">"Acziuns da text"</string>
<string name="low_internal_storage_view_title" msgid="1399732408701697546">"Pauca capacitad da memorisar"</string>
- <!-- outdated translation 635106544616378836 --> <string name="low_internal_storage_view_text" product="tablet" msgid="4231085657068852042">"Mo pli pauca capacitad da memorisar."</string>
+ <!-- no translation found for low_internal_storage_view_text (4231085657068852042) -->
+ <skip />
<string name="low_internal_storage_view_text" product="default" msgid="635106544616378836">"Mo pli pauca capacitad da memorisar."</string>
<string name="ok" msgid="5970060430562524910">"OK"</string>
<string name="cancel" msgid="6442560571259935130">"Interrumper"</string>
<string name="yes" msgid="5362982303337969312">"OK"</string>
<string name="no" msgid="5141531044935541497">"Interrumper"</string>
<string name="dialog_alert_title" msgid="2049658708609043103">"Attenziun"</string>
- <!-- outdated translation 1760724998928255250 --> <string name="loading" msgid="7933681260296021180">"Chargiar…"</string>
+ <!-- no translation found for loading (7933681260296021180) -->
+ <skip />
<string name="capital_on" msgid="1544682755514494298">"ACTIVÀ"</string>
<string name="capital_off" msgid="6815870386972805832">"DEACTIVÀ"</string>
<string name="whichApplication" msgid="4533185947064773386">"Cumplettar l\'acziun cun"</string>
<string name="alwaysUse" msgid="4583018368000610438">"Utilisar questa applicaziun sco standard per questa acziun."</string>
- <!-- outdated translation 4815455344600932173 --> <string name="clearDefaultHintMsg" msgid="3252584689512077257">"Stizzar ils parameters da standard en Parameters da la pagina da partenza > Applicaziuns > Administrar las applicaziuns."</string>
- <string name="chooseActivity" msgid="1009246475582238425">"Tscherner ina acziun"</string>
+ <!-- no translation found for clearDefaultHintMsg (3252584689512077257) -->
+ <skip />
+ <!-- no translation found for chooseActivity (7486876147751803333) -->
+ <skip />
<!-- no translation found for chooseUsbActivity (6894748416073583509) -->
<skip />
- <!-- outdated translation 1691104391758345586 --> <string name="noApplications" msgid="2991814273936504689">"Nagina applicaziun po exequir questa acziun."</string>
+ <!-- no translation found for noApplications (2991814273936504689) -->
+ <skip />
<string name="aerr_title" msgid="1905800560317137752"></string>
<!-- no translation found for aerr_application (932628488013092776) -->
<skip />
@@ -1048,9 +1325,12 @@
<skip />
<!-- no translation found for anr_process (6513209874880517125) -->
<skip />
- <!-- outdated translation 3653416315450806396 --> <string name="force_close" msgid="8346072094521265605">"Sfurzar da serrar"</string>
+ <!-- no translation found for force_close (8346072094521265605) -->
+ <skip />
<string name="report" msgid="4060218260984795706">"Rapport"</string>
<string name="wait" msgid="7147118217226317732">"Spetgar"</string>
+ <!-- no translation found for webpage_unresponsive (3272758351138122503) -->
+ <skip />
<!-- no translation found for launch_warning_title (1547997780506713581) -->
<skip />
<!-- no translation found for launch_warning_replace (6202498949970281412) -->
@@ -1075,18 +1355,25 @@
<!-- no translation found for android_upgrading_complete (1405954754112999229) -->
<skip />
<string name="heavy_weight_notification" msgid="9087063985776626166">"<xliff:g id="APP">%1$s</xliff:g> vegn exequida"</string>
- <!-- outdated translation 2423977499339403402 --> <string name="heavy_weight_notification_detail" msgid="1721681741617898865">"Tscherner per midar a l\'applicaziun"</string>
- <!-- outdated translation 1135403633766694316 --> <string name="heavy_weight_switcher_title" msgid="7153167085403298169">"Midar dad ina applicaziun a l\'autra?"</string>
- <!-- outdated translation 4592075610079319667 --> <string name="heavy_weight_switcher_text" msgid="7022631924534406403">"Ina autra applicaziun vegn gia exequida e sto vegnir serrada avant ch\'ina nova po vegnir aviada."</string>
+ <!-- no translation found for heavy_weight_notification_detail (1721681741617898865) -->
+ <skip />
+ <!-- no translation found for heavy_weight_switcher_title (7153167085403298169) -->
+ <skip />
+ <!-- no translation found for heavy_weight_switcher_text (7022631924534406403) -->
+ <skip />
<string name="old_app_action" msgid="493129172238566282">"Turnar a <xliff:g id="OLD_APP">%1$s</xliff:g>"</string>
- <!-- outdated translation 942967900237208466 --> <string name="old_app_description" msgid="2082094275580358049">"Betg aviai la nova applicaziun."</string>
+ <!-- no translation found for old_app_description (2082094275580358049) -->
+ <skip />
<string name="new_app_action" msgid="5472756926945440706">"Aviar <xliff:g id="OLD_APP">%1$s</xliff:g>"</string>
- <!-- outdated translation 6830398339826789493 --> <string name="new_app_description" msgid="1932143598371537340">"Fermai l\'applicaziun veglia senza memorisar."</string>
- <string name="sendText" msgid="5132506121645618310">"Tscherner ina acziun per il text"</string>
+ <!-- no translation found for new_app_description (1932143598371537340) -->
+ <skip />
+ <!-- no translation found for sendText (5209874571959469142) -->
+ <skip />
<string name="volume_ringtone" msgid="6885421406845734650">"Volumen dal tun da scalin"</string>
<string name="volume_music" msgid="5421651157138628171">"Volumen da medias"</string>
<string name="volume_music_hint_playing_through_bluetooth" msgid="9165984379394601533">"Reproducir tras bluetooth"</string>
- <string name="volume_music_hint_silent_ringtone_selected" msgid="6158339745293431194">"Tschernì il modus silenzius per il tun da scalin"</string>
+ <!-- no translation found for volume_music_hint_silent_ringtone_selected (8310739960973156272) -->
+ <skip />
<string name="volume_call" msgid="3941680041282788711">"Volumen dals cloms entrants"</string>
<string name="volume_bluetooth_call" msgid="2002891926351151534">"Volumen da cloms entrants da bluetooth"</string>
<string name="volume_alarm" msgid="1985191616042689100">"Volumen dal svegliarin"</string>
@@ -1115,34 +1402,46 @@
<item quantity="one" msgid="1634101450343277345">"Rait WLAN averta disponibla"</item>
<item quantity="other" msgid="7915895323644292768">"Raits WLAN avertas disponiblas"</item>
</plurals>
- <!-- no translation found for wifi_available_sign_in (9157196203958866662) -->
+ <!-- no translation found for wifi_available_sign_in (4029489716605255386) -->
<skip />
<!-- no translation found for wifi_available_sign_in_detailed (6797764740339907572) -->
<skip />
<!-- no translation found for wifi_watchdog_network_disabled (7904214231651546347) -->
<skip />
- <!-- no translation found for wifi_watchdog_network_disabled_detailed (4917472096696322767) -->
+ <!-- no translation found for wifi_watchdog_network_disabled_detailed (5548780776418332675) -->
<skip />
<!-- no translation found for wifi_p2p_dialog_title (97611782659324517) -->
<skip />
- <!-- no translation found for wifi_p2p_turnon_message (2804722042556269129) -->
+ <!-- no translation found for wifi_p2p_turnon_message (2909250942299627244) -->
<skip />
- <!-- no translation found for wifi_p2p_failed_message (1820097493844848281) -->
+ <!-- no translation found for wifi_p2p_failed_message (3763669677935623084) -->
<skip />
- <!-- no translation found for wifi_p2p_pbc_go_negotiation_request_message (3170321684621420428) -->
+ <!-- no translation found for accept (1645267259272829559) -->
<skip />
- <!-- no translation found for wifi_p2p_pin_go_negotiation_request_message (5177412094633377308) -->
+ <!-- no translation found for decline (2112225451706137894) -->
<skip />
- <!-- no translation found for wifi_p2p_pin_display_message (2834049169114922902) -->
+ <!-- no translation found for wifi_p2p_invitation_sent_title (1318975185112070734) -->
+ <skip />
+ <!-- no translation found for wifi_p2p_invitation_to_connect_title (4958803948658533637) -->
+ <skip />
+ <!-- no translation found for wifi_p2p_from_message (570389174731951769) -->
+ <skip />
+ <!-- no translation found for wifi_p2p_to_message (248968974522044099) -->
+ <skip />
+ <!-- no translation found for wifi_p2p_enter_pin_message (5920929550367828970) -->
+ <skip />
+ <!-- no translation found for wifi_p2p_show_pin_message (8530563323880921094) -->
<skip />
<!-- no translation found for wifi_p2p_enabled_notification_title (2068321881673734886) -->
<skip />
<!-- no translation found for wifi_p2p_enabled_notification_message (1638949953993894335) -->
<skip />
<string name="select_character" msgid="3365550120617701745">"Inserir in caracter"</string>
- <!-- outdated translation 7630529934366549163 --> <string name="sms_control_default_app_name" msgid="3058577482636640465">"Applicaziun nunenconuschenta"</string>
+ <!-- no translation found for sms_control_default_app_name (3058577482636640465) -->
+ <skip />
<string name="sms_control_title" msgid="7296612781128917719">"Trametter messadis SMS"</string>
- <!-- outdated translation 1289331457999236205 --> <string name="sms_control_message" msgid="4073755190243093924">"Vulais Vus trametter in grond dumber da messadis SMS? Tschernì OK per cuntinuar u Interrumper per annullar la spediziun."</string>
+ <!-- no translation found for sms_control_message (4073755190243093924) -->
+ <skip />
<string name="sms_control_yes" msgid="2532062172402615953">"OK"</string>
<string name="sms_control_no" msgid="1715320703137199869">"Interrumper"</string>
<!-- no translation found for sim_removed_title (6227712319223226185) -->
@@ -1153,7 +1452,7 @@
<skip />
<!-- no translation found for sim_added_title (3719670512889674693) -->
<skip />
- <!-- no translation found for sim_added_message (1209265974048554242) -->
+ <!-- no translation found for sim_added_message (6599945301141050216) -->
<skip />
<!-- no translation found for sim_restart_button (4722407842815232347) -->
<skip />
@@ -1166,25 +1465,37 @@
<string name="no_permissions" msgid="7283357728219338112">"Naginas permissiuns obligatoricas"</string>
<string name="perms_hide" msgid="7283915391320676226"><b>"Zuppentar"</b></string>
<string name="perms_show_all" msgid="2671791163933091180"><b>"Mussar tut"</b></string>
- <string name="usb_storage_activity_title" msgid="2399289999608900443">"Memoria da massa USB"</string>
+ <!-- no translation found for usb_storage_activity_title (4465055157209648641) -->
+ <skip />
<string name="usb_storage_title" msgid="5901459041398751495">"Connectà cun agid d\'in cabel USB"</string>
- <!-- outdated translation 4796759646167247178 --> <string name="usb_storage_message" product="nosdcard" msgid="6631094834151575841">"\"Vus avais connectà Voss telefonin cun Voss computer cun agid dad in cabel USB. Tscherni il buttun sutvart per copiar datotecas da Voss computer sin la carta SD da Voss Android, u viceversa.\""</string>
- <!-- outdated translation 4796759646167247178 --> <string name="usb_storage_message" product="default" msgid="4510858346516069238">"\"Vus avais connectà Voss telefonin cun Voss computer cun agid dad in cabel USB. Tscherni il buttun sutvart per copiar datotecas da Voss computer sin la carta SD da Voss Android, u viceversa.\""</string>
+ <!-- no translation found for usb_storage_message (3308538094316477839) -->
+ <skip />
+ <!-- no translation found for usb_storage_message (805351000446037811) -->
+ <skip />
<string name="usb_storage_button_mount" msgid="1052259930369508235">"Activar la memoria USB"</string>
- <!-- outdated translation 2534784751603345363 --> <string name="usb_storage_error_message" product="nosdcard" msgid="3276413764430468454">"Cun l\'utilisaziun da Vossa carta SD sco memoria USB è cumparì in problem."</string>
- <!-- outdated translation 2534784751603345363 --> <string name="usb_storage_error_message" product="default" msgid="120810397713773275">"Cun l\'utilisaziun da Vossa carta SD sco memoria USB è cumparì in problem."</string>
+ <!-- no translation found for usb_storage_error_message (3017045217365540658) -->
+ <skip />
+ <!-- no translation found for usb_storage_error_message (2876018512716970313) -->
+ <skip />
<string name="usb_storage_notification_title" msgid="8175892554757216525">"Connectà cun in cabel USB"</string>
- <string name="usb_storage_notification_message" msgid="7380082404288219341">"Tscherni las datotecas che duain vegnir copiadas da/sin Voss computer."</string>
+ <!-- no translation found for usb_storage_notification_message (939822783828183763) -->
+ <skip />
<string name="usb_storage_stop_notification_title" msgid="2336058396663516017">"Deactivar la memoria USB"</string>
- <string name="usb_storage_stop_notification_message" msgid="2591813490269841539">"Tscherner per deactivar la memoria USB."</string>
+ <!-- no translation found for usb_storage_stop_notification_message (1656852098555623822) -->
+ <skip />
<string name="usb_storage_stop_title" msgid="660129851708775853">"La memoria USB vegn gest utilisada"</string>
- <!-- outdated translation 3613713396426604104 --> <string name="usb_storage_stop_message" product="nosdcard" msgid="1368842269463745067">"Verifitgai avant che deactivar la memoria USB che Vus avais demontà la carta SD Android da Voss computer."</string>
- <string name="usb_storage_stop_message" product="default" msgid="3613713396426604104">"Verifitgai avant che deactivar la memoria USB che Vus avais demontà la carta SD Android da Voss computer."</string>
+ <!-- no translation found for usb_storage_stop_message (4264025280777219521) -->
+ <skip />
+ <!-- no translation found for usb_storage_stop_message (8043969782460613114) -->
+ <skip />
<string name="usb_storage_stop_button_mount" msgid="7060218034900696029">"Deactivar l\'apparat periferic da memoria USB"</string>
- <string name="usb_storage_stop_error_message" msgid="143881914840412108">"Cun deactivar la memoria USB è in problem cumparì. Verifitgai che Vus avais demontà il host USB ed empruvai anc ina giada."</string>
+ <!-- no translation found for usb_storage_stop_error_message (1970374898263063836) -->
+ <skip />
<string name="dlg_confirm_kill_storage_users_title" msgid="963039033470478697">"Activar la memoria USB"</string>
- <!-- outdated translation 3202838234780505886 --> <string name="dlg_confirm_kill_storage_users_text" msgid="6206212680430268343">"Sche Vus activais l\'apparat periferic da memoria USB sa ferman tschertas applicaziuns che Vus utilisais. Ellas n\'èn probablamain betg disponiblas enfin che l\'apparat periferic vegn puspè deactivà."</string>
- <!-- outdated translation 8048999973837339174 --> <string name="dlg_error_title" msgid="7323658469626514207">"Operaziun USB betg reussida"</string>
+ <!-- no translation found for dlg_confirm_kill_storage_users_text (5100428757107469454) -->
+ <skip />
+ <!-- no translation found for dlg_error_title (7323658469626514207) -->
+ <skip />
<string name="dlg_ok" msgid="7376953167039865701">"OK"</string>
<!-- no translation found for usb_mtp_notification_title (3699913097391550394) -->
<skip />
@@ -1194,51 +1505,76 @@
<skip />
<!-- no translation found for usb_accessory_notification_title (7848236974087653666) -->
<skip />
- <!-- no translation found for usb_notification_message (4447869605109736382) -->
+ <!-- no translation found for usb_notification_message (2290859399983720271) -->
<skip />
- <!-- outdated translation 8663247929551095854 --> <string name="extmedia_format_title" product="nosdcard" msgid="9020092196061007262">"Formatar la carta SD"</string>
- <!-- outdated translation 8663247929551095854 --> <string name="extmedia_format_title" product="default" msgid="3648415921526526069">"Formatar la carta SD"</string>
- <!-- outdated translation 3621369962433523619 --> <string name="extmedia_format_message" product="nosdcard" msgid="3934016853425761078">"Vulais Vus propi formatar la carta SD? En quest cas van tut las datas sin Vossa carta a perder."</string>
- <!-- outdated translation 3621369962433523619 --> <string name="extmedia_format_message" product="default" msgid="14131895027543830">"Vulais Vus propi formatar la carta SD? En quest cas van tut las datas sin Vossa carta a perder."</string>
+ <!-- no translation found for extmedia_format_title (9020092196061007262) -->
+ <skip />
+ <!-- no translation found for extmedia_format_title (3648415921526526069) -->
+ <skip />
+ <!-- no translation found for extmedia_format_message (3934016853425761078) -->
+ <skip />
+ <!-- no translation found for extmedia_format_message (14131895027543830) -->
+ <skip />
<string name="extmedia_format_button_format" msgid="4131064560127478695">"Format"</string>
<string name="adb_active_notification_title" msgid="6729044778949189918">"Debugging USB connectà"</string>
- <!-- outdated translation 8470296818270110396 --> <string name="adb_active_notification_message" msgid="1016654627626476142">"Tscherner per deactivar il debugging USB."</string>
- <!-- outdated translation 6865512749462072765 --> <string name="select_input_method" msgid="4653387336791222978">"Tscherner ina metoda d\'endataziun"</string>
+ <!-- no translation found for adb_active_notification_message (1016654627626476142) -->
+ <skip />
+ <!-- no translation found for select_input_method (4653387336791222978) -->
+ <skip />
<!-- no translation found for configure_input_methods (9091652157722495116) -->
<skip />
<string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="candidates_style" msgid="4333913089637062257"><u>"candidats"</u></string>
- <!-- outdated translation 5457603418970994050 --> <string name="ext_media_checking_notification_title" product="nosdcard" msgid="3449816005351468560">"Preparaziun da la carta SD"</string>
+ <!-- no translation found for ext_media_checking_notification_title (3449816005351468560) -->
+ <skip />
<string name="ext_media_checking_notification_title" product="default" msgid="5457603418970994050">"Preparaziun da la carta SD"</string>
<string name="ext_media_checking_notification_message" msgid="8287319882926737053">"Tschertgar errurs"</string>
- <!-- outdated translation 780477838241212997 --> <string name="ext_media_nofs_notification_title" product="nosdcard" msgid="7788040745686229307">"Carta SD vida"</string>
+ <!-- no translation found for ext_media_nofs_notification_title (7788040745686229307) -->
+ <skip />
<string name="ext_media_nofs_notification_title" product="default" msgid="780477838241212997">"Carta SD vida"</string>
- <!-- outdated translation 1312266820092958014 --> <string name="ext_media_nofs_notification_message" product="nosdcard" msgid="8623130522556087311">"La carta SD è vida u ch\'ella utilisescha in sistem da datotecas che na vegn betg sustegnì."</string>
- <string name="ext_media_nofs_notification_message" product="default" msgid="3817704088027829380">"La carta SD è vida ubain che ses sistem da datotecas na vegn betg sustegnì."</string>
- <!-- outdated translation 6410723906019100189 --> <string name="ext_media_unmountable_notification_title" product="nosdcard" msgid="2090046769532713563">"Carta SD donnegiada"</string>
+ <!-- no translation found for ext_media_nofs_notification_message (7840121067427269500) -->
+ <skip />
+ <!-- no translation found for ext_media_nofs_notification_message (8641065641786923604) -->
+ <skip />
+ <!-- no translation found for ext_media_unmountable_notification_title (2090046769532713563) -->
+ <skip />
<string name="ext_media_unmountable_notification_title" product="default" msgid="6410723906019100189">"Carta SD donnegiada"</string>
- <!-- outdated translation 2679412884290061775 --> <string name="ext_media_unmountable_notification_message" product="nosdcard" msgid="529021299294450667">"La carta SD è donnegiada. Vus stuais eventualmain reformatar Vossa carta."</string>
- <string name="ext_media_unmountable_notification_message" product="default" msgid="6902531775948238989">"La carta SD è donnegiada. Vus stuais eventualmain reformatar la carta."</string>
- <!-- outdated translation 6872152882604407837 --> <string name="ext_media_badremoval_notification_title" product="nosdcard" msgid="1661683031330951073">"Allontanà la carta SD nunspetgadamain"</string>
+ <!-- no translation found for ext_media_unmountable_notification_message (1795917578395333280) -->
+ <skip />
+ <!-- no translation found for ext_media_unmountable_notification_message (1753898567525568253) -->
+ <skip />
+ <!-- no translation found for ext_media_badremoval_notification_title (1661683031330951073) -->
+ <skip />
<string name="ext_media_badremoval_notification_title" product="default" msgid="6872152882604407837">"Allontanà la carta SD nunspetgadamain"</string>
- <!-- outdated translation 7260183293747448241 --> <string name="ext_media_badremoval_notification_message" product="nosdcard" msgid="4329848819865594241">"Demontar la carta SD avant che retrair ella per evitar ina sperdita da datas."</string>
+ <!-- no translation found for ext_media_badremoval_notification_message (4329848819865594241) -->
+ <skip />
<string name="ext_media_badremoval_notification_message" product="default" msgid="7260183293747448241">"Demontar la carta SD avant che retrair ella per evitar ina sperdita da datas."</string>
- <!-- outdated translation 6729801130790616200 --> <string name="ext_media_safe_unmount_notification_title" product="nosdcard" msgid="3967973893270360230">"La carta SD po vegnir allontanada a moda segira"</string>
+ <!-- no translation found for ext_media_safe_unmount_notification_title (3967973893270360230) -->
+ <skip />
<string name="ext_media_safe_unmount_notification_title" product="default" msgid="6729801130790616200">"La carta SD po vegnir allontanada a moda segira"</string>
- <!-- outdated translation 7613960686747592770 --> <string name="ext_media_safe_unmount_notification_message" product="nosdcard" msgid="6142195361606493530">"La carta SD po ussa vegnir allontanada."</string>
+ <!-- no translation found for ext_media_safe_unmount_notification_message (6142195361606493530) -->
+ <skip />
<string name="ext_media_safe_unmount_notification_message" product="default" msgid="568841278138377604">"La carta SD po vegnir retratga a moda segira."</string>
- <!-- outdated translation 8902518030404381318 --> <string name="ext_media_nomedia_notification_title" product="nosdcard" msgid="4486377230140227651">"Allontanà la carta SD"</string>
+ <!-- no translation found for ext_media_nomedia_notification_title (4486377230140227651) -->
+ <skip />
<string name="ext_media_nomedia_notification_title" product="default" msgid="8902518030404381318">"Allontanà la carta SD"</string>
- <!-- outdated translation 4205117227342822275 --> <string name="ext_media_nomedia_notification_message" product="nosdcard" msgid="6921126162580574143">"La carta SD è vegnida allontanada. Inseri ina carta SD nova per engrondir la capacitad da memorisar da Voss apparat."</string>
+ <!-- no translation found for ext_media_nomedia_notification_message (6921126162580574143) -->
+ <skip />
<string name="ext_media_nomedia_notification_message" product="default" msgid="3870120652983659641">"Allontanà la carta SD. Inseri ina nova."</string>
- <string name="activity_list_empty" msgid="4168820609403385789">"Betg chattà activitads correspundentas"</string>
+ <!-- no translation found for activity_list_empty (1675388330786841066) -->
+ <skip />
<string name="permlab_pkgUsageStats" msgid="8787352074326748892">"actualisar las datas statisticas da la cumponenta"</string>
- <!-- outdated translation 891553695716752835 --> <string name="permdesc_pkgUsageStats" msgid="1106612424254277630">"Permetta da modifitgar las datas statisticas rimnadas da la cumponenta. Betg previs per applicaziuns normalas."</string>
- <!-- outdated translation 1660908117394854464 --> <string name="permlab_copyProtectedData" msgid="4341036311211406692">"Permetta da clamar il servetsch da container predefinì per copiar il cuntegn. Betg previs per applicaziuns normalas."</string>
- <!-- outdated translation 537780957633976401 --> <string name="permdesc_copyProtectedData" msgid="4390697124288317831">"Permetta da clamar il servetsch da container predefinì per copiar il cuntegn. Betg previs per applicaziuns normalas."</string>
- <!-- outdated translation 1311810005957319690 --> <string name="tutorial_double_tap_to_zoom_message_short" msgid="4070433208160063538">"Tutgar duas giadas per reglar il zoom"</string>
- <string name="gadget_host_error_inflating" msgid="2613287218853846830">"Errur cun engrondir il widget"</string>
+ <!-- no translation found for permdesc_pkgUsageStats (1106612424254277630) -->
+ <skip />
+ <!-- no translation found for permlab_copyProtectedData (4341036311211406692) -->
+ <skip />
+ <!-- no translation found for permdesc_copyProtectedData (4390697124288317831) -->
+ <skip />
+ <!-- no translation found for tutorial_double_tap_to_zoom_message_short (4070433208160063538) -->
+ <skip />
+ <!-- no translation found for gadget_host_error_inflating (4882004314906466162) -->
+ <skip />
<string name="ime_action_go" msgid="8320845651737369027">"Dai"</string>
<string name="ime_action_search" msgid="658110271822807811">"Tschertgar"</string>
<string name="ime_action_send" msgid="2316166556349314424">"Trametter"</string>
@@ -1249,41 +1585,49 @@
<string name="ime_action_default" msgid="2840921885558045721">"Exequir"</string>
<string name="dial_number_using" msgid="5789176425167573586">"Cumponer il numer"\n"cun utilisar <xliff:g id="NUMBER">%s</xliff:g>"</string>
<string name="create_contact_using" msgid="4947405226788104538">"Agiuntar in contact"\n"cun il numer <xliff:g id="NUMBER">%s</xliff:g>"</string>
- <!-- outdated translation 6824538733852821001 --> <string name="grant_credentials_permission_message_header" msgid="2106103817937859662">"Las suandantas applicaziuns dumondan l\'autorisaziun dad acceder a partir dad ussa a Voss conto."</string>
+ <!-- no translation found for grant_credentials_permission_message_header (2106103817937859662) -->
+ <skip />
<string name="grant_credentials_permission_message_footer" msgid="3125211343379376561">"Vulais Vus autorisar questa dumonda?"</string>
- <string name="grant_permissions_header_text" msgid="2722567482180797717">"Dumonda d\'access"</string>
+ <!-- no translation found for grant_permissions_header_text (6874497408201826708) -->
+ <skip />
<string name="allow" msgid="7225948811296386551">"Permetter"</string>
<string name="deny" msgid="2081879885755434506">"Refusar"</string>
- <string name="permission_request_notification_title" msgid="5390555465778213840">"Autorisaziun dumandada"</string>
- <string name="permission_request_notification_with_subtitle" msgid="4325409589686688000">"Autorisaziun dumandada"\n"per il conto <xliff:g id="ACCOUNT">%s</xliff:g>"</string>
+ <!-- no translation found for permission_request_notification_title (6486759795926237907) -->
+ <skip />
+ <!-- no translation found for permission_request_notification_with_subtitle (8530393139639560189) -->
+ <skip />
<string name="input_method_binding_label" msgid="1283557179944992649">"Metoda d\'endataziun"</string>
<string name="sync_binding_label" msgid="3687969138375092423">"Sincronisar"</string>
<string name="accessibility_binding_label" msgid="4148120742096474641">"Agids d\'access"</string>
<string name="wallpaper_binding_label" msgid="1240087844304687662">"Fund davos"</string>
<string name="chooser_wallpaper" msgid="7873476199295190279">"Midar il fund davos"</string>
- <!-- no translation found for vpn_title (8219003246858087489) -->
+ <!-- no translation found for vpn_title (19615213552042827) -->
<skip />
<!-- no translation found for vpn_title_long (6400714798049252294) -->
<skip />
- <!-- no translation found for vpn_text (1610714069627824309) -->
+ <!-- no translation found for vpn_text (3011306607126450322) -->
<skip />
- <!-- no translation found for vpn_text_long (4907843483284977618) -->
+ <!-- no translation found for vpn_text_long (6407351006249174473) -->
<skip />
<string name="upload_file" msgid="2897957172366730416">"Tscherner ina datoteca"</string>
<string name="no_file_chosen" msgid="6363648562170759465">"Nagina datoteca tschernida"</string>
<string name="reset" msgid="2448168080964209908">"Reinizialisar"</string>
<string name="submit" msgid="1602335572089911941">"Trametter"</string>
<string name="car_mode_disable_notification_title" msgid="3164768212003864316">"Modus dad auto activà"</string>
- <string name="car_mode_disable_notification_message" msgid="668663626721675614">"Tscherner per serrar il modus dad auto."</string>
+ <!-- no translation found for car_mode_disable_notification_message (8035230537563503262) -->
+ <skip />
<string name="tethered_notification_title" msgid="3146694234398202601">"Tethering u hotspot activ"</string>
- <string name="tethered_notification_message" msgid="3067108323903048927">"Tutgar per configurar"</string>
+ <!-- no translation found for tethered_notification_message (6857031760103062982) -->
+ <skip />
<string name="back_button_label" msgid="2300470004503343439">"Enavos"</string>
<string name="next_button_label" msgid="1080555104677992408">"Vinavant"</string>
<string name="skip_button_label" msgid="1275362299471631819">"Sursiglir"</string>
<string name="throttle_warning_notification_title" msgid="4890894267454867276">"Grond diever da datas mobilas"</string>
- <string name="throttle_warning_notification_message" msgid="2609734763845705708">"Tutgar per vegnir a savair dapli davart l\'utilisaziun da datas mobilas"</string>
+ <!-- no translation found for throttle_warning_notification_message (3340822228599337743) -->
+ <skip />
<string name="throttled_notification_title" msgid="6269541897729781332">"Surpassà la limita da datas mobilas"</string>
- <string name="throttled_notification_message" msgid="4712369856601275146">"Tutgar per vegnir a savair dapli davart l\'utilisaziun da datas mobilas"</string>
+ <!-- no translation found for throttled_notification_message (5443457321354907181) -->
+ <skip />
<!-- no translation found for no_matches (8129421908915840737) -->
<skip />
<!-- no translation found for find_on_page (1946799233822820384) -->
@@ -1292,13 +1636,13 @@
<!-- no translation found for matches_found:other (4641872797067609177) -->
<!-- no translation found for action_mode_done (7217581640461922289) -->
<skip />
- <!-- no translation found for progress_unmounting (535863554318797377) -->
+ <!-- no translation found for progress_unmounting (3923810448507612746) -->
<skip />
- <!-- no translation found for progress_unmounting (5556813978958789471) -->
+ <!-- no translation found for progress_unmounting (1327894998409537190) -->
<skip />
- <!-- no translation found for progress_erasing (4183664626203056915) -->
+ <!-- no translation found for progress_erasing (4521573321524340058) -->
<skip />
- <!-- no translation found for progress_erasing (2115214724367534095) -->
+ <!-- no translation found for progress_erasing (6596988875507043042) -->
<skip />
<!-- no translation found for format_error (6299769563624776948) -->
<skip />
@@ -1336,19 +1680,19 @@
<skip />
<!-- no translation found for sync_too_many_deletes (5296321850662746890) -->
<skip />
- <!-- no translation found for sync_too_many_deletes_desc (7030265992955132593) -->
+ <!-- no translation found for sync_too_many_deletes_desc (496551671008694245) -->
<skip />
- <!-- no translation found for sync_really_delete (8933566316059338692) -->
+ <!-- no translation found for sync_really_delete (2572600103122596243) -->
<skip />
- <!-- no translation found for sync_undo_deletes (8610996708225006328) -->
+ <!-- no translation found for sync_undo_deletes (2941317360600338602) -->
<skip />
- <!-- no translation found for sync_do_nothing (8717589462945226869) -->
+ <!-- no translation found for sync_do_nothing (3743764740430821845) -->
<skip />
<!-- no translation found for choose_account_label (5655203089746423927) -->
<skip />
<!-- no translation found for add_account_label (2935267344849993553) -->
<skip />
- <!-- no translation found for choose_account_text (6891230675141555481) -->
+ <!-- no translation found for choose_account_text (6303348737197849675) -->
<skip />
<!-- no translation found for add_account_button_label (3611982894853435874) -->
<skip />
@@ -1356,7 +1700,7 @@
<skip />
<!-- no translation found for number_picker_decrement_button (2576606679160067262) -->
<skip />
- <!-- no translation found for number_picker_increment_scroll_mode (1343063395404990189) -->
+ <!-- no translation found for number_picker_increment_scroll_mode (3073101067441638428) -->
<skip />
<!-- no translation found for number_picker_increment_scroll_action (4628981789985093179) -->
<skip />
@@ -1440,7 +1784,7 @@
<skip />
<!-- no translation found for description_target_unlock_tablet (3833195335629795055) -->
<skip />
- <!-- no translation found for keyboard_headset_required_to_hear_password (5913502399391940888) -->
+ <!-- no translation found for keyboard_headset_required_to_hear_password (7011927352267668657) -->
<skip />
<!-- no translation found for keyboard_password_character_no_headset (2859873770886153678) -->
<skip />
@@ -1450,17 +1794,17 @@
<skip />
<!-- no translation found for action_menu_overflow_description (2295659037509008453) -->
<skip />
- <!-- no translation found for storage_internal (7556050805474115618) -->
+ <!-- no translation found for storage_internal (4891916833657929263) -->
<skip />
- <!-- no translation found for storage_sd_card (8921771478629812343) -->
+ <!-- no translation found for storage_sd_card (3282948861378286745) -->
<skip />
<!-- no translation found for storage_usb (3017954059538517278) -->
<skip />
- <!-- no translation found for extract_edit_menu_button (302060189057163906) -->
+ <!-- no translation found for extract_edit_menu_button (8940478730496610137) -->
<skip />
<!-- no translation found for data_usage_warning_title (1955638862122232342) -->
<skip />
- <!-- no translation found for data_usage_warning_body (7217480745540055170) -->
+ <!-- no translation found for data_usage_warning_body (2814673551471969954) -->
<skip />
<!-- no translation found for data_usage_3g_limit_title (7093334419518706686) -->
<skip />
@@ -1470,7 +1814,7 @@
<skip />
<!-- no translation found for data_usage_wifi_limit_title (8992154736441284865) -->
<skip />
- <!-- no translation found for data_usage_limit_body (4313857592916426843) -->
+ <!-- no translation found for data_usage_limit_body (3317964706973601386) -->
<skip />
<!-- no translation found for data_usage_3g_limit_snoozed_title (7026739121138005231) -->
<skip />
@@ -1480,11 +1824,11 @@
<skip />
<!-- no translation found for data_usage_wifi_limit_snoozed_title (8743856006384825974) -->
<skip />
- <!-- no translation found for data_usage_limit_snoozed_body (2932736326652880660) -->
+ <!-- no translation found for data_usage_limit_snoozed_body (7035490278298441767) -->
<skip />
<!-- no translation found for data_usage_restricted_title (5965157361036321914) -->
<skip />
- <!-- no translation found for data_usage_restricted_body (5087354814839059798) -->
+ <!-- no translation found for data_usage_restricted_body (6741521330997452990) -->
<skip />
<!-- no translation found for ssl_certificate (6510040486049237639) -->
<skip />
@@ -1524,4 +1868,10 @@
<skip />
<!-- no translation found for list_delimeter (3975117572185494152) -->
<skip />
+ <!-- no translation found for sending (3245653681008218030) -->
+ <skip />
+ <!-- no translation found for launchBrowserDefault (2057951947297614725) -->
+ <skip />
+ <!-- no translation found for SetupCallDefault (5834948469253758575) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-ro/strings.xml b/core/res/res/values-ro/strings.xml
index bc7f619..ecee96d 100644
--- a/core/res/res/values-ro/strings.xml
+++ b/core/res/res/values-ro/strings.xml
@@ -915,6 +915,7 @@
<string name="force_close" msgid="8346072094521265605">"OK"</string>
<string name="report" msgid="4060218260984795706">"Raportaţi"</string>
<string name="wait" msgid="7147118217226317732">"Aşteptaţi"</string>
+ <string name="webpage_unresponsive" msgid="3272758351138122503">"Pagina a devenit inactivă."\n\n"Doriţi să o închideţi?"</string>
<string name="launch_warning_title" msgid="1547997780506713581">"Aplicaţie redirecţionată"</string>
<string name="launch_warning_replace" msgid="6202498949970281412">"<xliff:g id="APP_NAME">%1$s</xliff:g> funcţionează acum."</string>
<string name="launch_warning_original" msgid="188102023021668683">"<xliff:g id="APP_NAME">%1$s</xliff:g> a fost lansată iniţial."</string>
diff --git a/core/res/res/values-ru/strings.xml b/core/res/res/values-ru/strings.xml
index 1d71fd6..7b95291 100644
--- a/core/res/res/values-ru/strings.xml
+++ b/core/res/res/values-ru/strings.xml
@@ -915,6 +915,7 @@
<string name="force_close" msgid="8346072094521265605">"ОК"</string>
<string name="report" msgid="4060218260984795706">"Отзыв"</string>
<string name="wait" msgid="7147118217226317732">"Подождать"</string>
+ <string name="webpage_unresponsive" msgid="3272758351138122503">"Страница не отвечает."\n\n"Закрыть ее?"</string>
<string name="launch_warning_title" msgid="1547997780506713581">"Приложение перенаправлено"</string>
<string name="launch_warning_replace" msgid="6202498949970281412">"Приложение <xliff:g id="APP_NAME">%1$s</xliff:g> выполняется."</string>
<string name="launch_warning_original" msgid="188102023021668683">"Изначально было запущено приложение <xliff:g id="APP_NAME">%1$s</xliff:g>."</string>
diff --git a/core/res/res/values-sk/strings.xml b/core/res/res/values-sk/strings.xml
index cb2e764..aafaa9e 100644
--- a/core/res/res/values-sk/strings.xml
+++ b/core/res/res/values-sk/strings.xml
@@ -915,6 +915,7 @@
<string name="force_close" msgid="8346072094521265605">"OK"</string>
<string name="report" msgid="4060218260984795706">"Prehľad"</string>
<string name="wait" msgid="7147118217226317732">"Čakajte"</string>
+ <string name="webpage_unresponsive" msgid="3272758351138122503">"Stránka nereaguje."\n\n"Chcete ju zavrieť?"</string>
<string name="launch_warning_title" msgid="1547997780506713581">"Presmerovaná aplikácia"</string>
<string name="launch_warning_replace" msgid="6202498949970281412">"Je spustená aplikácia <xliff:g id="APP_NAME">%1$s</xliff:g>."</string>
<string name="launch_warning_original" msgid="188102023021668683">"Pôvodne bola spustená aplikácia <xliff:g id="APP_NAME">%1$s</xliff:g>."</string>
diff --git a/core/res/res/values-sl/strings.xml b/core/res/res/values-sl/strings.xml
index 5e7c136..aa98c80 100644
--- a/core/res/res/values-sl/strings.xml
+++ b/core/res/res/values-sl/strings.xml
@@ -915,6 +915,7 @@
<string name="force_close" msgid="8346072094521265605">"V redu"</string>
<string name="report" msgid="4060218260984795706">"Poročaj"</string>
<string name="wait" msgid="7147118217226317732">"Čakaj"</string>
+ <string name="webpage_unresponsive" msgid="3272758351138122503">"Stran se ne odziva."\n" "\n"Ali jo želite zapreti?"</string>
<string name="launch_warning_title" msgid="1547997780506713581">"Program preusmerjen"</string>
<string name="launch_warning_replace" msgid="6202498949970281412">"<xliff:g id="APP_NAME">%1$s</xliff:g> se izvaja."</string>
<string name="launch_warning_original" msgid="188102023021668683">"Prvotno je bil zagnan program <xliff:g id="APP_NAME">%1$s</xliff:g>."</string>
diff --git a/core/res/res/values-sr/strings.xml b/core/res/res/values-sr/strings.xml
index bea78ce..7ba8503 100644
--- a/core/res/res/values-sr/strings.xml
+++ b/core/res/res/values-sr/strings.xml
@@ -50,7 +50,7 @@
<string name="invalidPuk" msgid="8761456210898036513">"Унесите PUK који се састоји од 8 цифара или више."</string>
<string name="needPuk" msgid="919668385956251611">"SIM картица је закључана PUK кодом. Унесите PUK кôд да бисте је откључали."</string>
<string name="needPuk2" msgid="4526033371987193070">"Унесите PUK2 да бисте деблокирали SIM картицу."</string>
- <string name="ClipMmi" msgid="6952821216480289285">"Долазећи ИД позиваоца"</string>
+ <string name="ClipMmi" msgid="6952821216480289285">"Долазни ИД позиваоца"</string>
<string name="ClirMmi" msgid="7784673673446833091">"Одлазни ИД позиваоца"</string>
<string name="CfMmi" msgid="5123218989141573515">"Преусмеравање позива"</string>
<string name="CwMmi" msgid="9129678056795016867">"Позив на чекању"</string>
@@ -915,6 +915,7 @@
<string name="force_close" msgid="8346072094521265605">"Потврди"</string>
<string name="report" msgid="4060218260984795706">"Пријави"</string>
<string name="wait" msgid="7147118217226317732">"Сачекај"</string>
+ <string name="webpage_unresponsive" msgid="3272758351138122503">"Страница је престала да се одазива."\n\n" Да ли желите да је затворите?"</string>
<string name="launch_warning_title" msgid="1547997780506713581">"Апликација је преусмерена"</string>
<string name="launch_warning_replace" msgid="6202498949970281412">"Апликација <xliff:g id="APP_NAME">%1$s</xliff:g> је сада покренута."</string>
<string name="launch_warning_original" msgid="188102023021668683">"Првобитно је покренута апликација <xliff:g id="APP_NAME">%1$s</xliff:g>."</string>
diff --git a/core/res/res/values-sv/strings.xml b/core/res/res/values-sv/strings.xml
index bc59298..4d3cea5 100644
--- a/core/res/res/values-sv/strings.xml
+++ b/core/res/res/values-sv/strings.xml
@@ -915,6 +915,7 @@
<string name="force_close" msgid="8346072094521265605">"OK"</string>
<string name="report" msgid="4060218260984795706">"Rapportera"</string>
<string name="wait" msgid="7147118217226317732">"Vänta"</string>
+ <string name="webpage_unresponsive" msgid="3272758351138122503">"Sidan har slutat svara."\n\n"Vill du stänga sidan?"</string>
<string name="launch_warning_title" msgid="1547997780506713581">"Appen omdirigeras"</string>
<string name="launch_warning_replace" msgid="6202498949970281412">"<xliff:g id="APP_NAME">%1$s</xliff:g> körs."</string>
<string name="launch_warning_original" msgid="188102023021668683">"<xliff:g id="APP_NAME">%1$s</xliff:g> startades först."</string>
diff --git a/core/res/res/values-sw/strings.xml b/core/res/res/values-sw/strings.xml
index 5077d1f..a9a8679 100644
--- a/core/res/res/values-sw/strings.xml
+++ b/core/res/res/values-sw/strings.xml
@@ -915,6 +915,7 @@
<string name="force_close" msgid="8346072094521265605">"Sawa"</string>
<string name="report" msgid="4060218260984795706">"Ripoti"</string>
<string name="wait" msgid="7147118217226317732">"Subiri"</string>
+ <string name="webpage_unresponsive" msgid="3272758351138122503">"Ukurasa umekwama. "\n" "\n" Je, unataka kuufunga?"</string>
<string name="launch_warning_title" msgid="1547997780506713581">"Programu imeelekezwa kwingine"</string>
<string name="launch_warning_replace" msgid="6202498949970281412">"<xliff:g id="APP_NAME">%1$s</xliff:g>inaendesha sasa."</string>
<string name="launch_warning_original" msgid="188102023021668683">"<xliff:g id="APP_NAME">%1$s</xliff:g> ilizinduliwa mwanzoni."</string>
diff --git a/core/res/res/values-th/strings.xml b/core/res/res/values-th/strings.xml
index 0babb00..6a8431c 100644
--- a/core/res/res/values-th/strings.xml
+++ b/core/res/res/values-th/strings.xml
@@ -915,6 +915,7 @@
<string name="force_close" msgid="8346072094521265605">"ตกลง"</string>
<string name="report" msgid="4060218260984795706">"รายงาน"</string>
<string name="wait" msgid="7147118217226317732">"รอ"</string>
+ <string name="webpage_unresponsive" msgid="3272758351138122503">"หน้าเว็บนี้ไม่ตอบสนอง"\n\n"คุณต้องการปิดหรือไม่"</string>
<string name="launch_warning_title" msgid="1547997780506713581">"แอปฯ ที่เปลี่ยนเส้นทาง"</string>
<string name="launch_warning_replace" msgid="6202498949970281412">"<xliff:g id="APP_NAME">%1$s</xliff:g> กำลังทำงานอยู่ในขณะนี้"</string>
<string name="launch_warning_original" msgid="188102023021668683">"<xliff:g id="APP_NAME">%1$s</xliff:g> เปิดใช้ไว้แล้ว"</string>
diff --git a/core/res/res/values-tl/strings.xml b/core/res/res/values-tl/strings.xml
index b31fbf7..04635c8 100644
--- a/core/res/res/values-tl/strings.xml
+++ b/core/res/res/values-tl/strings.xml
@@ -915,6 +915,7 @@
<string name="force_close" msgid="8346072094521265605">"OK"</string>
<string name="report" msgid="4060218260984795706">"Ulat"</string>
<string name="wait" msgid="7147118217226317732">"Maghintay"</string>
+ <string name="webpage_unresponsive" msgid="3272758351138122503">"Hindi na tumutugon ang pahina."\n\n"Nais mo ba itong isara?"</string>
<string name="launch_warning_title" msgid="1547997780506713581">"Na-redirect ang app"</string>
<string name="launch_warning_replace" msgid="6202498949970281412">"Tumatakbo na ngayon ang <xliff:g id="APP_NAME">%1$s</xliff:g>."</string>
<string name="launch_warning_original" msgid="188102023021668683">"Orihinal na nalunsad ang <xliff:g id="APP_NAME">%1$s</xliff:g>."</string>
diff --git a/core/res/res/values-tr/strings.xml b/core/res/res/values-tr/strings.xml
index ebade95..bfe9c0a 100644
--- a/core/res/res/values-tr/strings.xml
+++ b/core/res/res/values-tr/strings.xml
@@ -915,6 +915,7 @@
<string name="force_close" msgid="8346072094521265605">"Tamam"</string>
<string name="report" msgid="4060218260984795706">"Bildir"</string>
<string name="wait" msgid="7147118217226317732">"Bekle"</string>
+ <string name="webpage_unresponsive" msgid="3272758351138122503">"Sayfa yanıt vermiyor."\n\n"Kapatmak ister misiniz?"</string>
<string name="launch_warning_title" msgid="1547997780506713581">"Uygulama yönlendirildi"</string>
<string name="launch_warning_replace" msgid="6202498949970281412">"<xliff:g id="APP_NAME">%1$s</xliff:g> şimdi çalışıyor."</string>
<string name="launch_warning_original" msgid="188102023021668683">"İlk olarak <xliff:g id="APP_NAME">%1$s</xliff:g> başlatıldı."</string>
diff --git a/core/res/res/values-uk/strings.xml b/core/res/res/values-uk/strings.xml
index bc5456b..6708893 100644
--- a/core/res/res/values-uk/strings.xml
+++ b/core/res/res/values-uk/strings.xml
@@ -915,6 +915,7 @@
<string name="force_close" msgid="8346072094521265605">"OK"</string>
<string name="report" msgid="4060218260984795706">"Повідом."</string>
<string name="wait" msgid="7147118217226317732">"Чекати"</string>
+ <string name="webpage_unresponsive" msgid="3272758351138122503">"Сторінка не відповідає."\n\n"Закрити її?"</string>
<string name="launch_warning_title" msgid="1547997780506713581">"Програму переадресовано"</string>
<string name="launch_warning_replace" msgid="6202498949970281412">"Зараз працює <xliff:g id="APP_NAME">%1$s</xliff:g>."</string>
<string name="launch_warning_original" msgid="188102023021668683">"Спочатку було запущено <xliff:g id="APP_NAME">%1$s</xliff:g>."</string>
diff --git a/core/res/res/values-vi/strings.xml b/core/res/res/values-vi/strings.xml
index 177c474..6da402c 100644
--- a/core/res/res/values-vi/strings.xml
+++ b/core/res/res/values-vi/strings.xml
@@ -915,6 +915,7 @@
<string name="force_close" msgid="8346072094521265605">"OK"</string>
<string name="report" msgid="4060218260984795706">"Báo cáo"</string>
<string name="wait" msgid="7147118217226317732">"Đợi"</string>
+ <string name="webpage_unresponsive" msgid="3272758351138122503">"Trang không phản hồi."\n\n"Bạn có muốn đóng trang không?"</string>
<string name="launch_warning_title" msgid="1547997780506713581">"Đã chuyển hướng ứng dụng"</string>
<string name="launch_warning_replace" msgid="6202498949970281412">"<xliff:g id="APP_NAME">%1$s</xliff:g> hiện đang chạy."</string>
<string name="launch_warning_original" msgid="188102023021668683">"<xliff:g id="APP_NAME">%1$s</xliff:g> được khởi chạy trước tiên."</string>
diff --git a/core/res/res/values-zh-rCN/strings.xml b/core/res/res/values-zh-rCN/strings.xml
index b682eac..6c40202 100644
--- a/core/res/res/values-zh-rCN/strings.xml
+++ b/core/res/res/values-zh-rCN/strings.xml
@@ -915,6 +915,7 @@
<string name="force_close" msgid="8346072094521265605">"确定"</string>
<string name="report" msgid="4060218260984795706">"报告"</string>
<string name="wait" msgid="7147118217226317732">"等待"</string>
+ <string name="webpage_unresponsive" msgid="3272758351138122503">"该网页已无响应。"\n\n"要将其关闭吗?"</string>
<string name="launch_warning_title" msgid="1547997780506713581">"应用程序已重定向"</string>
<string name="launch_warning_replace" msgid="6202498949970281412">"<xliff:g id="APP_NAME">%1$s</xliff:g>目前正在运行。"</string>
<string name="launch_warning_original" msgid="188102023021668683">"<xliff:g id="APP_NAME">%1$s</xliff:g>已启动。"</string>
diff --git a/core/res/res/values-zh-rTW/strings.xml b/core/res/res/values-zh-rTW/strings.xml
index 0928de8..131c2f7 100644
--- a/core/res/res/values-zh-rTW/strings.xml
+++ b/core/res/res/values-zh-rTW/strings.xml
@@ -697,7 +697,7 @@
<string name="lockscreen_failed_attempts_now_wiping" product="default" msgid="3025504721764922246">"您嘗試解除這支手機的鎖定已失敗 <xliff:g id="NUMBER">%d</xliff:g> 次,手機現在將恢復原廠設定。"</string>
<string name="lockscreen_too_many_failed_attempts_countdown" msgid="6251480343394389665">"<xliff:g id="NUMBER">%d</xliff:g> 秒後再試一次。"</string>
<string name="lockscreen_forgot_pattern_button_text" msgid="2626999449610695930">"忘記解鎖圖形?"</string>
- <string name="lockscreen_glogin_forgot_pattern" msgid="2588521501166032747">"解除封鎖帳戶"</string>
+ <string name="lockscreen_glogin_forgot_pattern" msgid="2588521501166032747">"帳戶解鎖"</string>
<string name="lockscreen_glogin_too_many_attempts" msgid="2751368605287288808">"圖形嘗試次數過多"</string>
<string name="lockscreen_glogin_instructions" msgid="3931816256100707784">"如要解除鎖定,請使用 Google 帳戶登入。"</string>
<string name="lockscreen_glogin_username_hint" msgid="8846881424106484447">"使用者名稱 (電子郵件)"</string>
@@ -915,6 +915,7 @@
<string name="force_close" msgid="8346072094521265605">"確定"</string>
<string name="report" msgid="4060218260984795706">"回報"</string>
<string name="wait" msgid="7147118217226317732">"等待"</string>
+ <string name="webpage_unresponsive" msgid="3272758351138122503">"網頁沒有回應。"\n\n"您要結束嗎?"</string>
<string name="launch_warning_title" msgid="1547997780506713581">"應用程式已重新導向"</string>
<string name="launch_warning_replace" msgid="6202498949970281412">"「<xliff:g id="APP_NAME">%1$s</xliff:g>」現在正在執行。"</string>
<string name="launch_warning_original" msgid="188102023021668683">"「<xliff:g id="APP_NAME">%1$s</xliff:g>」原先已啟動。"</string>
diff --git a/core/res/res/values-zu/strings.xml b/core/res/res/values-zu/strings.xml
index fc01c1d..1068b66 100644
--- a/core/res/res/values-zu/strings.xml
+++ b/core/res/res/values-zu/strings.xml
@@ -915,6 +915,7 @@
<string name="force_close" msgid="8346072094521265605">"KULUNGILE"</string>
<string name="report" msgid="4060218260984795706">"Umbiko"</string>
<string name="wait" msgid="7147118217226317732">"Linda"</string>
+ <string name="webpage_unresponsive" msgid="3272758351138122503">"Leli khasi alisaphenduli."\n\n"Ingabe ufuna ukulivala na?"</string>
<string name="launch_warning_title" msgid="1547997780506713581">"Insiza idluliselwe phambili"</string>
<string name="launch_warning_replace" msgid="6202498949970281412">"<xliff:g id="APP_NAME">%1$s</xliff:g> iyasebenza."</string>
<string name="launch_warning_original" msgid="188102023021668683">"<xliff:g id="APP_NAME">%1$s</xliff:g> iqalisiwe."</string>
diff --git a/core/res/res/values/arrays.xml b/core/res/res/values/arrays.xml
index f9e1f5b..ce734fc 100644
--- a/core/res/res/values/arrays.xml
+++ b/core/res/res/values/arrays.xml
@@ -22,19 +22,9 @@
<!-- Do not translate. These are all of the drawable resources that should be preloaded by
the zygote process before it starts forking application processes. -->
<array name="preloaded_drawables">
- <item>@drawable/spinner_black_16</item>
- <item>@drawable/spinner_black_20</item>
- <item>@drawable/spinner_black_48</item>
- <item>@drawable/spinner_black_76</item>
- <item>@drawable/spinner_white_16</item>
- <item>@drawable/spinner_white_48</item>
- <item>@drawable/spinner_white_76</item>
- <item>@drawable/toast_frame</item>
<item>@drawable/toast_frame_holo</item>
- <item>@drawable/btn_check_on_selected</item>
<item>@drawable/btn_check_on_pressed_holo_light</item>
<item>@drawable/btn_check_on_pressed_holo_dark</item>
- <item>@drawable/btn_check_on_pressed</item>
<item>@drawable/btn_check_on_holo_light</item>
<item>@drawable/btn_check_on_holo_dark</item>
<item>@drawable/btn_check_on_focused_holo_light</item>
@@ -43,13 +33,8 @@
<item>@drawable/btn_check_on_disabled_holo_dark</item>
<item>@drawable/btn_check_on_disabled_focused_holo_light</item>
<item>@drawable/btn_check_on_disabled_focused_holo_dark</item>
- <item>@drawable/btn_check_on_disable_focused</item>
- <item>@drawable/btn_check_on_disable</item>
- <item>@drawable/btn_check_on</item>
- <item>@drawable/btn_check_off_selected</item>
<item>@drawable/btn_check_off_pressed_holo_light</item>
<item>@drawable/btn_check_off_pressed_holo_dark</item>
- <item>@drawable/btn_check_off_pressed</item>
<item>@drawable/btn_check_off_holo_light</item>
<item>@drawable/btn_check_off_holo_dark</item>
<item>@drawable/btn_check_off_focused_holo_light</item>
@@ -58,16 +43,10 @@
<item>@drawable/btn_check_off_disabled_holo_dark</item>
<item>@drawable/btn_check_off_disabled_focused_holo_light</item>
<item>@drawable/btn_check_off_disabled_focused_holo_dark</item>
- <item>@drawable/btn_check_off_disable_focused</item>
- <item>@drawable/btn_check_off_disable</item>
- <item>@drawable/btn_check_label_background</item>
<item>@drawable/btn_check_holo_light</item>
<item>@drawable/btn_check_holo_dark</item>
- <item>@drawable/btn_check</item>
- <item>@drawable/btn_radio_on_selected</item>
<item>@drawable/btn_radio_on_pressed_holo_light</item>
<item>@drawable/btn_radio_on_pressed_holo_dark</item>
- <item>@drawable/btn_radio_on_pressed</item>
<item>@drawable/btn_radio_on_holo_light</item>
<item>@drawable/btn_radio_on_holo_dark</item>
<item>@drawable/btn_radio_on_focused_holo_light</item>
@@ -76,11 +55,8 @@
<item>@drawable/btn_radio_on_disabled_holo_dark</item>
<item>@drawable/btn_radio_on_disabled_focused_holo_light</item>
<item>@drawable/btn_radio_on_disabled_focused_holo_dark</item>
- <item>@drawable/btn_radio_on</item>
- <item>@drawable/btn_radio_off_selected</item>
<item>@drawable/btn_radio_off_pressed_holo_light</item>
<item>@drawable/btn_radio_off_pressed_holo_dark</item>
- <item>@drawable/btn_radio_off_pressed</item>
<item>@drawable/btn_radio_off_holo_light</item>
<item>@drawable/btn_radio_off_holo_dark</item>
<item>@drawable/btn_radio_off_focused_holo_light</item>
@@ -89,23 +65,10 @@
<item>@drawable/btn_radio_off_disabled_holo_dark</item>
<item>@drawable/btn_radio_off_disabled_focused_holo_light</item>
<item>@drawable/btn_radio_off_disabled_focused_holo_dark</item>
- <item>@drawable/btn_radio_label_background</item>
- <item>@drawable/btn_radio</item>
- <item>@drawable/btn_default_transparent_normal</item>
- <item>@drawable/btn_default_small_selected</item>
- <item>@drawable/btn_default_small_pressed</item>
- <item>@drawable/btn_default_small_normal_disable_focused</item>
- <item>@drawable/btn_default_small_normal_disable</item>
- <item>@drawable/btn_default_small_normal</item>
- <item>@drawable/btn_default_selected</item>
<item>@drawable/btn_default_pressed_holo_light</item>
<item>@drawable/btn_default_pressed_holo_dark</item>
- <item>@drawable/btn_default_pressed</item>
<item>@drawable/btn_default_normal_holo_light</item>
<item>@drawable/btn_default_normal_holo_dark</item>
- <item>@drawable/btn_default_normal_disable_focused</item>
- <item>@drawable/btn_default_normal_disable</item>
- <item>@drawable/btn_default_normal</item>
<item>@drawable/btn_default_focused_holo_light</item>
<item>@drawable/btn_default_focused_holo_dark</item>
<item>@drawable/btn_default_disabled_holo_light</item>
@@ -114,24 +77,6 @@
<item>@drawable/btn_default_disabled_focused_holo_dark</item>
<item>@drawable/btn_default_holo_dark</item>
<item>@drawable/btn_default_holo_light</item>
- <item>@drawable/btn_default</item>
- <item>@drawable/btn_default_small</item>
- <item>@drawable/btn_dropdown_disabled</item>
- <item>@drawable/btn_dropdown_disabled_focused</item>
- <item>@drawable/btn_dropdown_normal</item>
- <item>@drawable/btn_dropdown_pressed</item>
- <item>@drawable/btn_dropdown_selected</item>
- <item>@drawable/btn_star_label_background</item>
- <item>@drawable/btn_star_big_off</item>
- <item>@drawable/btn_star_big_on</item>
- <item>@drawable/btn_star_big_on_disable</item>
- <item>@drawable/btn_star_big_off_disable</item>
- <item>@drawable/btn_star_big_on_pressed</item>
- <item>@drawable/btn_star_big_off_pressed</item>
- <item>@drawable/btn_star_big_on_selected</item>
- <item>@drawable/btn_star_big_off_selected</item>
- <item>@drawable/btn_star_big_on_disable_focused</item>
- <item>@drawable/btn_star_big_off_disable_focused</item>
<item>@drawable/btn_star_off_normal_holo_light</item>
<item>@drawable/btn_star_on_normal_holo_light</item>
<item>@drawable/btn_star_on_disabled_holo_light</item>
@@ -154,7 +99,6 @@
<item>@drawable/btn_star_on_disabled_focused_holo_dark</item>
<item>@drawable/btn_star_off_disabled_focused_holo_dark</item>
<item>@drawable/btn_star_holo_dark</item>
- <item>@drawable/btn_star</item>
<item>@drawable/btn_toggle_on_pressed_holo_light</item>
<item>@drawable/btn_toggle_on_pressed_holo_dark</item>
<item>@drawable/btn_toggle_on_normal_holo_light</item>
@@ -165,7 +109,6 @@
<item>@drawable/btn_toggle_on_disabled_holo_dark</item>
<item>@drawable/btn_toggle_on_disabled_focused_holo_light</item>
<item>@drawable/btn_toggle_on_disabled_focused_holo_dark</item>
- <item>@drawable/btn_toggle_on</item>
<item>@drawable/btn_toggle_off_pressed_holo_light</item>
<item>@drawable/btn_toggle_off_pressed_holo_dark</item>
<item>@drawable/btn_toggle_off_normal_holo_light</item>
@@ -176,23 +119,10 @@
<item>@drawable/btn_toggle_off_disabled_holo_dark</item>
<item>@drawable/btn_toggle_off_disabled_focused_holo_light</item>
<item>@drawable/btn_toggle_off_disabled_focused_holo_dark</item>
- <item>@drawable/btn_toggle_off</item>
<item>@drawable/btn_toggle_holo_light</item>
<item>@drawable/btn_toggle_holo_dark</item>
- <item>@drawable/btn_toggle</item>
- <item>@drawable/btn_toggle_bg</item>
- <item>@drawable/btn_dropdown</item>
- <item>@drawable/btn_dropdown</item>
- <item>@drawable/light_header_dither</item>
- <item>@drawable/divider_horizontal_textfield</item>
- <item>@drawable/divider_horizontal_dark_opaque</item>
- <item>@drawable/divider_horizontal_dark</item>
- <item>@drawable/divider_horizontal_bright_opaque</item>
- <item>@drawable/divider_horizontal_bright</item>
- <item>@drawable/divider_vertical_dark</item>
<item>@drawable/edit_text_holo_light</item>
<item>@drawable/edit_text_holo_dark</item>
- <item>@drawable/edit_text</item>
<item>@drawable/text_cursor_holo_light</item>
<item>@drawable/text_cursor_holo_dark</item>
<item>@drawable/text_select_handle_left</item>
@@ -200,70 +130,45 @@
<item>@drawable/text_edit_paste_window</item>
<item>@drawable/expander_close_holo_dark</item>
<item>@drawable/expander_close_holo_light</item>
- <item>@drawable/expander_ic_maximized</item>
- <item>@drawable/expander_ic_minimized</item>
- <item>@drawable/expander_group</item>
<item>@drawable/expander_group_holo_dark</item>
<item>@drawable/expander_group_holo_light</item>
- <item>@drawable/list_selector_background</item>
- <item>@drawable/list_selector_background_light</item>
- <item>@drawable/list_selector_background_longpress</item>
- <item>@drawable/list_selector_background_longpress_light</item>
- <item>@drawable/list_selector_background_pressed</item>
- <item>@drawable/list_selector_background_pressed_light</item>
- <item>@drawable/list_selector_background_selected</item>
<item>@drawable/list_selector_holo_dark</item>
<item>@drawable/list_selector_holo_light</item>
<item>@drawable/list_section_divider_holo_light</item>
<item>@drawable/list_section_divider_holo_dark</item>
- <item>@drawable/menu_background</item>
- <item>@drawable/menu_background_fill_parent_width</item>
<item>@drawable/menu_hardkey_panel_holo_dark</item>
<item>@drawable/menu_hardkey_panel_holo_light</item>
<item>@drawable/menu_submenu_background</item>
- <item>@drawable/menu_selector</item>
<item>@drawable/menu_dropdown_panel_holo_light</item>
<item>@drawable/menu_dropdown_panel_holo_dark</item>
<item>@drawable/overscroll_edge</item>
<item>@drawable/overscroll_glow</item>
- <item>@drawable/panel_background</item>
- <item>@drawable/popup_bottom_bright</item>
- <item>@drawable/popup_bottom_dark</item>
- <item>@drawable/popup_bottom_medium</item>
- <item>@drawable/popup_center_bright</item>
- <item>@drawable/popup_center_dark</item>
- <item>@drawable/popup_center_medium</item>
- <item>@drawable/popup_full_bright</item>
- <item>@drawable/popup_full_dark</item>
- <item>@drawable/popup_top_bright</item>
- <item>@drawable/popup_top_dark</item>
<item>@drawable/popup_inline_error_above_holo_dark</item>
<item>@drawable/popup_inline_error_above_holo_light</item>
<item>@drawable/popup_inline_error_holo_dark</item>
<item>@drawable/popup_inline_error_holo_light</item>
+ <item>@drawable/spinner_16_outer_holo</item>
+ <item>@drawable/spinner_16_inner_holo</item>
+ <item>@drawable/spinner_48_outer_holo</item>
+ <item>@drawable/spinner_48_inner_holo</item>
+ <item>@drawable/spinner_76_outer_holo</item>
+ <item>@drawable/spinner_76_inner_holo</item>
<item>@drawable/progress_bg_holo_dark</item>
<item>@drawable/progress_bg_holo_light</item>
- <item>@drawable/progress_horizontal</item>
<item>@drawable/progress_horizontal_holo_dark</item>
<item>@drawable/progress_horizontal_holo_light</item>
- <item>@drawable/progress_indeterminate_horizontal</item>
<item>@drawable/progress_indeterminate_horizontal_holo</item>
- <item>@drawable/progress_large</item>
<item>@drawable/progress_large_holo</item>
- <item>@drawable/progress_large_white</item>
- <item>@drawable/progress_medium</item>
<item>@drawable/progress_medium_holo</item>
- <item>@drawable/progress_medium_white</item>
<item>@drawable/progress_primary_holo_dark</item>
<item>@drawable/progress_primary_holo_light</item>
<item>@drawable/progress_secondary_holo_dark</item>
<item>@drawable/progress_secondary_holo_light</item>
- <item>@drawable/progress_small</item>
<item>@drawable/progress_small_holo</item>
- <item>@drawable/progress_small_titlebar</item>
- <item>@drawable/progress_small_white</item>
<item>@drawable/scrubber_progress_horizontal_holo_dark</item>
<item>@drawable/scrubber_progress_horizontal_holo_light</item>
+ <item>@drawable/background_holo_light</item>
+ <item>@drawable/background_holo_dark</item>
<item>@drawable/screen_background_dark</item>
<item>@drawable/screen_background_dark_transparent</item>
<item>@drawable/screen_background_light</item>
@@ -272,8 +177,6 @@
<item>@drawable/screen_background_selector_light</item>
<item>@drawable/scrollbar_handle_holo_dark</item>
<item>@drawable/scrollbar_handle_holo_light</item>
- <item>@drawable/scrollbar_handle_horizontal</item>
- <item>@drawable/scrollbar_handle_vertical</item>
<item>@drawable/spinner_background_holo_dark</item>
<item>@drawable/spinner_background_holo_light</item>
<item>@drawable/spinner_ab_default_holo_dark</item>
@@ -290,9 +193,6 @@
<item>@drawable/spinner_default_holo_light</item>
<item>@drawable/spinner_disabled_holo_dark</item>
<item>@drawable/spinner_disabled_holo_light</item>
- <item>@drawable/spinner_dropdown_background</item>
- <item>@drawable/spinner_dropdown_background_down</item>
- <item>@drawable/spinner_dropdown_background_up</item>
<item>@drawable/spinner_focused_holo_dark</item>
<item>@drawable/spinner_focused_holo_light</item>
<item>@drawable/spinner_pressed_holo_dark</item>
@@ -337,7 +237,6 @@
<item>@drawable/dialog_middle_holo_light</item>
<item>@drawable/dialog_top_holo_dark</item>
<item>@drawable/dialog_top_holo_light</item>
- <item>@drawable/ic_dialog_alert</item>
<item>@drawable/ic_dialog_alert_holo_dark</item>
<item>@drawable/ic_dialog_alert_holo_light</item>
<item>@drawable/list_divider_holo_dark</item>
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index 545a555..16b7ff3 100755
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -1830,12 +1830,12 @@
<!-- Defines whether the vertical scrollbar track should always be drawn. -->
<attr name="scrollbarAlwaysDrawVerticalTrack" format="boolean" />
- <!-- {@deprecated This attribute is deprecated and will be ignored as of
- API level 14 (<code>android.os.Build.VERSION_CODES#ICE_CREAM_SANDWICH</code>).
+ <!-- This attribute is deprecated and will be ignored as of
+ API level 14 ({@link android.os.Build.VERSION_CODES#ICE_CREAM_SANDWICH}).
Using fading edges may introduce noticeable performance
degradations and should be used only when required by the application's
visual design. To request fading edges with API level 14 and above,
- use the <code>requiresFadingEdge</code> attribute instead.} -->
+ use the <code>android:requiresFadingEdge</code> attribute instead. -->
<attr name="fadingEdge">
<!-- No edge is faded. -->
<flag name="none" value="0x00000000" />
@@ -2061,7 +2061,7 @@
</attr>
<!-- Direction of the text. A heuristic is used to determine the resolved text direction
of paragraphs. -->
- <attr name="textDirection" format="integer">
+ <attr name="textDirection" format="integer">
<!-- Default -->
<enum name="inherit" value="0" />
<!-- Default for the root view. The first strong directional character determines the
@@ -2072,16 +2072,12 @@
it is LTR if it contains any strong LTR characters. If there are neither, the
paragraph direction is the view’s resolved layout direction. -->
<enum name="anyRtl" value="2" />
- <!-- The paragraph direction is the same as the one held by a 60% majority of the
- characters. If there is no majority then the paragraph direction is the resolved
- layout direction of the View. -->
- <enum name="charCount" value="3" />
<!-- The paragraph direction is left to right. -->
- <enum name="ltr" value="4" />
+ <enum name="ltr" value="3" />
<!-- The paragraph direction is right to left. -->
- <enum name="rtl" value="5" />
+ <enum name="rtl" value="4" />
<!-- The paragraph direction is coming from the system Locale. -->
- <enum name="locale" value="6" />
+ <enum name="locale" value="5" />
</attr>
</declare-styleable>
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index bc132eb..0511b75 100755
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -361,7 +361,7 @@
with the modem or some other restricted hardware, add "/dev/bus/usb/001/"
to this list. If this is empty, no parts of the host USB bus will be excluded.
-->
- <string-array name="config_usbHostBlacklist">
+ <string-array name="config_usbHostBlacklist" translatable="false">
</string-array>
<!-- Vibrator pattern for feedback about a long screen/key press -->
@@ -533,13 +533,13 @@
<!-- Component name of the default wallpaper. This will be ImageWallpaper if not
specified -->
- <string name="default_wallpaper_component">@null</string>
+ <string name="default_wallpaper_component" translatable="false">@null</string>
<!-- Component name of the service providing network location support. -->
- <string name="config_networkLocationProvider">@null</string>
+ <string name="config_networkLocationProvider" translatable="false">@null</string>
<!-- Component name of the service providing geocoder API support. -->
- <string name="config_geocodeProvider">@null</string>
+ <string name="config_geocodeProvider" translatable="false">@null</string>
<!-- Boolean indicating if current platform supports bluetooth SCO for off call
use cases -->
@@ -563,7 +563,7 @@
<integer name="config_datause_throttle_kbitsps">300</integer>
<!-- The default iface on which to monitor data use -->
- <string name="config_datause_iface">rmnet0</string>
+ <string name="config_datause_iface" translatable="false">rmnet0</string>
<!-- The default reduced-datarate notification mask -->
<!-- 2 means give warning -->
@@ -593,11 +593,11 @@
<bool name="config_sms_capable">true</bool>
<!-- IP address of the dns server to use if nobody else suggests one -->
- <string name="config_default_dns_server">8.8.8.8</string>
+ <string name="config_default_dns_server" translatable="false">8.8.8.8</string>
<!-- The default character set for GsmAlphabet -->
<!-- Empty string means MBCS is not considered -->
- <string name="gsm_alphabet_default_charset"></string>
+ <string name="gsm_alphabet_default_charset" translatable="false"></string>
<!-- Enables SIP on WIFI only -->
<bool name="config_sip_wifi_only">false</bool>
@@ -632,7 +632,7 @@
OMA-TS-UAProf-V2_0-20060206-A Section 8.1.1.1. If the URL contains a '%s'
format string then that substring will be replaced with the value of
Build.MODEL. The format string shall not be escaped. -->
- <string name="config_useragentprofile_url"></string>
+ <string name="config_useragentprofile_url" translatable="false"></string>
<!-- When a database query is executed, the results retuned are paginated
in pages of size (in KB) indicated by this value -->
@@ -643,7 +643,7 @@
<bool name="config_showMenuShortcutsWhenKeyboardPresent">false</bool>
<!-- Do not translate. Defines the slots is Two Digit Number for dialing normally not USSD -->
- <string-array name="config_twoDigitNumberPattern">
+ <string-array name="config_twoDigitNumberPattern" translatable="false">
</string-array>
<!-- The VoiceMail default value is displayed to my own number if it is true -->
@@ -743,18 +743,18 @@
<!-- Set and Unsets WiMAX -->
<bool name="config_wimaxEnabled">false</bool>
<!-- Location of the wimax framwork jar location -->
- <string name="config_wimaxServiceJarLocation"></string>
+ <string name="config_wimaxServiceJarLocation" translatable="false"></string>
<!-- Location of the wimax native library locaiton -->
- <string name="config_wimaxNativeLibLocation"></string>
+ <string name="config_wimaxNativeLibLocation" translatable="false"></string>
<!-- Name of the wimax manager class -->
- <string name="config_wimaxManagerClassname"></string>
+ <string name="config_wimaxManagerClassname" translatable="false"></string>
<!-- Name of the wimax service class -->
- <string name="config_wimaxServiceClassname"></string>
+ <string name="config_wimaxServiceClassname" translatable="false"></string>
<!-- Name of the wimax state tracker clas -->
- <string name="config_wimaxStateTrackerClassname"></string>
+ <string name="config_wimaxStateTrackerClassname" translatable="false"></string>
<!-- Name of screensaver components to look for if none has been chosen by the user -->
- <string name="config_defaultDreamComponent">com.google.android.deskclock/com.android.deskclock.Screensaver</string>
+ <string name="config_defaultDreamComponent" translatable="false">com.google.android.deskclock/com.android.deskclock.Screensaver</string>
<!-- Base "touch slop" value used by ViewConfiguration as a
movement threshold where scrolling should begin. -->
diff --git a/core/res/res/values/styles.xml b/core/res/res/values/styles.xml
index 3b6d6f1..571c4ad 100644
--- a/core/res/res/values/styles.xml
+++ b/core/res/res/values/styles.xml
@@ -112,7 +112,7 @@
</style>
<!-- Standard animations for a translucent window or activity. This
- style is <em>not<em> used by default for the translucent theme
+ style is <em>not</em> used by default for the translucent theme
(since translucent activities are a special case that have no
clear UI paradigm), but you can make your own specialized theme
with this animation style if you would like to have the standard
diff --git a/core/res/res/values/themes.xml b/core/res/res/values/themes.xml
index fe5388b..7046fc5 100644
--- a/core/res/res/values/themes.xml
+++ b/core/res/res/values/themes.xml
@@ -29,15 +29,16 @@
===============================================================
-->
<resources>
- <!-- The default system theme. This is the theme used for activities
- that have not explicitly set their own theme.
-
+ <!-- The default theme for apps on API level 10 and lower. This is the theme used for
+ activities that have not explicitly set their own theme.
<p>You can count on this being a dark
background with light text on top, but should try to make no
other assumptions about its appearance. In particular, the text
inside of widgets using this theme may be completely different,
with the widget container being a light color and the text on top
of it a dark color.
+ <p>If you're developing for API level 11 and higher, you should instead use {@link
+ #Theme_Holo} or {@link #Theme_DeviceDefault}.</p>
-->
<style name="Theme">
@@ -370,13 +371,12 @@
<item name="pointerStyle">@android:style/Pointer</item>
</style>
- <!-- Variant of the default (dark) theme with no title bar -->
+ <!-- Variant of {@link #Theme} with no title bar -->
<style name="Theme.NoTitleBar">
<item name="android:windowNoTitle">true</item>
</style>
- <!-- Variant of the default (dark) theme that has no title bar and
- fills the entire screen -->
+ <!-- Variant of {@link #Theme} that has no title bar and no status bar -->
<style name="Theme.NoTitleBar.Fullscreen">
<item name="android:windowFullscreen">true</item>
<item name="android:windowContentOverlay">@null</item>
@@ -385,7 +385,8 @@
<!-- Theme for a light background with dark text on top. Set your activity
to this theme if you would like such an appearance. As with the
default theme, you should try to assume little more than that the
- background will be a light color. -->
+ background will be a light color.
+ <p>This is designed for API level 10 and lower.</p>-->
<style name="Theme.Light">
<item name="windowBackground">@android:drawable/screen_background_selector_light</item>
<item name="colorBackground">@android:color/background_light</item>
@@ -457,19 +458,19 @@
<item name="detailsElementBackground">@android:drawable/panel_bg_holo_light</item>
</style>
- <!-- Variant of the light theme with no title bar -->
+ <!-- Variant of {@link #Theme_Light} with no title bar -->
<style name="Theme.Light.NoTitleBar">
<item name="android:windowNoTitle">true</item>
</style>
- <!-- Variant of the light theme that has no title bar and
- fills the entire screen -->
+ <!-- Variant of {@link #Theme_Light} that has no title bar and
+ no status bar -->
<style name="Theme.Light.NoTitleBar.Fullscreen">
<item name="android:windowFullscreen">true</item>
<item name="android:windowContentOverlay">@null</item>
</style>
- <!-- Special variation on the default theme that ensures the background is
+ <!-- Variant on {@link #Theme} that ensures the background is
completely black. This is useful for things like image viewers and
media players. If you want the normal (dark background) theme
do <em>not</em> use this, use {@link #Theme}. -->
@@ -478,40 +479,40 @@
<item name="android:colorBackground">@android:color/black</item>
</style>
- <!-- Variant of the black theme with no title bar -->
+ <!-- Variant of {@link #Theme_Black} with no title bar -->
<style name="Theme.Black.NoTitleBar">
<item name="android:windowNoTitle">true</item>
</style>
- <!-- Variant of the black theme that has no title bar and
- fills the entire screen -->
+ <!-- Variant of {@link #Theme_Black} that has no title bar and
+ no status bar -->
<style name="Theme.Black.NoTitleBar.Fullscreen">
<item name="android:windowFullscreen">true</item>
<item name="android:windowContentOverlay">@null</item>
</style>
- <!-- Default theme for windows that want to have the user's selected
- wallpaper appear behind them. -->
+ <!-- Theme for windows that want to have the user's selected
+ wallpaper appear behind them (for API level 10 and lower). -->
<style name="Theme.Wallpaper">
<item name="android:windowBackground">@android:color/transparent</item>
<item name="android:colorBackgroundCacheHint">@null</item>
<item name="android:windowShowWallpaper">true</item>
</style>
- <!-- Variant of the translucent theme with no title bar -->
+ <!-- Variant of {@link #Theme_Wallpaper} that has no title bar -->
<style name="Theme.Wallpaper.NoTitleBar">
<item name="android:windowNoTitle">true</item>
</style>
- <!-- Variant of the translucent theme that has no title bar and
- fills the entire screen -->
+ <!-- Variant of {@link #Theme_Wallpaper} that
+ has no title bar or status bar. -->
<style name="Theme.Wallpaper.NoTitleBar.Fullscreen">
<item name="android:windowFullscreen">true</item>
<item name="android:windowContentOverlay">@null</item>
</style>
- <!-- Theme for a wallpaper's setting activity that is designed to be on
- top of a dark background. -->
+ <!-- Theme for a wallpaper's setting activity, which is designed to be a transparent
+ background with a dark shade, so the previous Activity is visible in the background. -->
<style name="Theme.WallpaperSettings">
<item name="android:windowBackground">@android:drawable/screen_background_dark_transparent</item>
<item name="android:colorBackgroundCacheHint">@null</item>
@@ -519,8 +520,8 @@
<item name="android:windowAnimationStyle">@android:style/Animation.Translucent</item>
</style>
- <!-- Theme for a wallpaper's setting activity that is designed to be on
- top of a light background. -->
+ <!-- Theme for a wallpaper's setting activity, which is designed to be a transparent
+ background with a light shade, so the previous Activity is visible in the background. -->
<style name="Theme.Light.WallpaperSettings">
<item name="android:windowBackground">@android:drawable/screen_background_light_transparent</item>
<item name="android:colorBackgroundCacheHint">@null</item>
@@ -538,8 +539,8 @@
<style name="PreviewWallpaperSettings">
</style>
- <!-- Default theme for translucent activities, that is windows that allow you
- to see through them to the windows behind. This sets up the translucent
+ <!-- Theme for translucent activities (on API level 10 and lower). That is, windows
+ that allow you to see through them to the windows behind. This sets up the translucent
flag and appropriate animations for your windows. -->
<style name="Theme.Translucent">
<item name="android:windowBackground">@android:color/transparent</item>
@@ -551,14 +552,14 @@
<item name="android:windowAnimationStyle">@android:style/Animation</item>
</style>
- <!-- Variant of the translucent theme with no title bar -->
+ <!-- Variant of {@link #Theme_Translucent} with no title bar -->
<style name="Theme.Translucent.NoTitleBar">
<item name="android:windowNoTitle">true</item>
<item name="android:windowContentOverlay">@null</item>
</style>
- <!-- Variant of the translucent theme that has no title bar and
- fills the entire screen -->
+ <!-- Variant of {@link #Theme_Translucent} that has no title bar and
+ no status bar -->
<style name="Theme.Translucent.NoTitleBar.Fullscreen">
<item name="android:windowFullscreen">true</item>
</style>
@@ -574,7 +575,8 @@
<item name="android:windowNoDisplay">true</item>
</style>
- <!-- Default theme for dialog windows and activities, which is used by the
+ <!-- Default theme for dialog windows and activities (on API level 10 and lower),
+ which is used by the
{@link android.app.Dialog} class. This changes the window to be
floating (not fill the entire screen), and puts a frame around its
contents. You can set this theme on an activity if you would like to
@@ -622,7 +624,7 @@
<item name="listPreferredItemPaddingRight">10dip</item>
</style>
- <!-- Variation of Theme.Dialog that does not include a frame (or background).
+ <!-- Variant of {@link Theme_Dialog} that does not include a frame (or background).
The view hierarchy of the dialog is responsible for drawing all of
its pixels. -->
<style name="Theme.Dialog.NoFrame">
@@ -636,7 +638,7 @@
<item name="android:windowCloseOnTouchOutside">false</item>
</style>
- <!-- Default theme for alert dialog windows, which is used by the
+ <!-- Default theme for alert dialog windows (on API level 10 and lower), which is used by the
{@link android.app.AlertDialog} class. This is basically a dialog
but sets the background to empty so it can do two-tone backgrounds. -->
<style name="Theme.Dialog.Alert">
@@ -648,8 +650,8 @@
<item name="textAppearanceListItemSmall">@android:style/TextAppearance.Large.Inverse</item>
</style>
- <!-- Default dark theme for panel windows. This removes all extraneous
- window decorations, so you basically have an empty rectangle in which
+ <!-- Default dark theme for panel windows (on API level 10 and lower). This removes all
+ extraneous window decorations, so you basically have an empty rectangle in which
to place your content. It makes the window floating, with a transparent
background, and turns off dimming behind the window. -->
<style name="Theme.Panel">
@@ -664,8 +666,8 @@
<item name="android:windowNoTitle">true</item>
</style>
- <!-- Default light theme for panel windows. This removes all extraneous
- window decorations, so you basically have an empty rectangle in which
+ <!-- Default light theme for panel windows (on API level 10 and lower). This removes all
+ extraneous window decorations, so you basically have an empty rectangle in which
to place your content. It makes the window floating, with a transparent
background, and turns off dimming behind the window. -->
<style name="Theme.Light.Panel">
@@ -712,7 +714,7 @@
<item name="android:windowNoTitle">true</item>
</style>
- <!-- Default theme for input methods, which is used by the
+ <!-- Default theme for input methods (on API level 10 and lower), which is used by the
{@link android.inputmethodservice.InputMethodService} class.
this inherits from Theme.Panel, but sets up IME appropriate animations
and a few custom attributes. -->
@@ -723,7 +725,7 @@
<item name="android:imeExtractExitAnimation">@android:anim/input_method_extract_exit</item>
</style>
- <!-- Default theme for modern holo style input methods, which is used by the
+ <!-- Default theme for holo style input methods, which is used by the
{@link android.inputmethodservice.InputMethodService} class.
this inherits from Theme.Panel, but sets up IME appropriate animations
and a few custom attributes. -->
@@ -842,14 +844,23 @@
<item name="android:windowActionModeOverlay">true</item>
</style>
- <!-- New Honeycomb holographic theme. Dark version. The widgets in the
- holographic theme are translucent on their brackground, so applications
- must ensure that any background they use with this theme is itself
- dark; otherwise, it will be difficult to see the widgets. The new
- UI style also includes a full action bar by default.
+ <!-- Honeycomb holographic theme (dark version).
+ <p>This is the default system theme for apps that target API level 11 - 13. Starting
+ with API level 14, the default system theme is supplied by {@link #Theme_DeviceDefault},
+ which might apply a different style on different devices. If you want to ensure that your
+ app consistenly uses the Holo theme at all times, you must explicitly declare it in your
+ manifest. For example, {@code <application android:theme="@android:style/Theme.Holo">}.
+ For more information, read <a
+ href="http://android-developers.blogspot.com/2012/01/holo-everywhere.html">Holo
+ Everywhere</a>.</p>
+ <p>The widgets in the holographic theme are translucent on their brackground, so
+ applications must ensure that any background they use with this theme is itself
+ dark; otherwise, it will be difficult to see the widgets. This UI style also includes a
+ full action bar by default.</p>
- Styles used by the Holo theme are named using the convention Type.Holo.Etc.
- (For example, Widget.Holo.Button, TextAppearance.Holo.Widget.PopupMenu.Large.)
+ <p>Styles used by the Holo theme are named using the convention Type.Holo.Etc
+ (for example, {@code Widget.Holo.Button} and {@code
+ TextAppearance.Holo.Widget.PopupMenu.Large}).
Specific resources used by Holo are named using the convention @type/foo_bar_baz_holo
with trailing _dark or _light specifiers if they are not shared between both light and
dark versions of the theme. -->
@@ -951,15 +962,12 @@
<item name="listDividerAlertDialog">@android:drawable/list_divider_holo_dark</item>
<item name="expandableListPreferredItemPaddingLeft">40dip</item>
- <item name="expandableListPreferredChildPaddingLeft">
- ?android:attr/expandableListPreferredItemPaddingLeft</item>
+ <item name="expandableListPreferredChildPaddingLeft">?android:attr/expandableListPreferredItemPaddingLeft</item>
<item name="expandableListPreferredItemIndicatorLeft">3dip</item>
<item name="expandableListPreferredItemIndicatorRight">0dip</item>
- <item name="expandableListPreferredChildIndicatorLeft">
- ?android:attr/expandableListPreferredItemIndicatorLeft</item>
- <item name="expandableListPreferredChildIndicatorRight">
- ?android:attr/expandableListPreferredItemIndicatorRight</item>
+ <item name="expandableListPreferredChildIndicatorLeft">?android:attr/expandableListPreferredItemIndicatorLeft</item>
+ <item name="expandableListPreferredChildIndicatorRight">?android:attr/expandableListPreferredItemIndicatorRight</item>
<!-- Gallery attributes -->
<item name="galleryItemBackground">@android:drawable/gallery_item_background</item>
@@ -1156,10 +1164,10 @@
</style>
- <!-- New Honeycomb holographic theme. Light version. The widgets in the
+ <!-- Honeycomb holographic theme (light version). The widgets in the
holographic theme are translucent on their brackground, so applications
must ensure that any background they use with this theme is itself
- light; otherwise, it will be difficult to see the widgets. The new
+ light; otherwise, it will be difficult to see the widgets. This
UI style also includes a full action bar by default. -->
<style name="Theme.Holo.Light" parent="Theme.Light">
<item name="colorForeground">@android:color/bright_foreground_holo_light</item>
@@ -1257,15 +1265,12 @@
<item name="activatedBackgroundIndicator">@android:drawable/activated_background_holo_light</item>
<item name="expandableListPreferredItemPaddingLeft">40dip</item>
- <item name="expandableListPreferredChildPaddingLeft">
- ?android:attr/expandableListPreferredItemPaddingLeft</item>
+ <item name="expandableListPreferredChildPaddingLeft">?android:attr/expandableListPreferredItemPaddingLeft</item>
<item name="expandableListPreferredItemIndicatorLeft">3dip</item>
<item name="expandableListPreferredItemIndicatorRight">0dip</item>
- <item name="expandableListPreferredChildIndicatorLeft">
- ?android:attr/expandableListPreferredItemIndicatorLeft</item>
- <item name="expandableListPreferredChildIndicatorRight">
- ?android:attr/expandableListPreferredItemIndicatorRight</item>
+ <item name="expandableListPreferredChildIndicatorLeft">?android:attr/expandableListPreferredItemIndicatorLeft</item>
+ <item name="expandableListPreferredChildIndicatorRight">?android:attr/expandableListPreferredItemIndicatorRight</item>
<item name="listDividerAlertDialog">@android:drawable/list_divider_holo_light</item>
@@ -1522,6 +1527,7 @@
</style>
<!-- Dialog themes for Holo -->
+ <eat-comment />
<!-- Holo theme for dialog windows and activities, which is used by the
{@link android.app.Dialog} class. This changes the window to be
@@ -1554,27 +1560,27 @@
<item name="listPreferredItemPaddingRight">16dip</item>
</style>
- <!-- Variation of Theme.Holo.Dialog that has a nice minumum width for
+ <!-- Variant of Theme.Holo.Dialog that has a nice minimum width for
a regular dialog. -->
<style name="Theme.Holo.Dialog.MinWidth">
<item name="android:windowMinWidthMajor">@android:dimen/dialog_min_width_major</item>
<item name="android:windowMinWidthMinor">@android:dimen/dialog_min_width_minor</item>
</style>
- <!-- Variation of Theme.Holo.Dialog that does not include a title bar. -->
+ <!-- Variant of Theme.Holo.Dialog that does not include a title bar. -->
<style name="Theme.Holo.Dialog.NoActionBar">
<item name="android:windowActionBar">false</item>
<item name="android:windowNoTitle">true</item>
</style>
- <!-- Variation of Theme.Holo.Dialog.NoActionVar that has a nice minumum width for
+ <!-- Variant of Theme.Holo.Dialog.NoActionBar that has a nice minimum width for
a regular dialog. -->
<style name="Theme.Holo.Dialog.NoActionBar.MinWidth">
<item name="android:windowMinWidthMajor">@android:dimen/dialog_min_width_major</item>
<item name="android:windowMinWidthMinor">@android:dimen/dialog_min_width_minor</item>
</style>
- <!-- Variation of Theme.Holo.Dialog that does not include a frame (or background).
+ <!-- Variant of Theme.Holo.Dialog that does not include a frame (or background).
The view hierarchy of the dialog is responsible for drawing all of
its pixels. -->
<style name="Theme.Holo.Dialog.NoFrame">
@@ -1646,20 +1652,20 @@
<item name="listPreferredItemPaddingRight">16dip</item>
</style>
- <!-- Variation of Theme.Holo.Light.Dialog that has a nice minumum width for
+ <!-- Variant of Theme.Holo.Light.Dialog that has a nice minimum width for
a regular dialog. -->
<style name="Theme.Holo.Light.Dialog.MinWidth">
<item name="android:windowMinWidthMajor">@android:dimen/dialog_min_width_major</item>
<item name="android:windowMinWidthMinor">@android:dimen/dialog_min_width_minor</item>
</style>
- <!-- Variation of Theme.Holo.Light.Dialog that does not include a title bar. -->
+ <!-- Variant of Theme.Holo.Light.Dialog that does not include a title bar. -->
<style name="Theme.Holo.Light.Dialog.NoActionBar">
<item name="android:windowActionBar">false</item>
<item name="android:windowNoTitle">true</item>
</style>
- <!-- Variation of Theme.Holo.Light.Dialog.NoActionBar that has a nice minumum width for
+ <!-- Variant of Theme.Holo.Light.Dialog.NoActionBar that has a nice minimum width for
a regular dialog. -->
<style name="Theme.Holo.Light.Dialog.NoActionBar.MinWidth">
<item name="android:windowMinWidthMajor">@android:dimen/dialog_min_width_major</item>
@@ -1700,7 +1706,8 @@
<item name="android:windowShowWallpaper">true</item>
</style>
- <!-- Variant of the holographic (dark) theme with no title bar -->
+ <!--Default holographic (dark) for windows that want to have the user's selected
+ wallpaper appear behind them and without an action bar. -->
<style name="Theme.Holo.Wallpaper.NoTitleBar">
<item name="android:windowNoTitle">true</item>
</style>
diff --git a/core/res/res/values/themes_device_defaults.xml b/core/res/res/values/themes_device_defaults.xml
index 8135986..abe4aad 100644
--- a/core/res/res/values/themes_device_defaults.xml
+++ b/core/res/res/values/themes_device_defaults.xml
@@ -31,6 +31,24 @@
===============================================================
-->
<resources>
+
+ <!-- The default theme for apps that target API level 14 and higher.
+ <p>The DeviceDefault themes are aliases for a specific device’s native look and feel. The
+ DeviceDefault theme family and widget style family offer ways for you to target your app
+ to a device’s native theme with all device customizations intact.</p>
+ <p>For example, when you set your app's {@code targetSdkVersion} to 14 or higher, this
+ theme is applied to your application by default. As such, your app might appear with the
+ {@link #Theme_Holo Holo} styles on one device, but with a different set of styles on
+ another device. This is great if you want your app to fit with the device's native look and
+ feel. If, however, you prefer to keep your UI style the same across all devices, you should
+ apply a specific theme such as {@link #Theme_Holo Holo} or one of your own design. For more
+ information, read <a
+ href="http://android-developers.blogspot.com/2012/01/holo-everywhere.html">Holo
+ Everywhere</a>.</p>
+ <p>Styles used by the DeviceDefault theme are named using the convention
+ Type.DeviceDefault.Etc (for example, {@code Widget.DeviceDefault.Button} and
+ {@code TextAppearance.DeviceDefault.Widget.PopupMenu.Large}).</p>
+ -->
<style name="Theme.DeviceDefault" parent="Theme.Holo" >
<!-- Text styles -->
<item name="textAppearance">@android:style/TextAppearance.DeviceDefault</item>
@@ -176,12 +194,16 @@
<!-- DatePicker style -->
<item name="datePickerStyle">@style/Widget.DeviceDefault.DatePicker</item>
</style>
+
+ <!-- Variant of {@link #Theme_DeviceDefault} with no action bar -->
<style name="Theme.DeviceDefault.NoActionBar" parent="Theme.Holo.NoActionBar" >
</style>
+ <!-- Variant of {@link #Theme_DeviceDefault} with no action bar and no status bar -->
<style name="Theme.DeviceDefault.NoActionBar.Fullscreen" parent="Theme.Holo.NoActionBar.Fullscreen" >
</style>
+ <!-- Variant of {@link #Theme_DeviceDefault} with a light-colored style -->
<style name="Theme.DeviceDefault.Light" parent="Theme.Holo.Light" >
<!-- Text styles -->
<item name="textAppearance">@android:style/TextAppearance.DeviceDefault.Light</item>
@@ -322,12 +344,17 @@
<!-- DatePicker style -->
<item name="datePickerStyle">@style/Widget.DeviceDefault.Light.DatePicker</item>
</style>
+ <!-- Variant of {@link #Theme_DeviceDefault_Light} with no action bar -->
<style name="Theme.DeviceDefault.Light.NoActionBar" parent="Theme.Holo.Light.NoActionBar" >
</style>
+ <!-- Variant of {@link #Theme_DeviceDefault_Light} with no action bar and no status bar -->
<style name="Theme.DeviceDefault.Light.NoActionBar.Fullscreen" parent="Theme.Holo.Light.NoActionBar.Fullscreen" >
</style>
+ <!-- DeviceDefault theme for dialog windows and activities. This changes the window to be
+ floating (not fill the entire screen), and puts a frame around its contents. You can set this
+ theme on an activity if you would like to make an activity that looks like a Dialog. -->
<style name="Theme.DeviceDefault.Dialog" parent="Theme.Holo.Dialog" >
<item name="android:windowTitleStyle">@android:style/DialogWindowTitle.DeviceDefault</item>
<item name="android:windowAnimationStyle">@android:style/Animation.DeviceDefault.Dialog</item>
@@ -338,15 +365,23 @@
<item name="textAppearance">@android:style/TextAppearance.DeviceDefault</item>
<item name="textAppearanceInverse">@android:style/TextAppearance.DeviceDefault.Inverse</item>
</style>
+ <!-- Variant of {@link #Theme_DeviceDefault_Dialog} that has a nice minimum width for a
+ regular dialog. -->
<style name="Theme.DeviceDefault.Dialog.MinWidth" parent="Theme.Holo.Dialog.MinWidth" >
</style>
+ <!-- Variant of {@link #Theme_DeviceDefault_Dialog} without an action bar -->
<style name="Theme.DeviceDefault.Dialog.NoActionBar" parent="Theme.Holo.Dialog.NoActionBar" >
</style>
+ <!-- Variant of {@link #Theme_DeviceDefault_Dialog_NoActionBar} that has a nice minimum width
+ for a regular dialog. -->
<style name="Theme.DeviceDefault.Dialog.NoActionBar.MinWidth" parent="Theme.Holo.Dialog.NoActionBar.MinWidth" >
</style>
+ <!-- DeviceDefault light theme for dialog windows and activities. This changes the window to be
+ floating (not fill the entire screen), and puts a frame around its contents. You can set this
+ theme on an activity if you would like to make an activity that looks like a Dialog.-->
<style name="Theme.DeviceDefault.Light.Dialog" parent="Theme.Holo.Light.Dialog" >
<item name="android:windowTitleStyle">@android:style/DialogWindowTitle.DeviceDefault.Light</item>
<item name="android:windowAnimationStyle">@android:style/Animation.DeviceDefault.Dialog</item>
@@ -357,42 +392,71 @@
<item name="textAppearance">@android:style/TextAppearance.DeviceDefault.Light</item>
<item name="textAppearanceInverse">@android:style/TextAppearance.DeviceDefault.Light.Inverse</item>
</style>
+ <!-- Variant of {@link #Theme_DeviceDefault_Light_Dialog} that has a nice minimum width for a
+ regular dialog. -->
<style name="Theme.DeviceDefault.Light.Dialog.MinWidth" parent="Theme.Holo.Light.Dialog.MinWidth" >
</style>
+ <!-- Variant of {@link #Theme_DeviceDefault_Light_Dialog} without an action bar -->
<style name="Theme.DeviceDefault.Light.Dialog.NoActionBar" parent="Theme.Holo.Light.Dialog.NoActionBar" >
</style>
+ <!-- Variant of {@link #Theme_DeviceDefault_Light_Dialog_NoActionBar} that has a nice minimum
+ width for a regular dialog. -->
<style name="Theme.DeviceDefault.Light.Dialog.NoActionBar.MinWidth" parent="Theme.Holo.Light.Dialog.NoActionBar.MinWidth" >
</style>
+ <!-- DeviceDefault theme for a window that will be displayed either full-screen on smaller
+ screens (small, normal) or as a dialog on larger screens (large, xlarge). -->
<style name="Theme.DeviceDefault.DialogWhenLarge" parent="Theme.Holo.DialogWhenLarge" >
</style>
+ <!-- DeviceDefault theme for a window without an action bar that will be displayed either
+ full-screen on smaller screens (small, normal) or as a dialog on larger screens (large,
+ xlarge). -->
<style name="Theme.DeviceDefault.DialogWhenLarge.NoActionBar" parent="Theme.Holo.DialogWhenLarge.NoActionBar" >
</style>
+ <!-- DeviceDefault light theme for a window that will be displayed either full-screen on smaller
+ screens (small, normal) or as a dialog on larger screens (large, xlarge). -->
<style name="Theme.DeviceDefault.Light.DialogWhenLarge" parent="Theme.Holo.Light.DialogWhenLarge" >
</style>
+ <!-- DeviceDefault light theme for a window without an action bar that will be displayed either
+ full-screen on smaller screens (small, normal) or as a dialog on larger screens (large,
+ xlarge). -->
<style name="Theme.DeviceDefault.Light.DialogWhenLarge.NoActionBar" parent="Theme.Holo.Light.DialogWhenLarge.NoActionBar" >
</style>
+ <!-- DeviceDefault theme for panel windows. This removes all extraneous window
+ decorations, so you basically have an empty rectangle in which to place your content. It makes
+ the window floating, with a transparent background, and turns off dimming behind the window. -->
<style name="Theme.DeviceDefault.Panel" parent="Theme.Holo.Panel" >
</style>
+ <!-- DeviceDefault light theme for panel windows. This removes all extraneous window
+ decorations, so you basically have an empty rectangle in which to place your content. It makes
+ the window floating, with a transparent background, and turns off dimming behind the window. -->
<style name="Theme.DeviceDefault.Light.Panel" parent="Theme.Holo.Light.Panel" >
</style>
+ <!-- DeviceDefault theme for windows that want to have the user's selected wallpaper appear
+ behind them. -->
<style name="Theme.DeviceDefault.Wallpaper" parent="Theme.Holo.Wallpaper" >
</style>
+ <!-- DeviceDefault theme for windows that want to have the user's selected wallpaper appear
+ behind them and without an action bar. -->
<style name="Theme.DeviceDefault.Wallpaper.NoTitleBar" parent="Theme.Holo.Wallpaper.NoTitleBar" >
</style>
+ <!-- DeviceDefault style for input methods, which is used by the
+ {@link android.inputmethodservice.InputMethodService} class.-->
<style name="Theme.DeviceDefault.InputMethod" parent="Theme.Holo.InputMethod" >
</style>
+ <!-- Variant of the DeviceDefault (light) theme that has a solid (opaque) action bar with an
+ inverse color profile. -->
<style name="Theme.DeviceDefault.Light.DarkActionBar" parent="Theme.Holo.Light.DarkActionBar" >
<item name="android:actionBarStyle">@android:style/Widget.DeviceDefault.Light.ActionBar.Solid.Inverse</item>
diff --git a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/ConnectivityManagerStressTestRunner.java b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/ConnectivityManagerStressTestRunner.java
index 3ffa085..7233e7f 100644
--- a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/ConnectivityManagerStressTestRunner.java
+++ b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/ConnectivityManagerStressTestRunner.java
@@ -46,7 +46,7 @@
@Override
public TestSuite getAllTests() {
TestSuite suite = new InstrumentationTestSuite(this);
- if (!UtilHelper.isWifiOnly()) {
+ if (!UtilHelper.isWifiOnly(getContext())) {
suite.addTestSuite(WifiApStress.class);
suite.addTestSuite(WifiStressTest.class);
} else {
@@ -64,7 +64,7 @@
@Override
public void onCreate(Bundle icicle) {
super.onCreate(icicle);
- if (!UtilHelper.isWifiOnly()) {
+ if (!UtilHelper.isWifiOnly(getContext())) {
String valueStr = (String) icicle.get("softap_iterations");
if (valueStr != null) {
int iteration = Integer.parseInt(valueStr);
diff --git a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/ConnectivityManagerTestRunner.java b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/ConnectivityManagerTestRunner.java
index 20aae47..9819c54 100644
--- a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/ConnectivityManagerTestRunner.java
+++ b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/ConnectivityManagerTestRunner.java
@@ -40,7 +40,7 @@
@Override
public TestSuite getAllTests() {
TestSuite suite = new InstrumentationTestSuite(this);
- if (!UtilHelper.isWifiOnly()) {
+ if (!UtilHelper.isWifiOnly(getContext())) {
suite.addTestSuite(ConnectivityManagerMobileTest.class);
} else {
// create a new test suite
diff --git a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/UtilHelper.java b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/UtilHelper.java
index 1b966bf..b9fe6ed 100644
--- a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/UtilHelper.java
+++ b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/UtilHelper.java
@@ -16,12 +16,31 @@
package com.android.connectivitymanagertest;
-import android.os.SystemProperties;
+import android.content.Context;
+import android.content.pm.PackageManager;
+import android.util.Log;
public class UtilHelper {
- public static boolean isWifiOnly() {
- return "wifi-only".equals(SystemProperties.get("ro.carrier"));
+
+ private static Boolean mIsWifiOnly = null;
+ private static final Object sLock = new Object();
+
+ /**
+ * Return true if device is a wifi only device.
+ */
+ public static boolean isWifiOnly(Context context) {
+ synchronized (sLock) {
+ // cache the result from pkgMgr statically. It will never change, since its a
+ // device configuration setting
+ if (mIsWifiOnly == null) {
+ PackageManager pkgMgr = context.getPackageManager();
+ mIsWifiOnly = Boolean.valueOf(!pkgMgr
+ .hasSystemFeature(PackageManager.FEATURE_TELEPHONY)
+ && pkgMgr.hasSystemFeature(PackageManager.FEATURE_WIFI));
+ String deviceType = mIsWifiOnly ? "wifi-only" : "telephony";
+ Log.d("ConnectivityManagerTest", String.format("detected a %s device", deviceType));
+ }
+ }
+ return mIsWifiOnly;
}
-
-
}
diff --git a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/functional/ConnectivityManagerMobileTest.java b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/functional/ConnectivityManagerMobileTest.java
index b1f4bf1..52326d5 100644
--- a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/functional/ConnectivityManagerMobileTest.java
+++ b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/functional/ConnectivityManagerMobileTest.java
@@ -16,37 +16,31 @@
package com.android.connectivitymanagertest.functional;
-import com.android.connectivitymanagertest.ConnectivityManagerTestActivity;
-import com.android.connectivitymanagertest.UtilHelper;
-
-import android.content.Intent;
import android.content.Context;
-import android.os.PowerManager;
-import android.os.PowerManager.WakeLock;
-import android.app.Instrumentation;
-import android.os.Handler;
-import android.os.Message;
-import android.provider.Settings;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.net.NetworkInfo.State;
-import android.net.NetworkInfo.DetailedState;
import android.net.wifi.WifiManager;
-
-import android.test.suitebuilder.annotation.LargeTest;
+import android.os.PowerManager;
+import android.os.PowerManager.WakeLock;
+import android.provider.Settings;
import android.test.ActivityInstrumentationTestCase2;
-import com.android.connectivitymanagertest.ConnectivityManagerTestRunner;
-import com.android.connectivitymanagertest.NetworkState;
+import android.test.suitebuilder.annotation.LargeTest;
import android.util.Log;
-public class ConnectivityManagerMobileTest
- extends ActivityInstrumentationTestCase2<ConnectivityManagerTestActivity> {
+import com.android.connectivitymanagertest.ConnectivityManagerTestActivity;
+import com.android.connectivitymanagertest.ConnectivityManagerTestRunner;
+import com.android.connectivitymanagertest.NetworkState;
+import com.android.connectivitymanagertest.UtilHelper;
+
+public class ConnectivityManagerMobileTest extends
+ ActivityInstrumentationTestCase2<ConnectivityManagerTestActivity> {
private static final String LOG_TAG = "ConnectivityManagerMobileTest";
- private static final String PKG_NAME = "com.android.connectivitymanagertest";
private String TEST_ACCESS_POINT;
private ConnectivityManagerTestActivity cmActivity;
private WakeLock wl;
+ private boolean mIsWifiOnlyDevice;
public ConnectivityManagerMobileTest() {
super(ConnectivityManagerTestActivity.class);
@@ -69,7 +63,8 @@
log("airplane is not disabled, disable it.");
cmActivity.setAirplaneMode(getInstrumentation().getContext(), false);
}
- if (!UtilHelper.isWifiOnly()) {
+ mIsWifiOnlyDevice = UtilHelper.isWifiOnly(mRunner.getTargetContext());
+ if (!mIsWifiOnlyDevice) {
if (!cmActivity.waitForNetworkState(ConnectivityManager.TYPE_MOBILE, State.CONNECTED,
ConnectivityManagerTestActivity.LONG_TIMEOUT)) {
// Note: When the test fails in setUp(), tearDown is not called. In that case,
@@ -166,7 +161,7 @@
public void testConnectToWifi() {
assertNotNull("SSID is null", TEST_ACCESS_POINT);
NetworkInfo networkInfo;
- if (!UtilHelper.isWifiOnly()) {
+ if (!mIsWifiOnlyDevice) {
//Prepare for connectivity verification
networkInfo = cmActivity.mCM.getNetworkInfo(ConnectivityManager.TYPE_MOBILE);
cmActivity.setStateTransitionCriteria(ConnectivityManager.TYPE_MOBILE,
@@ -185,7 +180,7 @@
log("wifi state is enabled");
assertTrue(cmActivity.waitForNetworkState(ConnectivityManager.TYPE_WIFI, State.CONNECTED,
ConnectivityManagerTestActivity.LONG_TIMEOUT));
- if (!UtilHelper.isWifiOnly()) {
+ if (!mIsWifiOnlyDevice) {
assertTrue(cmActivity.waitForNetworkState(ConnectivityManager.TYPE_MOBILE,
State.DISCONNECTED, ConnectivityManagerTestActivity.LONG_TIMEOUT));
}
@@ -197,7 +192,7 @@
cmActivity.getTransitionFailureReason(ConnectivityManager.TYPE_WIFI));
assertTrue(false);
}
- if (!UtilHelper.isWifiOnly()) {
+ if (!mIsWifiOnlyDevice) {
if (!cmActivity.validateNetworkStates(ConnectivityManager.TYPE_MOBILE)) {
log("Mobile state transition validation failed.");
log("reason: " +
@@ -232,13 +227,13 @@
ConnectivityManagerTestActivity.LONG_TIMEOUT));
assertTrue(cmActivity.waitForNetworkState(ConnectivityManager.TYPE_WIFI,
State.DISCONNECTED, ConnectivityManagerTestActivity.LONG_TIMEOUT));
- if (!UtilHelper.isWifiOnly()) {
+ if (!mIsWifiOnlyDevice) {
assertTrue(cmActivity.waitForNetworkState(ConnectivityManager.TYPE_MOBILE,
State.CONNECTED, ConnectivityManagerTestActivity.LONG_TIMEOUT));
}
NetworkInfo networkInfo;
- if (!UtilHelper.isWifiOnly()) {
+ if (!mIsWifiOnlyDevice) {
//Prepare for connectivity state verification
networkInfo = cmActivity.mCM.getNetworkInfo(ConnectivityManager.TYPE_MOBILE);
cmActivity.setStateTransitionCriteria(ConnectivityManager.TYPE_MOBILE,
@@ -258,7 +253,7 @@
// Wait for Wifi to be connected and mobile to be disconnected
assertTrue(cmActivity.waitForNetworkState(ConnectivityManager.TYPE_WIFI, State.CONNECTED,
ConnectivityManagerTestActivity.LONG_TIMEOUT));
- if (!UtilHelper.isWifiOnly()) {
+ if (!mIsWifiOnlyDevice) {
assertTrue(cmActivity.waitForNetworkState(ConnectivityManager.TYPE_MOBILE,
State.DISCONNECTED, ConnectivityManagerTestActivity.LONG_TIMEOUT));
}
@@ -288,7 +283,7 @@
sleep(ConnectivityManagerTestActivity.SHORT_TIMEOUT);
NetworkInfo networkInfo;
- if (!UtilHelper.isWifiOnly()) {
+ if (!mIsWifiOnlyDevice) {
networkInfo = cmActivity.mCM.getNetworkInfo(ConnectivityManager.TYPE_MOBILE);
cmActivity.setStateTransitionCriteria(ConnectivityManager.TYPE_MOBILE,
networkInfo.getState(),
@@ -304,7 +299,7 @@
assertTrue(cmActivity.waitForNetworkState(ConnectivityManager.TYPE_WIFI, State.DISCONNECTED,
ConnectivityManagerTestActivity.LONG_TIMEOUT));
- if (!UtilHelper.isWifiOnly()) {
+ if (!mIsWifiOnlyDevice) {
assertTrue(cmActivity.waitForNetworkState(ConnectivityManager.TYPE_MOBILE,
State.CONNECTED, ConnectivityManagerTestActivity.LONG_TIMEOUT));
}
@@ -316,7 +311,7 @@
cmActivity.getTransitionFailureReason(ConnectivityManager.TYPE_WIFI));
assertTrue(false);
}
- if (!UtilHelper.isWifiOnly()) {
+ if (!mIsWifiOnlyDevice) {
if (!cmActivity.validateNetworkStates(ConnectivityManager.TYPE_MOBILE)) {
log("Mobile state transition validation failed.");
log("reason: " +
@@ -393,7 +388,7 @@
cmActivity.setAirplaneMode(getInstrumentation().getContext(), true);
NetworkInfo networkInfo;
- if (!UtilHelper.isWifiOnly()) {
+ if (!mIsWifiOnlyDevice) {
assertTrue(cmActivity.waitForNetworkState(ConnectivityManager.TYPE_MOBILE,
State.DISCONNECTED, ConnectivityManagerTestActivity.LONG_TIMEOUT));
networkInfo = cmActivity.mCM.getNetworkInfo(ConnectivityManager.TYPE_MOBILE);
@@ -419,7 +414,7 @@
cmActivity.getTransitionFailureReason(ConnectivityManager.TYPE_WIFI));
assertTrue("State validation failed", false);
}
- if (!UtilHelper.isWifiOnly()) {
+ if (!mIsWifiOnlyDevice) {
if (!cmActivity.validateNetworkStates(ConnectivityManager.TYPE_MOBILE)) {
log("state validation for Mobile failed");
log("reason: " +
@@ -471,7 +466,7 @@
assertTrue(cmActivity.waitForNetworkState(ConnectivityManager.TYPE_WIFI, State.CONNECTED,
ConnectivityManagerTestActivity.LONG_TIMEOUT));
- if (!UtilHelper.isWifiOnly()) {
+ if (!mIsWifiOnlyDevice) {
assertTrue(cmActivity.waitForNetworkState(ConnectivityManager.TYPE_MOBILE,
State.DISCONNECTED, ConnectivityManagerTestActivity.LONG_TIMEOUT));
}
diff --git a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/stress/WifiStressTest.java b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/stress/WifiStressTest.java
index 2069789..feb63cd 100644
--- a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/stress/WifiStressTest.java
+++ b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/stress/WifiStressTest.java
@@ -16,10 +16,6 @@
package com.android.connectivitymanagertest.stress;
-import com.android.connectivitymanagertest.ConnectivityManagerStressTestRunner;
-import com.android.connectivitymanagertest.ConnectivityManagerTestActivity;
-import com.android.connectivitymanagertest.UtilHelper;
-
import android.content.Context;
import android.net.ConnectivityManager;
import android.net.NetworkInfo.State;
@@ -31,15 +27,15 @@
import android.net.wifi.WifiManager;
import android.os.Environment;
import android.os.PowerManager;
-import android.os.IPowerManager;
-import android.os.SystemClock;
-import android.os.ServiceManager;
import android.provider.Settings;
import android.test.ActivityInstrumentationTestCase2;
import android.test.suitebuilder.annotation.LargeTest;
-
import android.util.Log;
+import com.android.connectivitymanagertest.ConnectivityManagerStressTestRunner;
+import com.android.connectivitymanagertest.ConnectivityManagerTestActivity;
+import com.android.connectivitymanagertest.UtilHelper;
+
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
@@ -79,6 +75,7 @@
private String mPassword;
private ConnectivityManagerStressTestRunner mRunner;
private BufferedWriter mOutputWriter = null;
+ private boolean mIsWifiOnlyDevice;
public WifiStressTest() {
super(ConnectivityManagerTestActivity.class);
@@ -100,6 +97,7 @@
mOutputWriter = new BufferedWriter(new FileWriter(new File(
Environment.getExternalStorageDirectory(), OUTPUT_FILE), true));
mAct.turnScreenOn();
+ mIsWifiOnlyDevice = UtilHelper.isWifiOnly(mRunner.getTargetContext());
if (!mAct.mWifiManager.isWifiEnabled()) {
log("Enable wi-fi before stress tests.");
if (!mAct.enableWifi()) {
@@ -271,7 +269,7 @@
assertTrue("Wait for Wi-Fi to idle timeout",
mAct.waitForNetworkState(ConnectivityManager.TYPE_WIFI, State.DISCONNECTED,
6 * ConnectivityManagerTestActivity.SHORT_TIMEOUT));
- if (!UtilHelper.isWifiOnly()) {
+ if (!mIsWifiOnlyDevice) {
// use long timeout as the pppd startup may take several retries.
assertTrue("Wait for cellular connection timeout",
mAct.waitForNetworkState(ConnectivityManager.TYPE_MOBILE, State.CONNECTED,
@@ -282,7 +280,7 @@
assertEquals("Wi-Fi is reconnected", State.DISCONNECTED,
mAct.mCM.getNetworkInfo(ConnectivityManager.TYPE_WIFI).getState());
- if (!UtilHelper.isWifiOnly()) {
+ if (!mIsWifiOnlyDevice) {
assertEquals("Cellular connection is down", State.CONNECTED,
mAct.mCM.getNetworkInfo(ConnectivityManager.TYPE_MOBILE).getState());
assertTrue("Mobile is connected, but no data connection.", mAct.pingTest(null));
diff --git a/core/tests/bandwidthtests/src/com/android/bandwidthtest/util/ConnectionUtil.java b/core/tests/bandwidthtests/src/com/android/bandwidthtest/util/ConnectionUtil.java
index a5e5ab0e..dfcbba9 100644
--- a/core/tests/bandwidthtests/src/com/android/bandwidthtest/util/ConnectionUtil.java
+++ b/core/tests/bandwidthtests/src/com/android/bandwidthtest/util/ConnectionUtil.java
@@ -146,10 +146,10 @@
Log.v("ConnectivityReceiver", "onReceive() called with " + intent);
return;
}
- if (intent.hasExtra(ConnectivityManager.EXTRA_NETWORK_INFO)) {
- mNetworkInfo = (NetworkInfo)
- intent.getParcelableExtra(ConnectivityManager.EXTRA_NETWORK_INFO);
- }
+
+ final ConnectivityManager connManager = (ConnectivityManager) context
+ .getSystemService(Context.CONNECTIVITY_SERVICE);
+ mNetworkInfo = connManager.getActiveNetworkInfo();
if (intent.hasExtra(ConnectivityManager.EXTRA_OTHER_NETWORK_INFO)) {
mOtherNetworkInfo = (NetworkInfo)
diff --git a/core/tests/coretests/src/android/accessibilityservice/InterrogationActivity.java b/core/tests/coretests/src/android/accessibilityservice/InterrogationActivity.java
index b4a0581..a9f144b 100644
--- a/core/tests/coretests/src/android/accessibilityservice/InterrogationActivity.java
+++ b/core/tests/coretests/src/android/accessibilityservice/InterrogationActivity.java
@@ -14,12 +14,12 @@
package android.accessibilityservice;
-import com.android.frameworks.coretests.R;
-
import android.app.Activity;
import android.os.Bundle;
import android.view.View;
+import com.android.frameworks.coretests.R;
+
/**
* Activity for testing the accessibility APIs for "interrogation" of
* the screen content. These APIs allow exploring the screen and
diff --git a/core/tests/coretests/src/android/accessibilityservice/InterrogationActivityTest.java b/core/tests/coretests/src/android/accessibilityservice/InterrogationActivityTest.java
index 259a094..fa48093 100644
--- a/core/tests/coretests/src/android/accessibilityservice/InterrogationActivityTest.java
+++ b/core/tests/coretests/src/android/accessibilityservice/InterrogationActivityTest.java
@@ -14,26 +14,21 @@
package android.accessibilityservice;
-import static android.view.accessibility.AccessibilityNodeInfo.ACTION_CLEAR_FOCUS;
-import static android.view.accessibility.AccessibilityNodeInfo.ACTION_CLEAR_SELECTION;
import static android.view.accessibility.AccessibilityNodeInfo.ACTION_FOCUS;
+import static android.view.accessibility.AccessibilityNodeInfo.ACTION_CLEAR_FOCUS;
import static android.view.accessibility.AccessibilityNodeInfo.ACTION_SELECT;
+import static android.view.accessibility.AccessibilityNodeInfo.ACTION_CLEAR_SELECTION;
-import android.content.Context;
import android.graphics.Rect;
-import android.os.ServiceManager;
import android.os.SystemClock;
import android.test.ActivityInstrumentationTestCase2;
import android.test.suitebuilder.annotation.LargeTest;
import android.util.Log;
-import android.view.View;
import android.view.accessibility.AccessibilityEvent;
-import android.view.accessibility.AccessibilityInteractionClient;
-import android.view.accessibility.AccessibilityManager;
import android.view.accessibility.AccessibilityNodeInfo;
-import android.view.accessibility.IAccessibilityManager;
import com.android.frameworks.coretests.R;
+import com.android.internal.util.Predicate;
import java.util.ArrayList;
import java.util.LinkedList;
@@ -48,21 +43,15 @@
*/
public class InterrogationActivityTest
extends ActivityInstrumentationTestCase2<InterrogationActivity> {
- private static final boolean DEBUG = true;
+ private static final boolean DEBUG = false;
private static String LOG_TAG = "InterrogationActivityTest";
- // Timeout before give up wait for the system to process an accessibility setting change.
- private static final int TIMEOUT_PROPAGATE_ACCESSIBLITY_SETTING = 2000;
-
// Timeout for the accessibility state of an Activity to be fully initialized.
- private static final int TIMEOUT_ACCESSIBLITY_STATE_INITIALIZED_MILLIS = 100;
+ private static final int TIMEOUT_PROPAGATE_ACCESSIBILITY_EVENT_MILLIS = 5000;
// Handle to a connection to the AccessibilityManagerService
- private static int sConnectionId = View.NO_ID;
-
- // The last received accessibility event
- private volatile AccessibilityEvent mLastAccessibilityEvent;
+ private UiTestAutomationBridge mUiTestAutomationBridge;
public InterrogationActivityTest() {
super(InterrogationActivity.class);
@@ -70,16 +59,39 @@
@Override
public void setUp() throws Exception {
- ensureConnection();
- bringUpActivityWithInitalizedAccessbility();
+ super.setUp();
+ mUiTestAutomationBridge = new UiTestAutomationBridge();
+ mUiTestAutomationBridge.connect();
+ mUiTestAutomationBridge.executeCommandAndWaitForAccessibilityEvent(new Runnable() {
+ // wait for the first accessibility event
+ @Override
+ public void run() {
+ // bring up the activity
+ getActivity();
+ }
+ },
+ new Predicate<AccessibilityEvent>() {
+ @Override
+ public boolean apply(AccessibilityEvent event) {
+ return (event.getEventType() == AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED
+ && event.getPackageName().equals(getActivity().getPackageName()));
+ }
+ },
+ TIMEOUT_PROPAGATE_ACCESSIBILITY_EVENT_MILLIS);
+ }
+
+ @Override
+ public void tearDown() throws Exception {
+ mUiTestAutomationBridge.disconnect();
+ super.tearDown();
}
@LargeTest
public void testFindAccessibilityNodeInfoByViewId() throws Exception {
final long startTimeMillis = SystemClock.uptimeMillis();
try {
- AccessibilityNodeInfo button = AccessibilityInteractionClient.getInstance()
- .findAccessibilityNodeInfoByViewIdInActiveWindow(sConnectionId, R.id.button5);
+ AccessibilityNodeInfo button = mUiTestAutomationBridge
+ .findAccessibilityNodeInfoByViewIdInActiveWindow(R.id.button5);
assertNotNull(button);
assertEquals(0, button.getChildCount());
@@ -125,8 +137,8 @@
final long startTimeMillis = SystemClock.uptimeMillis();
try {
// find a view by text
- List<AccessibilityNodeInfo> buttons = AccessibilityInteractionClient.getInstance()
- .findAccessibilityNodeInfosByTextInActiveWindow(sConnectionId, "butto");
+ List<AccessibilityNodeInfo> buttons = mUiTestAutomationBridge
+ .findAccessibilityNodeInfosByTextInActiveWindow("butto");
assertEquals(9, buttons.size());
} finally {
if (DEBUG) {
@@ -141,12 +153,9 @@
public void testFindAccessibilityNodeInfoByViewTextContentDescription() throws Exception {
final long startTimeMillis = SystemClock.uptimeMillis();
try {
- bringUpActivityWithInitalizedAccessbility();
-
// find a view by text
- List<AccessibilityNodeInfo> buttons = AccessibilityInteractionClient.getInstance()
- .findAccessibilityNodeInfosByTextInActiveWindow(sConnectionId,
- "contentDescription");
+ List<AccessibilityNodeInfo> buttons = mUiTestAutomationBridge
+ .findAccessibilityNodeInfosByTextInActiveWindow("contentDescription");
assertEquals(1, buttons.size());
} finally {
if (DEBUG) {
@@ -177,8 +186,8 @@
classNameAndTextList.add("android.widget.ButtonButton8");
classNameAndTextList.add("android.widget.ButtonButton9");
- AccessibilityNodeInfo root = AccessibilityInteractionClient.getInstance()
- .findAccessibilityNodeInfoByViewIdInActiveWindow(sConnectionId, R.id.root);
+ AccessibilityNodeInfo root = mUiTestAutomationBridge
+ .findAccessibilityNodeInfoByViewIdInActiveWindow(R.id.root);
assertNotNull("We must find the existing root.", root);
Queue<AccessibilityNodeInfo> fringe = new LinkedList<AccessibilityNodeInfo>();
@@ -216,16 +225,16 @@
final long startTimeMillis = SystemClock.uptimeMillis();
try {
// find a view and make sure it is not focused
- AccessibilityNodeInfo button = AccessibilityInteractionClient.getInstance()
- .findAccessibilityNodeInfoByViewIdInActiveWindow(sConnectionId, R.id.button5);
+ AccessibilityNodeInfo button = mUiTestAutomationBridge
+ .findAccessibilityNodeInfoByViewIdInActiveWindow(R.id.button5);
assertFalse(button.isFocused());
// focus the view
assertTrue(button.performAction(ACTION_FOCUS));
// find the view again and make sure it is focused
- button = AccessibilityInteractionClient.getInstance()
- .findAccessibilityNodeInfoByViewIdInActiveWindow(sConnectionId, R.id.button5);
+ button = mUiTestAutomationBridge
+ .findAccessibilityNodeInfoByViewIdInActiveWindow(R.id.button5);
assertTrue(button.isFocused());
} finally {
if (DEBUG) {
@@ -240,24 +249,24 @@
final long startTimeMillis = SystemClock.uptimeMillis();
try {
// find a view and make sure it is not focused
- AccessibilityNodeInfo button = AccessibilityInteractionClient.getInstance()
- .findAccessibilityNodeInfoByViewIdInActiveWindow(sConnectionId, R.id.button5);
+ AccessibilityNodeInfo button = mUiTestAutomationBridge
+ .findAccessibilityNodeInfoByViewIdInActiveWindow(R.id.button5);
assertFalse(button.isFocused());
// focus the view
assertTrue(button.performAction(ACTION_FOCUS));
// find the view again and make sure it is focused
- button = AccessibilityInteractionClient.getInstance()
- .findAccessibilityNodeInfoByViewIdInActiveWindow(sConnectionId, R.id.button5);
+ button = mUiTestAutomationBridge
+ .findAccessibilityNodeInfoByViewIdInActiveWindow(R.id.button5);
assertTrue(button.isFocused());
// unfocus the view
assertTrue(button.performAction(ACTION_CLEAR_FOCUS));
// find the view again and make sure it is not focused
- button = AccessibilityInteractionClient.getInstance()
- .findAccessibilityNodeInfoByViewIdInActiveWindow(sConnectionId, R.id.button5);
+ button = mUiTestAutomationBridge
+ .findAccessibilityNodeInfoByViewIdInActiveWindow(R.id.button5);
assertFalse(button.isFocused());
} finally {
if (DEBUG) {
@@ -273,16 +282,16 @@
final long startTimeMillis = SystemClock.uptimeMillis();
try {
// find a view and make sure it is not selected
- AccessibilityNodeInfo button = AccessibilityInteractionClient.getInstance()
- .findAccessibilityNodeInfoByViewIdInActiveWindow(sConnectionId, R.id.button5);
+ AccessibilityNodeInfo button = mUiTestAutomationBridge
+ .findAccessibilityNodeInfoByViewIdInActiveWindow(R.id.button5);
assertFalse(button.isSelected());
// select the view
assertTrue(button.performAction(ACTION_SELECT));
// find the view again and make sure it is selected
- button = AccessibilityInteractionClient.getInstance()
- .findAccessibilityNodeInfoByViewIdInActiveWindow(sConnectionId, R.id.button5);
+ button = mUiTestAutomationBridge
+ .findAccessibilityNodeInfoByViewIdInActiveWindow(R.id.button5);
assertTrue(button.isSelected());
} finally {
if (DEBUG) {
@@ -297,24 +306,24 @@
final long startTimeMillis = SystemClock.uptimeMillis();
try {
// find a view and make sure it is not selected
- AccessibilityNodeInfo button = AccessibilityInteractionClient.getInstance()
- .findAccessibilityNodeInfoByViewIdInActiveWindow(sConnectionId, R.id.button5);
+ AccessibilityNodeInfo button = mUiTestAutomationBridge
+ .findAccessibilityNodeInfoByViewIdInActiveWindow(R.id.button5);
assertFalse(button.isSelected());
// select the view
assertTrue(button.performAction(ACTION_SELECT));
// find the view again and make sure it is selected
- button = AccessibilityInteractionClient.getInstance()
- .findAccessibilityNodeInfoByViewIdInActiveWindow(sConnectionId, R.id.button5);
+ button = mUiTestAutomationBridge
+ .findAccessibilityNodeInfoByViewIdInActiveWindow(R.id.button5);
assertTrue(button.isSelected());
// unselect the view
assertTrue(button.performAction(ACTION_CLEAR_SELECTION));
// find the view again and make sure it is not selected
- button = AccessibilityInteractionClient.getInstance()
- .findAccessibilityNodeInfoByViewIdInActiveWindow(sConnectionId, R.id.button5);
+ button = mUiTestAutomationBridge
+ .findAccessibilityNodeInfoByViewIdInActiveWindow(R.id.button5);
assertFalse(button.isSelected());
} finally {
if (DEBUG) {
@@ -330,23 +339,33 @@
final long startTimeMillis = SystemClock.uptimeMillis();
try {
// find a view and make sure it is not focused
- AccessibilityNodeInfo button = AccessibilityInteractionClient.getInstance()
- .findAccessibilityNodeInfoByViewIdInActiveWindow(sConnectionId, R.id.button5);
- assertFalse(button.isSelected());
+ final AccessibilityNodeInfo button = mUiTestAutomationBridge
+ .findAccessibilityNodeInfoByViewIdInActiveWindow(R.id.button5);
+ assertFalse(button.isFocused());
- // focus the view
- assertTrue(button.performAction(ACTION_FOCUS));
-
- synchronized (this) {
- try {
- wait(TIMEOUT_ACCESSIBLITY_STATE_INITIALIZED_MILLIS);
- } catch (InterruptedException ie) {
- /* ignore */
+ AccessibilityEvent event = mUiTestAutomationBridge
+ .executeCommandAndWaitForAccessibilityEvent(new Runnable() {
+ @Override
+ public void run() {
+ // focus the view
+ assertTrue(button.performAction(ACTION_FOCUS));
}
- }
+ },
+ new Predicate<AccessibilityEvent>() {
+ @Override
+ public boolean apply(AccessibilityEvent event) {
+ return (event.getEventType() == AccessibilityEvent.TYPE_VIEW_FOCUSED
+ && event.getPackageName().equals(getActivity().getPackageName())
+ && event.getText().get(0).equals(button.getText()));
+ }
+ },
+ TIMEOUT_PROPAGATE_ACCESSIBILITY_EVENT_MILLIS);
+
+ // check the last event
+ assertNotNull(event);
// check that last event source
- AccessibilityNodeInfo source = mLastAccessibilityEvent.getSource();
+ AccessibilityNodeInfo source = event.getSource();
assertNotNull(source);
// bounds
@@ -389,8 +408,9 @@
final long startTimeMillis = SystemClock.uptimeMillis();
try {
// find a view and make sure it is not focused
- AccessibilityNodeInfo button = AccessibilityInteractionClient.getInstance()
- .findAccessibilityNodeInfoByViewIdInActiveWindow(sConnectionId, R.id.button5);
+ AccessibilityNodeInfo button = mUiTestAutomationBridge
+ .findAccessibilityNodeInfoByViewIdInActiveWindow(R.id.button5);
+ assertNotNull(button);
AccessibilityNodeInfo parent = button.getParent();
final int childCount = parent.getChildCount();
for (int i = 0; i < childCount; i++) {
@@ -410,71 +430,4 @@
}
}
}
-
- private void bringUpActivityWithInitalizedAccessbility() {
- mLastAccessibilityEvent = null;
- // bring up the activity
- getActivity();
-
- final long startTimeMillis = SystemClock.uptimeMillis();
- while (true) {
- if (mLastAccessibilityEvent != null) {
- final int eventType = mLastAccessibilityEvent.getEventType();
- if (eventType == AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED) {
- return;
- }
- }
- final long remainingTimeMillis = TIMEOUT_ACCESSIBLITY_STATE_INITIALIZED_MILLIS
- - (SystemClock.uptimeMillis() - startTimeMillis);
- if (remainingTimeMillis <= 0) {
- return;
- }
- synchronized (this) {
- try {
- wait(remainingTimeMillis);
- } catch (InterruptedException e) {
- /* ignore */
- }
- }
- }
- }
-
- private void ensureConnection() throws Exception {
- if (sConnectionId == View.NO_ID) {
- IEventListener listener = new IEventListener.Stub() {
- public void setConnection(IAccessibilityServiceConnection connection,
- int connectionId) {
- sConnectionId = connectionId;
- if (connection != null) {
- AccessibilityInteractionClient.getInstance().addConnection(connectionId,
- connection);
- } else {
- AccessibilityInteractionClient.getInstance().removeConnection(connectionId);
- }
- synchronized (this) {
- notifyAll();
- }
- }
-
- public void onInterrupt() {}
-
- public void onAccessibilityEvent(AccessibilityEvent event) {
- mLastAccessibilityEvent = AccessibilityEvent.obtain(event);
- synchronized (this) {
- notifyAll();
- }
- }
- };
-
- AccessibilityManager accessibilityManager =
- AccessibilityManager.getInstance(getInstrumentation().getContext());
-
- synchronized (this) {
- IAccessibilityManager manager = IAccessibilityManager.Stub.asInterface(
- ServiceManager.getService(Context.ACCESSIBILITY_SERVICE));
- manager.registerEventListener(listener);
- wait(TIMEOUT_PROPAGATE_ACCESSIBLITY_SETTING);
- }
- }
- }
}
diff --git a/core/tests/coretests/src/android/util/InternalSelectionView.java b/core/tests/coretests/src/android/util/InternalSelectionView.java
index babf38d..a0fb0f1 100644
--- a/core/tests/coretests/src/android/util/InternalSelectionView.java
+++ b/core/tests/coretests/src/android/util/InternalSelectionView.java
@@ -36,6 +36,11 @@
* entire width of the view. The height of the view is divided evenly among
* the rows.
*
+ * Note: If the height of the view does not divide exactly to the number of rows,
+ * the last row's height is inflated with the remainder. For example, if the
+ * view height is 22 and there are two rows, the height of the first row is
+ * 10 and the second 22.
+ *
* Notice what this view does to be a good citizen w.r.t its internal selection:
* 1) calls {@link View#requestRectangleOnScreen} each time the selection changes due to
* internal navigation.
@@ -138,9 +143,6 @@
@Override
protected void onDraw(Canvas canvas) {
-
- int rowHeight = getRowHeight();
-
int rectTop = mPaddingTop;
int rectLeft = mPaddingLeft;
int rectRight = getWidth() - mPaddingRight;
@@ -149,6 +151,8 @@
mPainter.setColor(Color.BLACK);
mPainter.setAlpha(0x20);
+ int rowHeight = getRowHeight(i);
+
// draw background rect
mTempRect.set(rectLeft, rectTop, rectRight, rectTop + rowHeight);
canvas.drawRect(mTempRect, mPainter);
@@ -178,12 +182,19 @@
}
}
- private int getRowHeight() {
- return (getHeight() - mPaddingTop - mPaddingBottom) / mNumRows;
+ private int getRowHeight(int row) {
+ final int availableHeight = getHeight() - mPaddingTop - mPaddingBottom;
+ final int desiredRowHeight = availableHeight / mNumRows;
+ if (row < mNumRows - 1) {
+ return desiredRowHeight;
+ } else {
+ final int residualHeight = availableHeight % mNumRows;
+ return desiredRowHeight + residualHeight;
+ }
}
public void getRectForRow(Rect rect, int row) {
- final int rowHeight = getRowHeight();
+ final int rowHeight = getRowHeight(row);
final int top = mPaddingTop + row * rowHeight;
rect.set(mPaddingLeft,
top,
@@ -197,10 +208,7 @@
requestRectangleOnScreen(mTempRect);
}
-
- /* (non-Javadoc)
- * @see android.view.KeyEvent.Callback#onKeyDown(int, android.view.KeyEvent)
- */
+ @Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
switch(event.getKeyCode()) {
case KeyEvent.KEYCODE_DPAD_UP:
diff --git a/core/tests/coretests/src/android/widget/focus/ListOfInternalSelectionViews.java b/core/tests/coretests/src/android/widget/focus/ListOfInternalSelectionViews.java
index 6518341..53b866c 100644
--- a/core/tests/coretests/src/android/widget/focus/ListOfInternalSelectionViews.java
+++ b/core/tests/coretests/src/android/widget/focus/ListOfInternalSelectionViews.java
@@ -17,6 +17,7 @@
package android.widget.focus;
import android.app.Activity;
+import android.graphics.Point;
import android.os.Bundle;
import android.view.View;
import android.view.ViewGroup;
@@ -110,7 +111,10 @@
@Override
protected void onCreate(Bundle icicle) {
super.onCreate(icicle);
- mScreenHeight = getWindowManager().getDefaultDisplay().getHeight();
+
+ Point size = new Point();
+ getWindowManager().getDefaultDisplay().getSize(size);
+ mScreenHeight = size.y;
Bundle extras = getIntent().getExtras();
if (extras != null) {
diff --git a/core/tests/coretests/src/android/widget/focus/RequestFocus.java b/core/tests/coretests/src/android/widget/focus/RequestFocus.java
index af9ee17..21d762a 100644
--- a/core/tests/coretests/src/android/widget/focus/RequestFocus.java
+++ b/core/tests/coretests/src/android/widget/focus/RequestFocus.java
@@ -21,9 +21,7 @@
import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
-import android.widget.LinearLayout;
import android.widget.Button;
-import android.view.View;
/**
* Exercises cases where elements of the UI are requestFocus()ed.
diff --git a/core/tests/coretests/src/android/widget/focus/RequestFocusTest.java b/core/tests/coretests/src/android/widget/focus/RequestFocusTest.java
index 909a8c9..baf587e 100644
--- a/core/tests/coretests/src/android/widget/focus/RequestFocusTest.java
+++ b/core/tests/coretests/src/android/widget/focus/RequestFocusTest.java
@@ -16,21 +16,27 @@
package android.widget.focus;
-import android.widget.focus.RequestFocus;
-import com.android.frameworks.coretests.R;
-
import android.os.Handler;
-import android.test.ActivityInstrumentationTestCase;
+import android.test.ActivityInstrumentationTestCase2;
+import android.test.UiThreadTest;
import android.test.suitebuilder.annotation.LargeTest;
import android.test.suitebuilder.annotation.MediumTest;
-import android.widget.Button;
import android.util.AndroidRuntimeException;
+import android.view.View;
+import android.view.View.OnFocusChangeListener;
+import android.view.ViewTreeObserver.OnGlobalFocusChangeListener;
+import android.widget.Button;
+
+import com.android.frameworks.coretests.R;
+
+import java.util.ArrayList;
+import java.util.List;
/**
* {@link RequestFocusTest} is set up to exercise cases where the views that
* have focus become invisible or GONE.
*/
-public class RequestFocusTest extends ActivityInstrumentationTestCase<RequestFocus> {
+public class RequestFocusTest extends ActivityInstrumentationTestCase2<RequestFocus> {
private Button mTopLeftButton;
private Button mBottomLeftButton;
@@ -39,7 +45,7 @@
private Handler mHandler;
public RequestFocusTest() {
- super("com.android.frameworks.coretests", RequestFocus.class);
+ super(RequestFocus.class);
}
@Override
@@ -90,8 +96,149 @@
fail("requestFocus from wrong thread should raise exception.");
} catch (AndroidRuntimeException e) {
// Expected. The actual exception is not public, so we can't catch it.
- assertEquals("android.view.ViewAncestor$CalledFromWrongThreadException",
+ assertEquals("android.view.ViewRootImpl$CalledFromWrongThreadException",
e.getClass().getName());
}
}
+
+ /**
+ * This tests checks the case in which the first focusable View clears focus.
+ * In such a case the framework tries to give the focus to another View starting
+ * from the top. Hence, the framework will try to give focus to the view that
+ * wants to clear its focus. From a client perspective, the view does not loose
+ * focus after the call, therefore no callback for focus change should be invoked.
+ *
+ * @throws Exception If an error occurs.
+ */
+ @UiThreadTest
+ public void testOnFocusChangeNotCalledIfFocusDoesNotMove() throws Exception {
+ // Get the first focusable.
+ Button button = mTopLeftButton;
+
+ // Make sure that the button is the first focusable and focus it.
+ button.getRootView().requestFocus(View.FOCUS_DOWN);
+ assertTrue(button.hasFocus());
+
+ // Attach on focus change listener that should not be called.
+ button.setOnFocusChangeListener(new OnFocusChangeListener() {
+ @Override
+ public void onFocusChange(View v, boolean hasFocus) {
+ throw new IllegalStateException("Unexpeced call to"
+ + "OnFocusChangeListener#onFocusChange");
+ }
+ });
+
+ // Attach on global focus change listener that should not be called.
+ button.getViewTreeObserver().addOnGlobalFocusChangeListener(
+ new OnGlobalFocusChangeListener() {
+ @Override
+ public void onGlobalFocusChanged(View oldFocus, View newFocus) {
+ throw new IllegalStateException("Unexpeced call to"
+ + "OnFocusChangeListener#onFocusChange");
+ }
+ });
+
+ // Try to clear focus.
+ button.clearFocus();
+ }
+
+ /**
+ * This tests check whether the on focus change callbacks are invoked in
+ * the proper order when a View loses focus and the framework gives it to
+ * the fist focusable one.
+ *
+ * @throws Exception
+ */
+ @UiThreadTest
+ public void testOnFocusChangeCallbackOrder() throws Exception {
+ // Get the first focusable.
+ Button clearingFocusButton = mTopRightButton;
+ Button gainingFocusButton = mTopLeftButton;
+
+ // Make sure that the clearing focus is not the first focusable.
+ View focusCandidate = clearingFocusButton.getRootView().getParent().focusSearch(null,
+ View.FOCUS_FORWARD);
+ assertNotSame("The clearing focus button is not the first focusable.",
+ clearingFocusButton, focusCandidate);
+ assertSame("The gaining focus button is the first focusable.",
+ gainingFocusButton, focusCandidate);
+
+ // Focus the clearing focus button.
+ clearingFocusButton.requestFocus();
+ assertTrue(clearingFocusButton.hasFocus());
+
+ // Register the invocation order checker.
+ CallbackOrderChecker checker = new CallbackOrderChecker(clearingFocusButton,
+ gainingFocusButton);
+ clearingFocusButton.setOnFocusChangeListener(checker);
+ gainingFocusButton.setOnFocusChangeListener(checker);
+ clearingFocusButton.getViewTreeObserver().addOnGlobalFocusChangeListener(checker);
+
+ // Try to clear focus.
+ clearingFocusButton.clearFocus();
+
+ // Check that no callback was invoked since focus did not move.
+ checker.verify();
+ }
+
+ /**
+ * This class check whether the focus change callback are invoked in order.
+ */
+ private class CallbackOrderChecker implements OnFocusChangeListener,
+ OnGlobalFocusChangeListener {
+
+ private class CallbackInvocation {
+ final String mMethodName;
+ final Object[] mArguments;
+
+ CallbackInvocation(String methodName, Object[] arguments) {
+ mMethodName = methodName;
+ mArguments = arguments;
+ }
+ }
+
+ private final View mClearingFocusView;
+ private final View mGainingFocusView;
+
+ private final List<CallbackInvocation> mInvocations = new ArrayList<CallbackInvocation>();
+
+ public CallbackOrderChecker(View clearingFocusView, View gainingFocusView) {
+ mClearingFocusView = clearingFocusView;
+ mGainingFocusView = gainingFocusView;
+ }
+
+ @Override
+ public void onFocusChange(View view, boolean hasFocus) {
+ CallbackInvocation invocation = new CallbackInvocation(
+ "OnFocusChangeListener#onFocusChange", new Object[] {view, hasFocus});
+ mInvocations.add(invocation);
+ }
+
+ @Override
+ public void onGlobalFocusChanged(View oldFocus, View newFocus) {
+ CallbackInvocation invocation = new CallbackInvocation(
+ "OnFocusChangeListener#onFocusChange", new Object[] {oldFocus, newFocus});
+ mInvocations.add(invocation);
+ }
+
+ public void verify() {
+ assertSame("All focus change callback should be invoked.", 3, mInvocations.size());
+ assertInvioked("Callback for View clearing focus explected.", 0,
+ "OnFocusChangeListener#onFocusChange",
+ new Object[] {mClearingFocusView, false});
+ assertInvioked("Callback for View global focus change explected.", 1,
+ "OnFocusChangeListener#onFocusChange", new Object[] {mClearingFocusView,
+ mGainingFocusView});
+ assertInvioked("Callback for View gaining focus explected.", 2,
+ "OnFocusChangeListener#onFocusChange", new Object[] {mGainingFocusView, true});
+ }
+
+ private void assertInvioked(String message, int order, String methodName,
+ Object[] arguments) {
+ CallbackInvocation invocation = mInvocations.get(order);
+ assertEquals(message, methodName, invocation.mMethodName);
+ assertEquals(message, arguments[0], invocation.mArguments[0]);
+ assertEquals(message, arguments[1], invocation.mArguments[1]);
+ }
+ }
}
diff --git a/core/tests/coretests/src/android/widget/focus/ScrollingThroughListOfFocusablesTest.java b/core/tests/coretests/src/android/widget/focus/ScrollingThroughListOfFocusablesTest.java
index eb9192a..795e09c 100644
--- a/core/tests/coretests/src/android/widget/focus/ScrollingThroughListOfFocusablesTest.java
+++ b/core/tests/coretests/src/android/widget/focus/ScrollingThroughListOfFocusablesTest.java
@@ -20,10 +20,9 @@
import android.test.InstrumentationTestCase;
import android.test.suitebuilder.annotation.LargeTest;
import android.test.suitebuilder.annotation.MediumTest;
+import android.util.InternalSelectionView;
import android.view.KeyEvent;
import android.widget.ListView;
-import android.widget.focus.ListOfInternalSelectionViews;
-import android.util.InternalSelectionView;
/**
@@ -51,6 +50,10 @@
mNumRowsPerItem, // 5 internally selectable rows per item
mScreenHeightFactor)); // each item is 5 / 4 screen height tall
mListView = mActivity.getListView();
+ // Make sure we have some fading edge regardless of ListView style.
+ mListView.setVerticalFadingEdgeEnabled(true);
+ mListView.setFadingEdgeLength(10);
+ ensureNotInTouchMode();
}
@Override
@@ -67,12 +70,12 @@
assertEquals(mNumRowsPerItem, mActivity.getNumRowsPerItem());
}
- // TODO: needs to be adjusted to pass on non-HVGA displays
- // @MediumTest
+ @MediumTest
public void testScrollingDownInFirstItem() throws Exception {
for (int i = 0; i < mNumRowsPerItem; i++) {
assertEquals(0, mListView.getSelectedItemPosition());
+
InternalSelectionView view = mActivity.getSelectedView();
assertInternallySelectedRowOnScreen(view, i);
@@ -90,13 +93,12 @@
mListView.getSelectedView();
// 1 pixel tolerance in case height / 4 is not an even number
- final int fadingEdge = mListView.getBottom() - mListView.getVerticalFadingEdgeLength();
+ final int bottomFadingEdgeTop =
+ mListView.getBottom() - mListView.getVerticalFadingEdgeLength();
assertTrue("bottom of view should be just above fading edge",
- view.getBottom() >= fadingEdge - 1 &&
- view.getBottom() <= fadingEdge);
+ view.getBottom() == bottomFadingEdgeTop);
}
-
// make sure fading edge is the expected view
{
assertEquals("should be a second view visible due to the fading edge",
@@ -109,7 +111,6 @@
}
}
-
@MediumTest
public void testScrollingToSecondItem() throws Exception {
@@ -223,4 +224,12 @@
assertTrue("bottom of row " + row + " should be on sreen",
mTempRect.bottom < mActivity.getScreenHeight());
}
+
+ private void ensureNotInTouchMode() {
+ // If in touch mode inject a DPAD down event to exit that mode.
+ if (mListView.isInTouchMode()) {
+ sendKeys(KeyEvent.KEYCODE_DPAD_DOWN);
+ getInstrumentation().waitForIdleSync();
+ }
+ }
}
diff --git a/docs/html/design/get-started/ui-overview.html b/docs/html/design/get-started/ui-overview.html
index b08c743..bd5ff9c 100644
--- a/docs/html/design/get-started/ui-overview.html
+++ b/docs/html/design/get-started/ui-overview.html
@@ -153,12 +153,12 @@
</div>
</div>
-<h2>UI Bars</h2>
+<h2>System Bars</h2>
-<p>The UI bars are screen areas dedicated to the display of notifications, communication of device
-status, and device navigation. Typically the UI bars are displayed concurrently with your app. Apps
-that display immersive content, such as movies or images, can temporarily hide the UI bars to allow
-the user to enjoy full screen content without distraction.</p>
+<p>The system bars are screen areas dedicated to the display of notifications, communication of device
+status, and device navigation. Typically the system bars are displayed concurrently with your app.
+Apps that display immersive content, such as movies or images, can temporarily hide the system bars
+to allow the user to enjoy full screen content without distraction.</p>
<img src="../static/content/ui_overview_system_ui.png">
@@ -177,8 +177,9 @@
Recents, and also displays a menu for apps written for Android 2.3 or earlier.</p>
</li>
<li>
-<h4>System Bar</h4>
-<p>Combines the status and navigation bars for display on tablet form factors.</p>
+<h4>Combined Bar</h4>
+<p>On tablet form factors the status and navigation bars are combined into a single bar at the
+ bottom of the screen.</p>
</li>
</ol>
diff --git a/docs/html/design/patterns/actionbar.html b/docs/html/design/patterns/actionbar.html
index 99ae2d7..911c549 100644
--- a/docs/html/design/patterns/actionbar.html
+++ b/docs/html/design/patterns/actionbar.html
@@ -133,7 +133,7 @@
you wish.
Important: If the app is currently not displaying the top-level screen, be sure to display the Up
caret to the left of the app icon, so the user can navigate up the hierarchy. For more discussion of
-Up navigation, see the "Navigation" pattern.
+Up navigation, see the <a href="../patterns/navigation.html">Navigation</a> pattern.
<div class="figure">
<img src="../static/content/action_bar_pattern_up_app_icon.png">
@@ -369,6 +369,22 @@
<p>If either F, I, or T apply, then it's appropriate for the action bar. Otherwise, it belongs in the
action overflow.</p>
+<p>
+
+Pre-defined glyphs should be used for certain common actions such as "refresh" and "share." The
+download link below provides a package with icons that are scaled for various screen densities and
+are suitable for use with the Holo Light and Holo Dark themes. The package also includes unstyled
+icons that you can modify to match your theme, in addition to Adobe® Illustrator® source
+files for further customization.
+
+</p>
+<p>
+
+<a href="../static/download/action_bar_icons-v4.0.zip">Download the Action Bar Icon
+Pack</a>
+
+</p>
+
<div class="layout-content-row">
<div class="layout-content-col span-6">
diff --git a/docs/html/design/patterns/app-structure.html b/docs/html/design/patterns/app-structure.html
index b87f402..fb9205b 100644
--- a/docs/html/design/patterns/app-structure.html
+++ b/docs/html/design/patterns/app-structure.html
@@ -159,9 +159,9 @@
<img src="../static/content/app_structure_market.png">
<div class="figure-caption">
- Market's start screen primarily allows navigation into the stores for Apps, Music, Books, and
- Games. It is also enriched with tailored recommendations and promotions that surface content
- of interest to the user. Search is readily available from the action bar.
+ Market's start screen primarily allows navigation into the stores for Apps, Music, Books,
+ Movies and Games. It is also enriched with tailored recommendations and promotions that
+ surface content of interest to the user. Search is readily available from the action bar.
</div>
</div>
diff --git a/docs/html/design/patterns/navigation.html b/docs/html/design/patterns/navigation.html
index aabfc39..cad3682 100644
--- a/docs/html/design/patterns/navigation.html
+++ b/docs/html/design/patterns/navigation.html
@@ -131,7 +131,7 @@
<p>The Back key also supports a few behaviors not directly tied to screen-to-screen navigation:</p>
<ul>
<li>Back dismisses floating windows (dialogs, popups)</li>
-<li>Back dismisses contextual action bars, and remove highlight from selected items</li>
+<li>Back dismisses contextual action bars, and removes the highlight from the selected items</li>
<li>Back hides the onscreen keyboard (IME)</li>
</ul>
<h2>Navigation Within Your App</h2>
@@ -189,18 +189,19 @@
<h4>App-to-app navigation</h4>
<p>When navigating deep into your app's hierarchy directly from another app via an intent, Back will
return to the referring app.</p>
-<p>The Up button is handled is follows:
+<p>The Up button is handled as follows:
- If the destination screen is typically reached from one particular screen within your app, Up
should navigate to that screen.
- Otherwise, Up should navigate to the topmost ("Home") screen of your app.</p>
-<p>For example, after choosing to share a book being view in Market, the user navigates directly to the
-Gmail's compose screen. From there, Up returns to the Inbox (which happens to be both the typical
-referrer to compose, as well as the topmost screen of the app), while Back returns to Market.</p>
+<p>For example, after choosing to share a book being viewed in Market, the user navigates directly to
+Gmail's compose screen. From there, Up returns to the Inbox (which happens to be both the
+typical referrer to compose, as well as the topmost screen of the app), while Back returns to
+Market.</p>
<img src="../static/content/navigation_from_outside_up.png">
<h4>System-to-app navigation</h4>
-<p>If the your app was reached via the system mechanisms of notifications or home screen widgets, Up
+<p>If your app was reached via the system mechanisms of notifications or home screen widgets, Up
behaves as described for app-to-app navigation, above.</p>
<p>For the Back key, you should make navigation more predictably by inserting into the task's back
stack the complete upward navigation path to the app's topmost screen. This way, a user who has
diff --git a/docs/html/design/patterns/notifications.html b/docs/html/design/patterns/notifications.html
index acec306..c5045aed 100644
--- a/docs/html/design/patterns/notifications.html
+++ b/docs/html/design/patterns/notifications.html
@@ -200,7 +200,7 @@
the user is taken to a hierarchy level below your app's top-level, insert navigation into your app's
back stack to allow them to navigate to your app's top level using the system back key. For more
information, see the chapter on <em>System-to-app navigation</em> in the
-<a href="../patterns/notifications.html">Navigation</a> design pattern.</p>
+<a href="../patterns/navigation.html">Navigation</a> design pattern.</p>
<h4>Timestamps for time sensitive events</h4>
<p>By default, standard Android notifications include a timestamp in the upper right corner. Consider
whether the timestamp is valuable in the context of your notification. If the timestamp is not
diff --git a/docs/html/design/static/download/action_bar_icons-v4.0.zip b/docs/html/design/static/download/action_bar_icons-v4.0.zip
new file mode 100644
index 0000000..4568894
--- /dev/null
+++ b/docs/html/design/static/download/action_bar_icons-v4.0.zip
Binary files differ
diff --git a/docs/html/design/style/iconography.html b/docs/html/design/style/iconography.html
index 663770b..5d5d200 100644
--- a/docs/html/design/style/iconography.html
+++ b/docs/html/design/style/iconography.html
@@ -193,10 +193,28 @@
<h2 id="actionbar">Action Bar</h2>
-<p>Action bar icons are graphic buttons that represent the most important actions people can take
-within your app. Each one should employ a simple metaphor representing a single concept that most
-people can grasp at a glance.</p>
+<p>
+Action bar icons are graphic buttons that represent the most important actions people can take
+within your app. Each one should employ a simple metaphor representing a single concept that most
+people can grasp at a glance.
+
+</p>
+<p>
+
+Pre-defined glyphs should be used for certain common actions such as "refresh" and "share." The
+download link below provides a package with icons that are scaled for various screen densities and
+are suitable for use with the Holo Light and Holo Dark themes. The package also includes unstyled
+icons that you can modify to match your theme, in addition to Adobe® Illustrator® source
+files for further customization.
+
+</p>
+<p>
+
+<a href="../static/download/action_bar_icons-v4.0.zip">Download the Action Bar Icon
+Pack</a>
+
+</p>
<div class="layout-content-row">
<div class="layout-content-col span-4">
diff --git a/docs/html/guide/appendix/market-filters.jd b/docs/html/guide/appendix/market-filters.jd
index 07b9370..d9b2155 100644
--- a/docs/html/guide/appendix/market-filters.jd
+++ b/docs/html/guide/appendix/market-filters.jd
@@ -165,10 +165,10 @@
<p><strong>Example 1</strong><br />
The manifest declares <code><uses-sdk android:minSdkVersion="3"></code>
- and does not does not include a <code><supports-screens></code> element.
- <strong>Result</strong>: Android Market will not show the app to a user of a
- small-screen device, but will show it to users of normal and large-screen
- devices, users, unless other filters apply. </p>
+ and does not include a <code><supports-screens></code> element.
+ <strong>Result</strong>: Android Market does not show the app to a user of a
+ small-screen device, but does show it to users of normal and large-screen
+ devices, unless other filters also exclude those devices. </p>
<p><strong>Example 2<br />
</strong>The manifest declares <code><uses-sdk android:minSdkVersion="3"
android:targetSdkVersion="4"></code> and does not include a
diff --git a/docs/html/guide/developing/device.jd b/docs/html/guide/developing/device.jd
index c4d08ed..e46d07c 100644
--- a/docs/html/guide/developing/device.jd
+++ b/docs/html/guide/developing/device.jd
@@ -154,6 +154,14 @@
<td><code>0489</code></td>
</tr>
<tr>
+ <td>Fujitsu</td>
+ <td><code>04C5</code></td>
+ </tr>
+ <tr>
+ <td>Fujitsu Toshiba</td>
+ <td><code>04C5</code></td>
+ </tr>
+ <tr>
<td>Garmin-Asus</td>
<td><code>091E</code></td>
</tr>
diff --git a/docs/html/guide/guide_toc.cs b/docs/html/guide/guide_toc.cs
index be0ca0e..4a9a684 100644
--- a/docs/html/guide/guide_toc.cs
+++ b/docs/html/guide/guide_toc.cs
@@ -8,15 +8,16 @@
<ul>
<li>
- <h2><span class="en">Android Basics</span>
- <span class="de" style="display:none">Einführung in Android</span>
- <span class="es" style="display:none">Información básica sobre Android</span>
- <span class="fr" style="display:none">Présentation d'Android</span>
- <span class="it" style="display:none">Nozioni di base su Android</span>
- <span class="ja" style="display:none">Android の基本</span>
- <span class="zh-CN" style="display:none">Android 基础知识</span>
- <span class="zh-TW" style="display:none">Android 簡介</span>
- </h2>
+ <span class="heading">
+ <span class="en">Android Basics</span>
+ <span class="de" style="display:none">Einführung in Android</span>
+ <span class="es" style="display:none">Información básica sobre Android</span>
+ <span class="fr" style="display:none">Présentation d'Android</span>
+ <span class="it" style="display:none">Nozioni di base su Android</span>
+ <span class="ja" style="display:none">Android の基本</span>
+ <span class="zh-CN" style="display:none">Android 基础知识</span>
+ <span class="zh-TW" style="display:none">Android 簡介</span>
+ </span>
<ul>
<li><a href="<?cs var:toroot ?>guide/basics/what-is-android.html">
<span class="en">What Is Android?</span>
@@ -46,7 +47,7 @@
</li>
<li>
- <h2>
+ <span class="heading">
<span class="en">Framework Topics</span>
<span class="de" style="display:none">Framework-Themen</span>
<span class="es" style="display:none">Temas sobre el framework</span>
@@ -55,7 +56,7 @@
<span class="ja" style="display:none">フレームワーク トピック</span>
<span class="zh-CN" style="display:none">框架主题</span>
<span class="zh-TW" style="display:none">架構主題</span>
- </h2>
+ </span>
<ul>
<li class="toggle-list">
<div><a href="<?cs var:toroot ?>guide/topics/fundamentals/activities.html">
@@ -87,10 +88,24 @@
<span class="en">Content Providers</span>
</a></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>
+ <li>
+ <a href="<?cs var:toroot ?>guide/topics/providers/content-provider-basics.html">
+ <span class="en">Content Provider Basics</span>
+ </a>
+ <span class="new">new!</span>
+ </li>
+ <li>
+ <a href="<?cs var:toroot ?>guide/topics/providers/content-provider-creating.html">
+ <span class="en">Creating a Content Provider</span>
+ </a>
+ <span class="new">new!</span>
+ </li>
+ <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">
@@ -116,7 +131,7 @@
</a></li>
<li><a href="<?cs var:toroot ?>guide/topics/ui/menus.html">
<span class="en">Menus</span>
- </a></li>
+ </a> <span class="new">updated</span></li>
<li><a href="<?cs var:toroot ?>guide/topics/ui/actionbar.html">
<span class="en">Action Bar</span>
</a></li>
@@ -271,7 +286,8 @@
</li>
<li class="toggle-list">
<div><a href="<?cs var:toroot ?>guide/topics/renderscript/index.html">
- <span class="en">RenderScript</span></a>
+ <span class="en">Renderscript</span></a>
+ <span class="new">updated</span>
</div>
<ul>
<li><a href="<?cs var:toroot ?>guide/topics/renderscript/graphics.html">
@@ -364,6 +380,9 @@
<li><a href="<?cs var:toroot ?>guide/topics/nfc/advanced-nfc.html">Advanced NFC</a></li>
</ul>
</li>
+ <li><a href="<?cs var:toroot?>guide/topics/wireless/wifip2p.html">
+ <span class="en">Wi-Fi Direct</span></a> <span class="new">new!</span>
+ </li>
<li class="toggle-list">
<div><a href="<?cs var:toroot?>guide/topics/usb/index.html">
<span class="en">USB</span></a>
@@ -425,9 +444,9 @@
</li>
<li>
- <h2>
+ <span class="heading">
<span class="en">Android Market Topics</span>
- </h2>
+ </span>
<ul>
<li><a href="<?cs var:toroot ?>guide/publishing/publishing.html">
<span class="en">Publishing on Android Market</span>
@@ -471,15 +490,16 @@
<li>
- <h2><span class="en">Developing</span>
- <span class="de" style="display:none">Entwicklung</span>
- <span class="es" style="display:none">Desarrollo</span>
- <span class="fr" style="display:none">Développement</span>
- <span class="it" style="display:none">Sviluppo</span>
- <span class="ja" style="display:none">開発</span>
- <span class="zh-CN" style="display:none">开发</span>
- <span class="zh-TW" style="display:none">開發</span>
- </h2>
+ <span class="heading">
+ <span class="en">Developing</span>
+ <span class="de" style="display:none">Entwicklung</span>
+ <span class="es" style="display:none">Desarrollo</span>
+ <span class="fr" style="display:none">Développement</span>
+ <span class="it" style="display:none">Sviluppo</span>
+ <span class="ja" style="display:none">開発</span>
+ <span class="zh-CN" style="display:none">开发</span>
+ <span class="zh-TW" style="display:none">開發</span>
+ </span>
<ul>
<!--<li><a href="">Developing for Android</a></li>
signing, upgrading, selecting a package name, select device profile, touch, trackball, dpad available, etc. -->
@@ -665,15 +685,16 @@
</li>
<li>
- <h2><span class="en">Publishing</span>
- <span class="de" style="display:none">Veröffentlichung</span>
- <span class="es" style="display:none">Publicación</span>
- <span class="fr" style="display:none">Publication</span>
- <span class="it" style="display:none">Pubblicazione</span>
- <span class="ja" style="display:none">公開</span>
- <span class="zh-CN" style="display:none">发布</span>
- <span class="zh-TW" style="display:none">發佈</span>
- </h2>
+ <span class="heading">
+ <span class="en">Publishing</span>
+ <span class="de" style="display:none">Veröffentlichung</span>
+ <span class="es" style="display:none">Publicación</span>
+ <span class="fr" style="display:none">Publication</span>
+ <span class="it" style="display:none">Pubblicazione</span>
+ <span class="ja" style="display:none">公開</span>
+ <span class="zh-CN" style="display:none">发布</span>
+ <span class="zh-TW" style="display:none">發佈</span>
+ </span>
<ul>
<li><a href="<?cs var:toroot ?>guide/publishing/publishing_overview.html">
<span class="en">Publishing Overview</span>
@@ -715,15 +736,16 @@
</li>
<li>
- <h2><span class="en">Best Practices</span>
- <span class="de" style="display:none">Bewährte Verfahren</span>
- <span class="es" style="display:none">Prácticas recomendadas</span>
- <span class="fr" style="display:none">Meilleures pratiques</span>
- <span class="it" style="display:none">Best practice</span>
- <span class="ja" style="display:none">ベスト プラクティス</span>
- <span class="zh-CN" style="display:none">最佳实践</span>
- <span class="zh-TW" style="display:none">最佳實務</span>
- </h2>
+ <span class="heading">
+ <span class="en">Best Practices</span>
+ <span class="de" style="display:none">Bewährte Verfahren</span>
+ <span class="es" style="display:none">Prácticas recomendadas</span>
+ <span class="fr" style="display:none">Meilleures pratiques</span>
+ <span class="it" style="display:none">Best practice</span>
+ <span class="ja" style="display:none">ベスト プラクティス</span>
+ <span class="zh-CN" style="display:none">最佳实践</span>
+ <span class="zh-TW" style="display:none">最佳實務</span>
+ </span>
<ul>
<li><a href="<?cs var:toroot ?>guide/practices/compatibility.html">
<span class="en">Compatibility</span>
@@ -819,8 +841,9 @@
</li>
<li>
- <h2><span class="en">Web Applications</span>
- </h2>
+ <span class="heading">
+ <span class="en">Web Applications</span>
+ </span>
<ul>
<li><a href="<?cs var:toroot ?>guide/webapps/index.html">
<span class="en">Web Apps Overview</span>
@@ -841,15 +864,16 @@
</li>
<li>
- <h2><span class="en">Appendix</span>
- <span class="de" style="display:none">Anhang</span>
- <span class="es" style="display:none">Apéndice</span>
- <span class="fr" style="display:none">Annexes</span>
- <span class="it" style="display:none">Appendice</span>
- <span class="ja" style="display:none">付録</span>
- <span class="zh-CN" style="display:none">附录</span>
- <span class="zh-TW" style="display:none">附錄</span>
- </h2>
+ <span class="heading">
+ <span class="en">Appendix</span>
+ <span class="de" style="display:none">Anhang</span>
+ <span class="es" style="display:none">Apéndice</span>
+ <span class="fr" style="display:none">Annexes</span>
+ <span class="it" style="display:none">Appendice</span>
+ <span class="ja" style="display:none">付録</span>
+ <span class="zh-CN" style="display:none">附录</span>
+ <span class="zh-TW" style="display:none">附錄</span>
+ </span>
<ul>
<li><a href="<?cs var:toroot ?>guide/appendix/api-levels.html">
<span class="en">Android API Levels</span>
diff --git a/docs/html/guide/practices/ui_guidelines/icon_design.jd b/docs/html/guide/practices/ui_guidelines/icon_design.jd
index 96aecf5..1c66185 100644
--- a/docs/html/guide/practices/ui_guidelines/icon_design.jd
+++ b/docs/html/guide/practices/ui_guidelines/icon_design.jd
@@ -42,8 +42,6 @@
Templates Pack, v2.3 »</a></li>
<li><a href="{@docRoot}shareables/icon_templates-v2.0.zip">Android Icon
Templates Pack, v2.0 »</a></li>
-<li><a href="{@docRoot}shareables/icon_templates-v1.0.zip">Android Icon
-Templates Pack, v1.0 »</a></li>
</ol>
<h2>See also</h2>
diff --git a/docs/html/guide/publishing/preparing.jd b/docs/html/guide/publishing/preparing.jd
index 4d3bffa..83aa5ee 100644
--- a/docs/html/guide/publishing/preparing.jd
+++ b/docs/html/guide/publishing/preparing.jd
@@ -117,6 +117,9 @@
certificate requirements, see <a href="{@docRoot}guide/publishing/app-signing.html#cert">Obtain a
suitable private key</a>.</p>
+<p class="caution"><strong>Important:</strong> Your application must be signed with a cryptographic
+key whose validity period ends after 22 October 2033.</p>
+
<p>You may also have to obtain other release keys if your application accesses a service or uses a
third-party library that requires you to use a key that is based on your private key. For example,
if your application uses the <a
diff --git a/docs/html/guide/publishing/publishing.jd b/docs/html/guide/publishing/publishing.jd
index fa677e6..49b34d8 100644
--- a/docs/html/guide/publishing/publishing.jd
+++ b/docs/html/guide/publishing/publishing.jd
@@ -7,9 +7,9 @@
<h2>Quickview</h2>
<ul>
-<li>You can publish your application using a hosted service such as Android Market or through a web server.</li>
-<li>Before you publish, make sure you have prepared your application properly.</li>
-<li>Android Market makes it easy for users of Android-powered devices to see and download your application.</li>
+<li>Learn how to publish and update apps on Android Market.</li>
+<li>Find out how to create links to apps that are published on Android Market.</li>
+<li>Learn about Android Market features.</li>
</ul>
@@ -17,97 +17,201 @@
<ol>
<li><a href="#overview">About Android Market</a>
+<li><A href="#marketpublish">Publishing Apps on Android Market</a></li>
<li><a href="#marketupgrade">Publishing Updates on Android Market</a></li>
<li><a href="#marketLicensing">Using Android Market Licensing Service</a></li>
+<li><a href="#marketinappbilling">Using Android Market In-app Billing</a></li>
<li><a href="#marketintent">Linking to Your Apps on Android Market</a>
<ol>
<li><a href="#OpeningDetails">Opening an app's details page</a></li>
<li><a href="#PerformingSearch">Performing a search</a></li>
<li><a href="#BuildaButton">Build an Android Market button</a></li>
<li><a href="#UriSummary">Summary of URI formats</a></li>
- </ol>
+ </ol>
</li>
</ol>
<h2>See also</h2>
<ol>
-<li><a href="{@docRoot}guide/publishing/licensing.html">Application Licensing</a></li>
-<li><a href="{@docRoot}guide/publishing/preparing.html">Preparing to Publish</a></li>
+<li><a href="{@docRoot}guide/publishing/publishing_overview.html">Publishing Overview</a></li>
+<li><a href="{@docRoot}guide/publishing/preparing.html">Preparing for Release</a></li>
</ol>
<div id="qv-extra">
<img id="rule" src="{@docRoot}assets/images/grad-rule-qv.png">
<div id="qv-sub-rule">
<img src="{@docRoot}assets/images/icon_market.jpg" style="float:left;margin:0;padding:0 5px;">
- <h2 style="color:#669999;">Interested in publishing your app on Android Market?</h2>
- <p><a href="http://market.android.com/publish">Go to Android Market</a> to
-create a developer account and upload your application. For more information about the
-required assets, listing details, and options, see <a
-href="http://market.android.com/support/bin/answer.py?answer=113469">Uploading
-applications</a>.</p>
+ <h2 style="color:#669999;">Already know about Android Market and want to get started?</h2>
+ <p>Go to <a href="http://market.android.com/publish">Android Market</a>, create a developer
+account, and upload your application. For more information about required assets, listing details,
+and publishing options, see <a
+href="http://market.android.com/support/bin/answer.py?answer=113469">Upload
+Applications</a>.</p>
</div>
</div>
</div>
</div>
-<p>If you've followed the steps outlined in <a
-href="{@docRoot}guide/publishing/preparing.html">Preparing to Publish</a>, the result of the process
-is a compiled {@code .apk} file that is signed with your private release key. Your application is
-now ready to be published publicly so users can install it.</p>
+<p>One of the most effective ways to get your application into users' hands is to
+publish it on an application marketplace like Android Market. Publishing on Android Market is a
+straightforward process that you can do in just a few simple steps—register, configure,
+upload, and publish. Registration takes only a few minutes and needs to be done only once.
+The configuration and publishing steps can all be done through the Android Market Developer Console
+after you register as an Android Market developer.</p>
-<p>You can publish your application and allow users to install it any way you choose, including
-from your own web server. This document provides information about publishing your Android
-application with Android Market.</p>
+<p>To start publishing on Android Market, first read this topic and then go to the <a
+href="https://market.android.com/publish/signup">Android Market publisher site</a> and register as
+an Android Market developer.</p>
<h2 id="overview">About Android Market</h2>
-<p>Android Market is a service that makes it easy for users to find and download Android
-applications to their Android-powered devices, either from the Android Market application on their
-device or from the Android Market web site (<a
-href="http://market.android.com">market.android.com</a>). As a developer, you can use Android Market
-to distribute your applications to users on all types of Android-powered devices, all around the
-world.</p>
+<p>Android Market is a robust publishing platform that helps you publicize, sell, and distribute
+your Android applications to users around the world. When you release your applications through
+Android Market you have access to a suite of developer tools that let you analyze your sales,
+identify market trends, and control who your applications are being distributed to. You also have
+access to several revenue-enhancing features, such as <a
+href="{@docRoot}guide/market/billing/index.html">in-app billing</a> and
+<a href="{@docRoot}guide/publishing/licensing.html">application licensing</a>.</p>
-<p>To publish your application on Android Market, you first need to register
-with the service using a Google account and agree to the terms of service.
-Once you are registered, you can upload your application to the service whenever
-you want, update it as many times as you want, and then publish it when you are ready.
-Once published, users can see your application, download it, and rate it. </p>
+<p>Before you can publish applications on Android Market, you need to <a
+href="http://market.android.com/publish">register</a> as an Android Market developer. During the
+registration process you will need to create a developer profile, pay a registration fee, and agree
+to the <a href="http://www.android.com/us/developer-distribution-agreement.html">Android Market
+Developer Distribution Agreement</a>. After you register you can access the Android Market Developer
+Console, where you can upload applications, configure publishing options, and monitor publishing
+data. If you want to sell your applications or use the in-app billing feature, you will also need
+to set up a Google Checkout merchant account. For more information about the registration process,
+see <a href="https://support.google.com/androidmarket/developer/bin/answer.py?hl=en&answer=113468">
+Developer Registration</a>.</p>
-<p>To register as an Android Market developer and get started with publishing,
-visit the Android Market publisher site: </p>
+<h2 id="marketpublish">Publishing Apps on Android Market</h2>
-<p style="margin-left:3em;"><a
-href="http://market.android.com/publish">http://market.android.com/publish</a>
+<p>Publishing your application on Android Market is a simple process that involves three basic
+tasks (see figure 1):</p>
+
+<ul>
+ <li>Creating various graphical assets that
+accompany your app on Android Market.</li>
+ <li>Using the Android Market <a
+href="http://market.android.com/publish">Developer Console</a> to configure publishing options,
+specify listing details, and upload your app and graphical assets to Android Market.</li>
+ <li>Reviewing your publishing settings and changing the release
+status of your app from Unpublished to Published.</li>
+</ul>
+
+<img src="{@docRoot}images/publishing/publishing_android_market.png"
+ alt="Shows the three steps that are required to publish on Android Market"
+ height="168"
+ id="figure1" />
+<p class="img-caption">
+ <strong>Figure 1.</strong> To publish apps on Android Market you must first <a
+href="{@docRoot}guide/publishing/preparing.html">prepare your app for release</a> and then perform
+three simple tasks.
</p>
-<p>If you plan to publish your application on Android Market, you must make sure
-that it meets the requirements listed below, which are enforced by the Market
-server when you upload the application.</p>
+<p class="caution"><strong>Important:</strong> You must <a
+href="{@docRoot}guide/publishing/preparing.html">prepare your application for release</a> before you
+can publish it on Android Market. When you prepare your application for release you configure it for
+release and build it in release mode. Building in release mode signs your application's {@code .apk}
+file with your private release key. You cannot publish an application on Android Market unless it is
+signed with your own private release key.</p>
-<div class="special">
-<p>Requirements enforced by the Android Market server:</p>
-<ol>
-<li>Your application must be signed with a cryptographic private key whose
-validity period ends after <span style="color:red">22 October 2033</span>. </li>
-<li>Your application must define both an <code>android:versionCode</code> and an
-<code>android:versionName</code> attribute in the
+<h3>Preparing promotional materials</h3>
+
+<p>To fully leverage the marketing and publicity capabilities of Android Market, you need to create
+several graphical assets that accompany your app on Android Market, such as screenshots, videos,
+promotional graphics, and promotional text. At a minimum you must provide two screenshots of your
+application and a high resolution application icon. The screenshots are displayed on the details
+page for your application in Android Market, and the high resolution application icon is displayed
+in various locations throughout Android Market. The high resolution icon does not replace the
+launcher icon for your application, rather, it serves as a supplemental icon and should look
+the same as your launcher icon. Promotional video,
+graphics, and text are optional, although we strongly recommended that you prepare these for your
+app. For more information about the graphic assets that accompany your application, see <a
+href="http://support.google.com/androidmarket/developer/bin/answer.py?hl=en&answer=1078870">Graphic
+Assets for your Application</a>.</p>
+
+<h3>Configuring options and uploading assets</h3>
+
+<p>Android Market lets you target your application to a worldwide pool of users and devices. To
+reach these users you can use the Android Market Developer Console to configure various publishing
+options and listing details for your app. For example, you can choose the <a
+href="http://support.google.com/androidmarket/developer/bin/answer.py?hl=en&answer=138294&topic=
+2365624&ctx=topic">countries</a> you want to reach, the listing languages you want to use, and the
<a
-href="{@docRoot}guide/topics/manifest/manifest-element.html"><code><manifest></code></a>
-element of its manifest file. The server uses the <code>android:versionCode</code> as
-the basis for identifying the application internally and handling updates, and
-it displays the <code>android:versionName</code> to users as the application's
-version.</li>
-<li>Your application must define both an <code>android:icon</code> and an
-<code>android:label</code> attribute in the <a
-href="{@docRoot}guide/topics/manifest/application-element.html"><code><application></code></a>
-element of its manifest file.</li>
-</ol>
-</div>
+href="http://support.google.com/androidmarket/developer/bin/answer.py?hl=en&answer=138412&topic=
+15867&ctx=topic">price</a> you want to charge in each country. You can also configure listing
+details such as the application type, <a
+href="https://support.google.com/androidmarket/developer/bin/answer.py?hl=en&answer=113475&topic=
+2365760&ctx=topic">category</a>, and <a
+href="http://support.google.com/androidmarket/developer/bin/answer.py?hl=en&answer=188189&topic=
+2364761&ctx=topic">content rating</a>. In addition, if you want to sell items within your app using
+the in-app billing feature, you can use the Developer Console to <a
+href="http://grendel.sea.corp.google.com:48014/guide/market/billing/billing_admin.html#billing-list
+- setup">create a product list</a> and control which items are available for purchase in your
+app.</p>
+<p>When you are finished setting publishing options and listing details, you can upload your assets
+and your application to Android Market. You can also upload your application as a draft
+(unpublished) application, which lets you do final testing before you publish it for final
+release.</p>
+
+<p>To learn more about Android Market publishing settings, see the following resources:</p>
+
+<ul>
+ <li><a
+href="http://support.google.com/androidmarket/developer/bin/answer.py?hl=en&answer=113469&topic=
+236562&ctx=topic">Upload Applications</a>—provides a summary of the publishing settings
+you can configure for an app.</li>
+ <li><a
+href="http://support.google.com/androidmarket/developer/bin/topic.py?hl=en&topic=15867">Selling
+Your Apps</a>—provides guidance about pricing, supported currencies, tax rates, and many
+other topics related to selling apps.</li>
+ <li><a
+href="https://support.google.com/androidmarket/developer/bin/answer.py?hl=en&answer=1169947&topic=
+15867&ctx=topic">Selling Apps in Multiple Currencies</a>—provides a description of how
+pricing, payouts, and exchange rates work.</li>
+</ul>
+
+<h3>Publishing your application</h3>
+
+<p>When you are satisfied that your publishing settings are correctly configured and your uploaded
+application is ready to be released to the public, you can simply click <strong>Publish</strong> in
+the Developer Console to make your app available for download
+around the world. Keep in mind, it can take several hours for your app to appear on Android
+Market after you click <strong>Publish</strong> in the Developer Console.</p>
+
+<h3>Controlling Distribution to Devices</h3>
+
+<p>If your application targets different device configurations, you can control which Android-powered
+devices have access to your application on Android Market by
+using Android Market filters. Filtering compares device configurations that you declare in your
+app's manifest file to the configuration defined by a device. For example, if you declare the camera
+filter in your manifest, only those devices that have a camera will see your app on Android
+Market. Filters must be configured in your application's manifest file when you are <a
+href="{@docRoot}guide/publishing/preparing.html">preparing your app for release</a> (that is, before
+you upload your app to Android Market). For more information, see <a
+href="{@docRoot}guide/appendix/market-filters.html">Market Filters</a>.</p>
+
+<p>You can also use the multiple APK feature to distribute different {@code .apk} files under the same
+application listing and the same package name; however, you should use this option only as a last
+resort. Android applications usually run on most compatible devices with a single APK, by supplying
+alternative resources for different configurations (for example, different layouts for different screen
+sizes) and the Android system selects the appropriate resources for the device at runtime. In a
+few cases, however, a single APK is unable to support all device configurations, because alternative
+resources make the APK file too big (greater than 50MB) or other technical challenges prevent a
+single APK from working on all devices. Although we encourage you to develop and publish a single
+APK that supports as many device configurations as possible, doing so is sometimes
+not possible. To help you publish your application for as many devices as possible, Android Market
+allows you to publish multiple APKs under the same application listing. Android Market then supplies
+each APK to the appropriate devices based on configuration support you've declared in the manifest
+file of each APK. To use this feature, you need to build your separate {@code .apk} files when you are <a
+href="{@docRoot}guide/publishing/preparing.html">preparing your app for release</a> (that is, before
+you upload your app to Android Market). For more information, see <a
+href="{@docRoot}guide/market/publishing/multiple-apks.html">Multiple APK Support</a>.</p>
<h2 id="marketupgrade">Publishing Updates on Android Market</h2>
@@ -128,6 +232,9 @@
consider it a new application, publish it as such, and will not offer it to existing users as an
update.</p>
+<p>If you plan to publish your application on Android Market, you must make sure
+ that it meets the requirements listed below, which are enforced by the Market
+ server when you upload the application.</p>
<h2 id="marketLicensing">Using Android Market Licensing Service</h2>
@@ -136,7 +243,7 @@
Android Market Licensing, your applications can query Android Market at runtime
to obtain the licensing status for the current user, then allow or disallow
further use of the application as appropriate. Using the service, you can apply a flexible
-licensing policy on an application-by-application basis—each
+licensing policy on an application-by-application basis—each
application can enforce its licensing status in the way most appropriate
for it. </p>
@@ -149,7 +256,31 @@
use it in your application, read <a
href="{@docRoot}guide/publishing/licensing.html">Application Licensing</a>.</p>
+<h2 id="marketinappbilling">Using Android Market In-app Billing</h2>
+<p><a href="{@docRoot}guide/market/billing/billing_overview.html">Android Market In-app Billing</a>
+is an Android Market service that lets you sell digital content in your applications. You can use
+the service to sell a wide range of content, including downloadable content such as media files or
+photos, and virtual content such as game levels or potions.</p>
+
+<p>When you use Android Market's in-app billing service to sell an item, Android Market handles all
+billing details so your application never has to directly process any financial transactions.
+Android Market uses the same checkout service that is used for application purchases, so your users
+experience a consistent and familiar purchase flow (see figure 1). Also, the transaction fee for
+in-app purchases is the same as the transaction fee for application purchases (30%).</p>
+
+<p>Any application that you publish through Android Market can implement in-app billing. No special
+account or registration is required other than an Android Market publisher account and a Google
+Checkout Merchant account. Also, because the service uses no dedicated framework APIs, you can add
+in-app billing to any application that uses a minimum API level of 4 or higher.</p>
+
+<p>To help you integrate in-app billing into your application, the Android SDK provides a <a
+href="{@docRoot}guide/market/billing/billing_integrate.html#billing-download">sample application</a>
+that demonstrates a simple implementation of in-app billing. The sample application contains
+examples of billing-related classes you can use to implement in-app billing in your application. It
+also contains examples of the database, user interface, and business logic you might use to
+implement in-app billing. For more information about the in-app billing feature, see the
+<a href="{@docRoot}guide/market/billing/index.html">In-app Billing documentation</a>.</p>
<h2 id="marketintent">Linking to Your Apps on Android Market</h2>
@@ -337,7 +468,7 @@
Guidelines</a>.</p>
<style type="text/css">
-
+
form.button-form {
margin-top:2em;
}
@@ -539,7 +670,7 @@
<tr>
<td>Display the details screen for a specific application</td>
-<td><code>http://market.android.com/details?id=<package_name></code>
+<td><code>http://market.android.com/details?id=<package_name></code>
<td><code>market://details?id=<package_name></code></td>
</tr>
diff --git a/docs/html/guide/publishing/publishing_overview.jd b/docs/html/guide/publishing/publishing_overview.jd
index e30360b..79199c5 100755
--- a/docs/html/guide/publishing/publishing_overview.jd
+++ b/docs/html/guide/publishing/publishing_overview.jd
@@ -134,7 +134,7 @@
and features, coupled with numerous end-user community features, makes Android Market the premier
marketplace for selling and buying Android applications.</p>
-<p>Releasing your application on Android Market is a simple process that involves four basic
+<p>Releasing your application on Android Market is a simple process that involves three basic
steps:</p>
<div class="figure" style="width:275px">
@@ -153,21 +153,16 @@
create promotional materials for your application, such as screenshots, videos, graphics, and
promotional text.</p>
</li>
- <li>Planning publishing options.
+ <li>Configuring options and uploading assets.
<p>Android Market lets you target your application to a worldwide pool of users and devices.
- Using various Android Market tools, you can choose the countries you want to reach, the
- price you want to charge in each country, and the devices you want to target. You can also
- use Android Market's filtering settings to target specific device features and capabilities.</p>
- </li>
- <li>Configuring publishing options and uploading assets.
- <p>After you create your promotional materials and determine which publishing options are
- suitable for your application, you can use the Android Market developer console to configure
- those options and upload the promotional materials. You can also use the developer console to
- upload your application as a draft (unpublished) application, which lets you do final
- testing before you publish it for final release.</p>
+ By configuring various Android Market settings, you can choose the countries you want to
+ reach, the listing languages you want to use, and the price you want to charge in each
+ country. You can also configure listing details such as the application type, category, and
+ content rating. When you are done configuring options you can upload your promotional materials
+ and your application as a draft (unpublished) application.</p>
</li>
<li>Publishing the release version of your application.
- <p>When you are satisfied that your publishing settings are correctly configured and your
+ <p>If you are satisfied that your publishing settings are correctly configured and your
uploaded application is ready to be released to the public, you can simply click
<strong>Publish</strong > in the developer console and within minutes your application will be
live and available for download around the world.</p>
@@ -233,4 +228,4 @@
<p>Releasing applications through email is convenient if you are sending your application to
only a few trusted users, but it provides few protections from piracy and unauthorized
distribution; that is, anyone you send your application to can simply forward it to someone else.
-else.
\ No newline at end of file
+else.
diff --git a/docs/html/guide/topics/graphics/hardware-accel.jd b/docs/html/guide/topics/graphics/hardware-accel.jd
index e3ff215..39ccbf4 100644
--- a/docs/html/guide/topics/graphics/hardware-accel.jd
+++ b/docs/html/guide/topics/graphics/hardware-accel.jd
@@ -300,6 +300,16 @@
<li>{@link android.graphics.Paint#setRasterizer setRasterizer()}</li>
</ul>
</li>
+
+ <li>
+ <strong>Xfermodes</strong>
+
+ <ul>
+ <li>{@link android.graphics.AvoidXfermode AvoidXfermode}</li>
+
+ <li>{@link android.graphics.PixelXorXfermode PixelXorXfermode}</li>
+ </ul>
+ </li>
</ul>
<p>In addition, some operations behave differently with hardware acceleration enabled:</p>
@@ -315,9 +325,6 @@
<li>{@link android.graphics.Canvas#drawBitmapMesh drawBitmapMesh()}: colors array is
ignored</li>
-
- <li>{@link android.graphics.Canvas#setDrawFilter setDrawFilter()}: can be set, but is
- ignored</li>
</ul>
</li>
@@ -336,6 +343,24 @@
</li>
<li>
+ <strong>PorterDuffXfermode</strong>
+
+ <ul>
+ <li>{@link android.graphics.PorterDuff.Mode#DARKEN PorterDuff.Mode.DARKEN} will
+ be equivalent to {@link android.graphics.PorterDuff.Mode#SRC_OVER} when blending
+ against the framebuffer.</li>
+
+ <li>{@link android.graphics.PorterDuff.Mode#LIGHTEN PorterDuff.Mode.LIGHTEN} will
+ be equivalent to {@link android.graphics.PorterDuff.Mode#SRC_OVER} when blending
+ against the framebuffer.</li>
+
+ <li>{@link android.graphics.PorterDuff.Mode#OVERLAY PorterDuff.Mode.OVERLAY} will
+ be equivalent to {@link android.graphics.PorterDuff.Mode#SRC_OVER} when blending
+ against the framebuffer.</li>
+ </ul>
+ </li>
+
+ <li>
<strong>ComposeShader</strong>
<ul>
diff --git a/docs/html/guide/topics/providers/content-provider-basics.jd b/docs/html/guide/topics/providers/content-provider-basics.jd
new file mode 100644
index 0000000..40b5c3f
--- /dev/null
+++ b/docs/html/guide/topics/providers/content-provider-basics.jd
@@ -0,0 +1,1215 @@
+page.title=Content Provider Basics
+@jd:body
+<div id="qv-wrapper">
+<div id="qv">
+
+
+ <!-- In this document -->
+<h2>In this document</h2>
+<ol>
+ <li>
+ <a href="#Basics">Overview</a>
+ <ol>
+ <li>
+ <a href="#ClientProvider">Accessing a provider</a>
+ </li>
+ <li>
+ <a href="#ContentURIs">Content URIs</a>
+ </li>
+ </ol>
+ </li>
+ <li>
+ <a href="#SimpleQuery">Retrieving Data from the Provider</a>
+ <ol>
+ <li>
+ <a href="#RequestPermissions">Requesting read access permission</a>
+ </li>
+ <li>
+ <a href="#Query">Constructing the query</a>
+ </li>
+ <li>
+ <a href="#DisplayResults">Displaying query results</a>
+ </li>
+ <li>
+ <a href="#GettingResults">Getting data from query results</a>
+ </li>
+ </ol>
+ </li>
+ <li>
+ <a href="#Permissions">Content Provider Permissions</a>
+ </li>
+ <li>
+ <a href="#Modifications">Inserting, Updating, and Deleting Data</a>
+ <ol>
+ <li>
+ <a href="#Inserting">Inserting data</a>
+ </li>
+ <li>
+ <a href="#Updating">Updating data</a>
+ </li>
+ <li>
+ <a href="#Deleting">Deleting data</a>
+ </li>
+ </ol>
+ </li>
+ <li>
+ <a href="#DataTypes">Provider Data Types</a>
+ </li>
+ <li>
+ <a href="#AltForms">Alternative Forms of Provider Access</a>
+ <ol>
+ <li>
+ <a href="#Batch">Batch access</a>
+ </li>
+ <li>
+ <a href="#Intents">Data access via intents</a>
+ </li>
+ </ol>
+ </li>
+ <li>
+ <a href="#ContractClasses">Contract Classes</a>
+ </li>
+ <li>
+ <a href="#MIMETypeReference">MIME Type Reference</a>
+ </li>
+</ol>
+
+ <!-- Key Classes -->
+<h2>Key classes</h2>
+ <ol>
+ <li>
+ {@link android.content.ContentProvider}
+ </li>
+ <li>
+ {@link android.content.ContentResolver}
+ </li>
+ <li>
+ {@link android.database.Cursor}
+ </li>
+ <li>
+ {@link android.net.Uri}
+ </li>
+ </ol>
+
+ <!-- Related Samples -->
+<h2>Related Samples</h2>
+ <ol>
+ <li>
+ <a
+ href="{@docRoot}resources/samples/ApiDemos/src/com/example/android/apis/view/List2.html">
+ Cursor (People)</a>
+ </li>
+ <li>
+ <a
+ href="{@docRoot}resources/samples/ApiDemos/src/com/example/android/apis/view/List7.html">
+ Cursor (Phones)</a>
+ </li>
+ </ol>
+
+ <!-- See also -->
+<h2>See also</h2>
+ <ol>
+ <li>
+ <a href="{@docRoot}guide/topics/providers/content-provider-creating.html">
+ Creating a Content Provider</a>
+ </li>
+ <li>
+ <a href="{@docRoot}guide/topics/providers/calendar-provider.html">
+ Calendar Provider</a>
+ </li>
+ </ol>
+</div>
+</div>
+
+ <!-- Intro paragraphs -->
+<p>
+ A content provider manages access to a central repository of data. The provider and
+ is part of an Android application, which often provides its own UI for working with
+ the data. However, content providers are primarily intended to be used by other
+ applications, which access the provider using a provider client object. Together, providers
+ and provider clients offer a consistent, standard interface to data that also handles
+ inter-process communication and secure data access.
+</p>
+<p>
+ This topic describes the basics of the following:
+</p>
+ <ul>
+ <li>How content providers work.</li>
+ <li>The API you use retrieve data from a content provider.</li>
+ <li>The API you use to insert, update, or delete data in a content provider.</li>
+ <li>Other API features that facilitate working with providers.</li>
+ </ul>
+
+ <!-- Basics -->
+<h2 id="Basics">Overview</h2>
+<p>
+ A content provider presents data to external applications as one or more tables that are
+ similar to the tables found in a relational database. A row represents an instance of some type
+ of data the provider collects, and each row in the column represents an individual piece of
+ data collected for an instance.
+</p>
+<p>
+ For example, one of the built-in providers in the Android platform is the user dictionary, which
+ stores the spellings of non-standard words that the user wants to keep. Table 1 illustrates what
+ the data might look like in this provider's table:
+</p>
+<p class="table-caption">
+ <strong>Table 1:</strong> Sample user dictionary table.
+</p>
+<table id="table1" style="width: 50%;">
+ <tr>
+ <th style="width:20%" align="center" scope="col">word</th>
+ <th style="width:20%" align="center" scope="col">app id</th>
+ <th style="width:20%" align="center" scope="col">frequency</th>
+ <th style="width:20%" align="center" scope="col">locale</th>
+ <th style="width:20%" align="center" scope="col">_ID</th>
+ </tr>
+ <tr>
+ <td align="center" scope="row">mapreduce</td>
+ <td align="center">user1</td>
+ <td align="center">100</td>
+ <td align="center">en_US</td>
+ <td align="center">1</td>
+ </tr>
+ <tr>
+ <td align="center" scope="row">precompiler</td>
+ <td align="center">user14</td>
+ <td align="center">200</td>
+ <td align="center">fr_FR</td>
+ <td align="center">2</td>
+ </tr>
+ <tr>
+ <td align="center" scope="row">applet</td>
+ <td align="center">user2</td>
+ <td align="center">225</td>
+ <td align="center">fr_CA</td>
+ <td align="center">3</td>
+ </tr>
+ <tr>
+ <td align="center" scope="row">const</td>
+ <td align="center">user1</td>
+ <td align="center">255</td>
+ <td align="center">pt_BR</td>
+ <td align="center">4</td>
+ </tr>
+ <tr>
+ <td align="center" scope="row">int</td>
+ <td align="center">user5</td>
+ <td align="center">100</td>
+ <td align="center">en_UK</td>
+ <td align="center">5</td>
+ </tr>
+</table>
+<p>
+ In table 1, each row represents an instance of a word that might not be
+ found in a standard dictionary. Each column represents some data for that word, such as the
+ locale in which it was first encountered. The column headers are column names that are stored in
+ the provider. To refer to a row's locale, you refer to its <code>locale</code> column. For
+ this provider, the <code>_ID</code> column serves as a "primary key" column that
+ the provider automatically maintains.
+</p>
+<p class="note">
+ <strong>Note:</strong> A provider isn't required to have a primary key, and it isn't required
+ to use <code>_ID</code> as the column name of a primary key if one is present. However,
+ if you want to bind data from a provider to a {@link android.widget.ListView}, one of the
+ column names has to be <code>_ID</code>. This requirement is explained in more detail in the
+ section <a href="#DisplayResults">Displaying query results</a>.
+</p>
+<h3 id="ClientProvider">Accessing a provider</h3>
+<p>
+ An application accesses the data from a content provider with
+ a {@link android.content.ContentResolver} client object. This object has methods that call
+ identically-named methods in the provider object, an instance of one of the concrete
+ subclasses of {@link android.content.ContentProvider}. The
+ {@link android.content.ContentResolver} methods provide the basic
+ "CRUD" (create, retrieve, update, and delete) functions of persistent storage.
+</p>
+<p>
+ The {@link android.content.ContentResolver} object in the client application's
+ process and the {@link android.content.ContentProvider} object in the application that owns
+ the provider automatically handle inter-process communication.
+ {@link android.content.ContentProvider} also acts as an abstraction layer between its
+ repository of data and the external appearance of data as tables.
+</p>
+<p class="note">
+ <strong>Note:</strong> To access a provider, your application usually has to request specific
+ permissions in its manifest file. This is described in more detail in the section
+ <a href="#Permissions">Content Provider Permissions</a>
+</p>
+<p>
+ For example, to get a list of the words and their locales from the User Dictionary Provider,
+ you call {@link android.content.ContentResolver#query(Uri, String[], String, String[], String)
+ ContentResolver.query()}.
+ The {@link android.content.ContentResolver#query(Uri, String[], String, String[], String)
+ query()} method calls the
+ {@link android.content.ContentProvider#query(Uri, String[], String, String[], String)
+ ContentProvider.query()} method defined by the User Dictionary Provider. The following lines
+ of code show a
+ {@link android.content.ContentResolver#query(Uri, String[], String, String[], String)
+ ContentResolver.query()} call:
+<p>
+<pre>
+// Queries the user dictionary and returns results
+mCursor = getContentResolver().query(
+ UserDictionary.Words.CONTENT_URI, // The content URI of the words table
+ mProjection, // The columns to return for each row
+ mSelectionClause // Selection criteria
+ mSelectionArgs, // Selection criteria
+ mSortOrder); // The sort order for the returned rows
+</pre>
+<p>
+ Table 2 shows how the arguments to
+ {@link android.content.ContentResolver#query(Uri, String[], String, String[], String)
+ query(Uri,projection,selection,selectionArgs,sortOrder)} match an SQL SELECT statement:
+</p>
+<p class="table-caption">
+ <strong>Table 2:</strong> Query() compared to SQL query.
+</p>
+<table id="table2" style="width: 75%;">
+ <tr>
+ <th style="width:25%" align="center" scope="col">query() argument</th>
+ <th style="width:25%" align="center" scope="col">SELECT keyword/parameter</th>
+ <th style="width:50%" align="center" scope="col">Notes</th>
+ </tr>
+ <tr>
+ <td align="center"><code>Uri</code></td>
+ <td align="center"><code>FROM <em>table_name</em></code></td>
+ <td><code>Uri</code> maps to the table in the provider named <em>table_name</em>.</td>
+ </tr>
+ <tr>
+ <td align="center"><code>projection</code></td>
+ <td align="center"><code><em>col,col,col,...</em></code></td>
+ <td>
+ <code>projection</code> is an array of columns that should be included for each row
+ retrieved.
+ </td>
+ </tr>
+ <tr>
+ <td align="center"><code>selection</code></td>
+ <td align="center"><code>WHERE <em>col</em> = <em>value</em></code></td>
+ <td><code>selection</code> specifies the criteria for selecting rows.</td>
+ </tr>
+ <tr>
+ <td align="center"><code>selectionArgs</code></td>
+ <td align="center">
+ (No exact equivalent. Selection arguments replace <code>?</code> placeholders in the
+ selection clause.)
+ </td>
+ </tr>
+ <tr>
+ <td align="center"><code>sortOrder</code></td>
+ <td align="center"><code>ORDER BY <em>col,col,...</em></code></td>
+ <td>
+ <code>sortOrder</code> specifies the order in which rows appear in the returned
+ {@link android.database.Cursor}.
+ </td>
+ </tr>
+</table>
+<h3 id="ContentURIs">Content URIs</h3>
+<p>
+ A <strong>content URI</strong> is a URI that identifies data in a provider. Content URIs
+ include the symbolic name of the entire provider (its <strong>authority</strong>) and a
+ name that points to a table (a <strong>path</strong>). When you call
+ a client method to access a table in a provider, the content URI for the table is one of
+ the arguments.
+</p>
+<p>
+ In the preceding lines of code, the constant
+ {@link android.provider.UserDictionary.Words#CONTENT_URI} contains the content URI of
+ the user dictionary's "words" table. The {@link android.content.ContentResolver}
+ object parses out the URI's authority, and uses it to "resolve" the provider by
+ comparing the authority to a system table of known providers. The
+ {@link android.content.ContentResolver} can then dispatch the query arguments to the correct
+ provider.
+</p>
+<p>
+ The {@link android.content.ContentProvider} uses the path part of the content URI to choose the
+ table to access. A provider usually has a <strong>path</strong> for each table it exposes.
+</p>
+<p>
+ In the previous lines of code, the full URI for the "words" table is:
+</p>
+<pre>
+content://user_dictionary/words
+</pre>
+<p>
+ where the <code>user_dictionary</code> string is the provider's authority, and
+ <code>words</code> string is the table's path. The string
+ <code>content://</code> (the <strong>scheme</strong>) is always present,
+ and identifies this as a content URI.
+</p>
+<p>
+ Many providers allow you to access a single row in a table by appending an ID value
+ to the end of the URI. For example, to retrieve a row whose <code>_ID</code> is
+ <code>4</code> from user dictionary, you can use this content URI:
+</p>
+<pre>
+Uri singleUri = ContentUri.withAppendedId(UserDictionary.Words.CONTENT_URI,4);
+</pre>
+<p>
+ You often use id values when you've retrieved a set of rows and then want to update or delete
+ one of them.
+</p>
+<p class="note">
+ <strong>Note:</strong> The {@link android.net.Uri} and {@link android.net.Uri.Builder} classes
+ contain convenience methods for constructing well-formed Uri objects from strings. The
+ {@link android.content.ContentUris} contains convenience methods for appending id values to
+ a URI. The previous snippet uses {@link android.content.ContentUris#withAppendedId(Uri, long)
+ withAppendedId()} to append an id to the UserDictionary content URI.
+</p>
+
+
+ <!-- Retrieving Data from the Provider -->
+<h2 id="SimpleQuery">Retrieving Data from the Provider</h2>
+<p>
+ This section describes how to retrieve data from a provider, using the User Dictionary Provider
+ as an example.
+</p>
+<p class="note">
+ For the sake of clarity, the code snippets in this section call
+ {@link android.content.ContentResolver#query(Uri, String[], String, String[], String)
+ ContentResolver.query()} on the "UI thread"". In actual code, however, you should
+ do queries asynchronously on a separate thread. One way to do this is to use the
+ {@link android.content.CursorLoader} class, which is described
+ in more detail in the <a href="{@docRoot}guide/topics/fundamentals/loaders.html">
+ Loaders</a> guide. Also, the lines of code are snippets only; they don't show a complete
+ application.
+</p>
+<p>
+ To retrieve data from a provider, follow these basic steps:
+</p>
+<ol>
+ <li>
+ Request the read access permission for the provider.
+ </li>
+ <li>
+ Define the code that sends a query to the provider.
+ </li>
+</ol>
+<h3 id="RequestPermissions">Requesting read access permission</h3>
+<p>
+ To retrieve data from a provider, your application needs "read access permission" for the
+ provider. You can't request this permission at run-time; instead, you have to specify that
+ you need this permission in your manifest, using the
+ <code><a href="{@docRoot}guide/topics/manifest/uses-permission-element.html">
+ <uses-permission></a></code> element and the exact permission name defined by the
+ provider. When you specify this element in your manifest, you are in effect "requesting" this
+ permission for your application. When users install your application, they implicitly grant
+ this request.
+</p>
+<p>
+ To find the exact name of the read access permission for the provider you're using, as well
+ as the names for other access permissions used by the provider, look in the provider's
+ documentation.
+</p>
+<p>
+ The role of permissions in accessing providers is described in more detail in the section
+ <a href="#Permissions">Content Provider Permissions</a>.
+</p>
+<p>
+ The User Dictionary Provider defines the permission
+ <code>android.permission.READ_USER_DICTIONARY</code> in its manifest file, so an
+ application that wants to read from the provider must request this permission.
+</p>
+<!-- Constructing the query -->
+<h3 id="Query">Constructing the query</h3>
+<p>
+ The next step in retrieving data a provider is to construct a query. This first snippet
+ defines some variables for accessing the User Dictionary Provider:
+</p>
+<pre class="prettyprint">
+
+// A "projection" defines the columns that will be returned for each row
+String[] mProjection =
+{
+ UserDictionary.Words._ID, // Contract class constant for the _ID column name
+ UserDictionary.Words.WORD, // Contract class constant for the word column name
+ UserDictionary.Words.LOCALE // Contract class constant for the locale column name
+};
+
+// Defines a string to contain the selection clause
+String mSelectionClause = null;
+
+// Initializes an array to contain selection arguments
+String[] mSelectionArgs = {""};
+
+</pre>
+<p>
+ The next snippet shows how to use
+ {@link android.content.ContentResolver#query(Uri, String[], String, String[], String)
+ ContentResolver.query()}, using the User Dictionary Provider as an example.
+ A provider client query is similar to an SQL query, and it contains a set of columns to return,
+ a set of selection criteria, and a sort order.
+</p>
+<p>
+ The set of columns that the query should return is called a <strong>projection</strong>
+ (the variable <code>mProjection</code>).
+</p>
+<p>
+ The expression that specifies the rows to retrieve is split into a selection clause and
+ selection arguments. The selection clause is a combination of logical and Boolean expressions,
+ column names, and values (the variable <code>mSelection</code>). If you specify the replaceable
+ parameter <code>?</code> instead of a value, the query method retrieves the value from the
+ selection arguments array (the variable <code>mSelectionArgs</code>).
+</p>
+<p>
+ In the next snippet, if the user doesn't enter a word, the selection clause is set to
+ <code>null</code>, and the query returns all the words in the provider. If the user enters
+ a word, the selection clause is set to <code>UserDictionary.Words.Word + " = ?"</code> and
+ the first element of selection arguments array is set to the word the user enters.
+</p>
+<pre class="prettyprint">
+/*
+ * This defines a one-element String array to contain the selection argument.
+ */
+String[] mSelectionArgs = {""};
+
+// Gets a word from the UI
+mSearchString = mSearchWord.getText().toString();
+
+// Remember to insert code here to check for invalid or malicious input.
+
+// If the word is the empty string, gets everything
+if (TextUtils.isEmpty(mSearchString)) {
+ // Setting the selection clause to null will return all words
+ mSelectionClause = null;
+ mSelectionArgs[0] = "";
+
+} else {
+ // Constructs a selection clause that matches the word that the user entered.
+ mSelectionClause = " = ?";
+
+ // Moves the user's input string to the selection arguments.
+ mSelectionArgs[0] = mSearchString;
+
+}
+
+// Does a query against the table and returns a Cursor object
+mCursor = getContentResolver().query(
+ UserDictionary.Words.CONTENT_URI, // The content URI of the words table
+ mProjection, // The columns to return for each row
+ mSelectionClause // Either null, or the word the user entered
+ mSelectionArgs, // Either empty, or the string the user entered
+ mSortOrder); // The sort order for the returned rows
+
+// Some providers return null if an error occurs, others throw an exception
+if (null == mCursor) {
+ /*
+ * Insert code here to handle the error. Be sure not to use the cursor! You may want to
+ * call android.util.Log.e() to log this error.
+ *
+ */
+// If the Cursor is empty, the provider found no matches
+} else if (mCursor.getCount() < 1) {
+
+ /*
+ * Insert code here to notify the user that the search was unsuccessful. This isn't necessarily
+ * an error. You may want to offer the user the option to insert a new row, or re-type the
+ * search term.
+ */
+
+} else {
+ // Insert code here to do something with the results
+
+}
+</pre>
+<p>
+ This query is analogous to the SQL statement:
+</p>
+<pre>
+SELECT _ID, word, frequency, locale FROM words WHERE word = <userinput> ORDER BY word ASC;
+</pre>
+<p>
+ In this SQL statement, the actual column names are used instead of contract class constants.
+</p>
+<h4 id="Injection">Protecting against malicious input</h4>
+<p>
+ If the data managed by the content provider is in an SQL database, including external untrusted
+ data into raw SQL statements can lead to SQL injection.
+</p>
+<p>
+ Consider this selection clause:
+</p>
+<pre>
+// Constructs a selection clause by concatenating the user's input to the column name
+String mSelectionClause = "var = " + mUserInput;
+</pre>
+<p>
+ If you do this, you're allowing the user to concatenate malicious SQL onto your SQL statement.
+ For example, the user could enter "nothing; DROP TABLE *;" for <code>mUserInput</code>, which
+ would result in the selection clause <code>var = nothing; DROP TABLE *;</code>. Since the
+ selection clause is treated as an SQL statement, this might cause the provider to erase all of
+ the tables in the underlying SQLite database (unless the provider is set up to catch
+ <a href="http://en.wikipedia.org/wiki/SQL_injection">SQL injection</a> attempts).
+</p>
+<p>
+ To avoid this problem, use a selection clause that uses <code>?</code> as a replaceable
+ parameter and a separate array of selection arguments. When you do this, the user input
+ is bound directly to the query rather than being interpreted as part of an SQL statement.
+ Because it's not treated as SQL, the user input can't inject malicious SQL. Instead of using
+ concatenation to include the user input, use this selection clause:
+</p>
+<pre>
+// Constructs a selection clause with a replaceable parameter
+String mSelectionClause = "var = ?";
+</pre>
+<p>
+ Set up the array of selection arguments like this:
+</p>
+<pre>
+// Defines an array to contain the selection arguments
+String[] selectionArgs = {""};
+</pre>
+<p>
+ Put a value in the selection arguments array like this:
+</p>
+<pre>
+// Sets the selection argument to the user's input
+selectionArgs[0] = mUserInput;
+</pre>
+<p>
+ A selection clause that uses <code>?</code> as a replaceable parameter and an array of
+ selection arguments array are preferred way to specify a selection, even the provider isn't
+ based on an SQL database.
+</p>
+<!-- Displaying the results -->
+<h3 id="DisplayResults">Displaying query results</h3>
+<p>
+ The {@link android.content.ContentResolver#query(Uri, String[], String, String[], String)
+ ContentResolver.query()} client method always returns a {@link android.database.Cursor}
+ containing the columns specified by the query's projection for the rows that match the query's
+ selection criteria. A {@link android.database.Cursor} object provides random read access to the
+ rows and columns it contains. Using {@link android.database.Cursor} methods,
+ you can iterate over the rows in the results, determine the data type of each column, get the
+ data out of a column, and examine other properties of the results. Some
+ {@link android.database.Cursor} implementations automatically update the object when the
+ provider's data changes, or trigger methods in an observer object when the
+ {@link android.database.Cursor} changes, or both.
+</p>
+<p class="note">
+ <strong>Note:</strong> A provider may restrict access to columns based on the nature of the
+ object making the query. For example, the Contacts Provider restricts access for some columns to
+ sync adapters, so it won't return them to an activity or service.
+</p>
+<p>
+ If no rows match the selection criteria, the provider
+ returns a {@link android.database.Cursor} object for which
+ {@link android.database.Cursor#getCount() Cursor.getCount()} is 0 (an empty cursor).
+</p>
+<p>
+ If an internal error occurs, the results of the query depend on the particular provider. It may
+ choose to return <code>null</code>, or it may throw an {@link java.lang.Exception}.
+</p>
+<p>
+ Since a {@link android.database.Cursor} is a "list" of rows, a good way to display the
+ contents of a {@link android.database.Cursor} is to link it to a {@link android.widget.ListView}
+ via a {@link android.widget.SimpleCursorAdapter}.
+</p>
+<p>
+ The following snippet continues the code from the previous snippet. It creates a
+ {@link android.widget.SimpleCursorAdapter} object containing the {@link android.database.Cursor}
+ retrieved by the query, and sets this object to be the adapter for a
+ {@link android.widget.ListView}:
+</p>
+<pre class="prettyprint">
+// Defines a list of columns to retrieve from the Cursor and load into an output row
+String[] mWordListColumns =
+{
+ UserDictionary.Words.WORD, // Contract class constant containing the word column name
+ UserDictionary.Words.LOCALE // Contract class constant containing the locale column name
+};
+
+// Defines a list of View IDs that will receive the Cursor columns for each row
+int[] mWordListItems = { R.id.dictWord, R.id.locale};
+
+// Creates a new SimpleCursorAdapter
+mCursorAdapter = new SimpleCursorAdapter(
+ getApplicationContext(), // The application's Context object
+ R.layout.wordlistrow, // A layout in XML for one row in the ListView
+ mCursor, // The result from the query
+ mWordListColumns, // A string array of column names in the cursor
+ mWordListItems, // An integer array of view IDs in the row layout
+ 0); // Flags (usually none are needed)
+
+// Sets the adapter for the ListView
+mWordList.setAdapter(mCursorAdapter);
+</pre>
+<p class="note">
+ <strong>Note:</strong> To back a {@link android.widget.ListView} with a
+ {@link android.database.Cursor}, the cursor must contain a column named <code>_ID</code>.
+ Because of this, the query shown previously retrieves the <code>_ID</code> column for the
+ "words" table, even though the {@link android.widget.ListView} doesn't display it.
+ This restriction also explains why most providers have a <code>_ID</code> column for each of
+ their tables.
+</p>
+
+ <!-- Getting data from query results -->
+<h3 id="GettingResults">Getting data from query results</h3>
+<p>
+ Rather than simply displaying query results, you can use them for other tasks. For
+ example, you can retrieve spellings from the user dictionary and then look them up in
+ other providers. To do this, you iterate over the rows in the {@link android.database.Cursor}:
+</p>
+<pre class="prettyprint">
+
+// Determine the column index of the column named "word"
+int index = mCursor.getColumnIndex(UserDictionary.Words.WORD);
+
+/*
+ * Only executes if the cursor is valid. The User Dictionary Provider returns null if
+ * an internal error occurs. Other providers may throw an Exception instead of returning null.
+ */
+
+if (mCursor != null) {
+ /*
+ * Moves to the next row in the cursor. Before the first movement in the cursor, the
+ * "row pointer" is -1, and if you try to retrieve data at that position you will get an
+ * exception.
+ */
+ while (mCursor.moveToNext()) {
+
+ // Gets the value from the column.
+ newWord = mCursor.getString(index);
+
+ // Insert code here to process the retrieved word.
+
+ ...
+
+ // end of while loop
+ }
+} else {
+
+ // Insert code here to report an error if the cursor is null or the provider threw an exception.
+}
+</pre>
+<p>
+ {@link android.database.Cursor} implementations contain several "get" methods for
+ retrieving different types of data from the object. For example, the previous snippet
+ uses {@link android.database.Cursor#getString(int) getString()}. They also have a
+ {@link android.database.Cursor#getType(int) getType()} method that returns a value indicating
+ the data type of the column.
+</p>
+
+
+ <!-- Requesting permissions -->
+<h2 id="Permissions">Content Provider Permissions</h2>
+<p>
+ A provider's application can specify permissions that other applications must have in order to
+ access the provider's data. These permissions ensure that the user knows what data
+ an application will try to access. Based on the provider's requirements, other applications
+ request the permissions they need in order to access the provider. End users see the requested
+ permissions when they install the application.
+</p>
+<p>
+ If a provider's application doesn't specify any permissions, then other applications have no
+ access to the provider's data. However, components in the provider's application always have
+ full read and write access, regardless of the specified permissions.
+</p>
+<p>
+ As noted previously, the User Dictionary Provider requires the
+ <code>android.permission.READ_USER_DICTIONARY</code> permission to retrieve data from it.
+ The provider has the separate <code>android.permission.WRITE_USER_DICTIONARY</code>
+ permission for inserting, updating, or deleting data.
+</p>
+<p>
+ To get the permissions needed to access a provider, an application requests them with a
+ <code><a href="{@docRoot}guide/topics/manifest/uses-permission-element.html">
+ <uses-permission></a></code> element in its manifest file.
+ When the Android Package Manager installs the application, a user must approve all of the
+ permissions the application requests. If the user approves all of them, Package Manager
+ continues the installation; if the user doesn't approve them, Package Manager
+ aborts the installation.
+</p>
+<p>
+ The following
+ <code><a href="{@docRoot}guide/topics/manifest/uses-permission-element.html">
+ <uses-permission></a></code> element requests read access to the User Dictionary Provider:
+</p>
+<pre>
+ <uses-permission android:name="android.permission.READ_USER_DICTIONARY">
+</pre>
+<p>
+ The impact of permissions on provider access is explained in more detail in the
+ <a href="{@docRoot}guide/topics/security/security.html">Security and Permissions</a> guide.
+</p>
+
+
+<!-- Inserting, Updating, and Deleting Data -->
+<h2 id="Modifications">Inserting, Updating, and Deleting Data</h2>
+<p>
+ In the same way that you retrieve data from a provider, you also use the interaction between
+ a provider client and the provider's {@link android.content.ContentProvider} to modify data.
+ You call a method of {@link android.content.ContentResolver} with arguments that are passed to
+ the corresponding method of {@link android.content.ContentProvider}. The provider and provider
+ client automatically handle security and inter-process communication.
+</p>
+<h3 id="Inserting">Inserting data</h3>
+<p>
+ To insert data into a provider, you call the
+ {@link android.content.ContentResolver#insert(Uri,ContentValues) ContentResolver.insert()}
+ method. This method inserts a new row into the provider and returns a content URI for that row.
+ This snippet shows how to insert a new word into the User Dictionary Provider:
+</p>
+<pre class="prettyprint">
+// Defines a new Uri object that receives the result of the insertion
+Uri mNewUri;
+
+...
+
+// Defines an object to contain the new values to insert
+ContentValues mNewValues = new ContentValues();
+
+/*
+ * Sets the values of each column and inserts the word. The arguments to the "put"
+ * method are "column name" and "value"
+ */
+mNewValues.put(UserDictionary.Words.APP_ID, "example.user");
+mNewValues.put(UserDictionary.Words.LOCALE, "en_US");
+mNewValues.put(UserDictionary.Words.WORD, "insert");
+mNewValues.put(UserDictionary.Words.FREQUENCY, "100");
+
+mNewUri = getContentResolver().insert(
+ UserDictionary.Word.CONTENT_URI, // the user dictionary content URI
+ mNewValues // the values to insert
+);
+</pre>
+<p>
+ The data for the new row goes into a single {@link android.content.ContentValues} object, which
+ is similar in form to a one-row cursor. The columns in this object don't need to have the
+ same data type, and if you don't want to specify a value at all, you can set a column
+ to <code>null</code> using {@link android.content.ContentValues#putNull(String)
+ ContentValues.putNull()}.
+</p>
+<p>
+ The snippet doesn't add the <code>_ID</code> column, because this column is maintained
+ automatically. The provider assigns a unique value of <code>_ID</code> to every row that is
+ added. Providers usually use this value as the table's primary key.
+</p>
+<p>
+ The content URI returned in <code>newUri</code> identifies the newly-added row, with
+ the following format:
+</p>
+<pre>
+content://user_dictionary/words/<id_value>
+</pre>
+<p>
+ The <code><id_value></code> is the contents of <code>_ID</code> for the new row.
+ Most providers can detect this form of content URI automatically and then perform the requested
+ operation on that particular row.
+</p>
+<p>
+ To get the value of <code>_ID</code> from the returned {@link android.net.Uri}, call
+ {@link android.content.ContentUris#parseId(Uri) ContentUris.parseId()}.
+</p>
+<h3 id="Updating">Updating data</h3>
+<p>
+ To update a row, you use a {@link android.content.ContentValues} object with the updated
+ values just as you do with an insertion, and selection criteria just as you do with a query.
+ The client method you use is
+ {@link android.content.ContentResolver#update(Uri, ContentValues, String, String[])
+ ContentResolver.update()}. You only need to add values to the
+ {@link android.content.ContentValues} object for columns you're updating. If you want to clear
+ the contents of a column, set the value to <code>null</code>.
+</p>
+<p>
+ The following snippet changes all the rows whose locale has the language "en" to a
+ have a locale of <code>null</code>. The return value is the number of rows that were updated:
+</p>
+<pre>
+// Defines an object to contain the updated values
+ContentValues mUpdateValues = new ContentValues();
+
+// Defines selection criteria for the rows you want to update
+String mSelectionClause = UserDictionary.Words.LOCALE + "LIKE ?";
+String[] mSelectionArgs = {"en_%"};
+
+// Defines a variable to contain the number of updated rows
+int mRowsUpdated = 0;
+
+...
+
+/*
+ * Sets the updated value and updates the selected words.
+ */
+mUpdateValues.putNull(UserDictionary.Words.LOCALE);
+
+mRowsUpdated = getContentResolver().update(
+ UserDictionary.Words.CONTENT_URI, // the user dictionary content URI
+ mUpdateValues // the columns to update
+ mSelectionClause // the column to select on
+ mSelectionArgs // the value to compare to
+);
+</pre>
+<p>
+ You should also sanitize user input when you call
+ {@link android.content.ContentResolver#update(Uri, ContentValues, String, String[])
+ ContentResolver.update()}. To learn more about this, read the section
+ <a href="#Injection">Protecting against malicious input</a>.
+</p>
+<h3 id="Deleting">Deleting data</h3>
+<p>
+ Deleting rows is similar to retrieving row data: you specify selection criteria for the rows
+ you want to delete and the client method returns the number of deleted rows.
+ The following snippet deletes rows whose appid matches "user". The method returns the
+ number of deleted rows.
+</p>
+<pre>
+
+// Defines selection criteria for the rows you want to delete
+String mSelectionClause = UserDictionary.Words.APP_ID + " LIKE ?";
+String[] mSelectionArgs = {"user"};
+
+// Defines a variable to contain the number of rows deleted
+int mRowsDeleted = 0;
+
+...
+
+// Deletes the words that match the selection criteria
+mRowsDeleted = getContentResolver().delete(
+ UserDictionary.Words.CONTENT_URI, // the user dictionary content URI
+ mSelectionClause // the column to select on
+ mSelectionArgs // the value to compare to
+);
+</pre>
+<p>
+ You should also sanitize user input when you call
+ {@link android.content.ContentResolver#delete(Uri, String, String[])
+ ContentResolver.delete()}. To learn more about this, read the section
+ <a href="#Injection">Protecting against malicious input</a>.
+</p>
+<!-- Provider Data Types -->
+<h2 id="DataTypes">Provider Data Types</h2>
+<p>
+ Content providers can offer many different data types. The User Dictionary Provider offers only
+ text, but providers can also offer the following formats:
+</p>
+ <ul>
+ <li>
+ integer
+ </li>
+ <li>
+ long integer (long)
+ </li>
+ <li>
+ floating point
+ </li>
+ <li>
+ long floating point (double)
+ </li>
+ </ul>
+<p>
+ Another data type that providers often use is Binary Large OBject (BLOB) implemented as a
+ 64KB byte array. You can see the available data types by looking at the
+ {@link android.database.Cursor} class "get" methods.
+</p>
+<p>
+ The data type for each column in a provider is usually listed in its documentation.
+ The data types for the User Dictionary Provider are listed in the reference documentation
+ for its contract class {@link android.provider.UserDictionary.Words} (contract classes are
+ described in the section <a href="#ContractClasses">Contract Classes</a>).
+ You can also determine the data type by calling {@link android.database.Cursor#getType(int)
+ Cursor.getType()}.
+</p>
+<p>
+ Providers also maintain MIME data type information for each content URI they define. You can
+ use the MIME type information to find out if your application can handle data that the
+ provider offers, or to choose a type of handling based on the MIME type. You usually need the
+ MIME type when you are working with a provider that contains complex
+ data structures or files. For example, the {@link android.provider.ContactsContract.Data}
+ table in the Contacts Provider uses MIME types to label the type of contact data stored in each
+ row. To get the MIME type corresponding to a content URI, call
+ {@link android.content.ContentResolver#getType(Uri) ContentResolver.getType()}.
+</p>
+<p>
+ The section <a href="#MIMETypeReference">MIME Type Reference</a> describes the
+ syntax of both standard and custom MIME types.
+</p>
+
+
+<!-- Alternative Forms of Provider Access -->
+<h2 id="AltForms">Alternative Forms of Provider Access</h2>
+<p>
+ Three alternative forms of provider access are important in application development:
+</p>
+<ul>
+ <li>
+ <a href="#Batch">Batch access</a>: You can create a batch of access calls with methods in
+ the {@link android.content.ContentProviderOperation} class, and then apply them with
+ {@link android.content.ContentResolver#applyBatch(String, ArrayList)
+ ContentResolver.applyBatch()}.
+ </li>
+ <li>
+ Asynchronous queries: You should do queries in a separate thread. One way to do this is to
+ use a {@link android.content.CursorLoader} object. The examples in the
+ <a href="{@docRoot}guide/topics/fundamentals/loaders.html">Loaders</a> guide demonstrate
+ how to do this.
+ </li>
+ <li>
+ <a href="#Intents">Data access via intents</a>: Although you can't send an intent
+ directly to a provider, you can send an intent to the provider's application, which is
+ usually the best-equipped to modify the provider's data.
+ </li>
+</ul>
+<p>
+ Batch access and modification via intents are described in the following sections.
+</p>
+<h3 id="Batch">Batch access</h3>
+<p>
+ Batch access to a provider is useful for inserting a large number of rows, or for inserting
+ rows in multiple tables in the same method call, or in general for performing a set of
+ operations across process boundaries as a transaction (an atomic operation).
+</p>
+<p>
+ To access a provider in "batch mode",
+ you create an array of {@link android.content.ContentProviderOperation} objects and then
+ dispatch them to a content provider with
+ {@link android.content.ContentResolver#applyBatch(String, ArrayList)
+ ContentResolver.applyBatch()}. You pass the content provider's <em>authority</em> to this
+ method, rather than a particular content URI, which allows each
+ {@link android.content.ContentProviderOperation} object in the array to work against a
+ different table. A call to {@link android.content.ContentResolver#applyBatch(String, ArrayList)
+ ContentResolver.applyBatch()} returns an array of results.
+</p>
+<p>
+ The description of the {@link android.provider.ContactsContract.RawContacts} contract class
+ includes a code snippet that demonstrates batch insertion. The
+ <a href="{@docRoot}resources/samples/ContactManager/index.html">Contact Manager</a>
+ sample application contains an example of batch access in its <code>ContactAdder.java</code>
+ source file.
+</p>
+<div class="sidebox-wrapper">
+<div class="sidebox">
+<h2>Displaying data using a helper app</h2>
+<p>
+ If your application <em>does</em> have access permissions, you still may want to use an
+ intent to display data in another application. For example, the Calendar application accepts an
+ {@link android.content.Intent#ACTION_VIEW} intent, which displays a particular date or event.
+ This allows you to display calendar information without having to create your own UI.
+ To learn more about this feature, see the
+ <a href="{@docRoot}guide/topics/providers/calendar-provider.html">Calendar Provider</a> guide.
+</p>
+<p>
+ The application to which you send the intent doesn't have to be the application
+ associated with the provider. For example, you can retrieve a contact from the
+ Contact Provider, then send an {@link android.content.Intent#ACTION_VIEW} intent
+ containing the content URI for the contact's image to an image viewer.
+</p>
+</div>
+</div>
+<h3 id="Intents">Data access via intents</h3>
+<p>
+ Intents can provide indirect access to a content provider. You allow the user to access
+ data in a provider even if your application doesn't have access permissions, either by
+ getting a result intent back from an application that has permissions, or by activating an
+ application that has permissions and letting the user do work in it.
+</p>
+<h4>Getting access with temporary permissions</h4>
+<p>
+ You can access data in a content provider, even if you don't have the proper access
+ permissions, by sending an intent to an application that does have the permissions and
+ receiving back a result intent containing "URI" permissions.
+ These are permissions for a specific content URI that last until the activity that receives
+ them is finished. The application that has permanent permissions grants temporary
+ permissions by setting a flag in the result intent:
+</p>
+<ul>
+ <li>
+ <strong>Read permission:</strong>
+ {@link android.content.Intent#FLAG_GRANT_READ_URI_PERMISSION}
+ </li>
+ <li>
+ <strong>Write permission:</strong>
+ {@link android.content.Intent#FLAG_GRANT_WRITE_URI_PERMISSION}
+ </li>
+</ul>
+<p class="note">
+ <strong>Note:</strong> These flags don't give general read or write access to the provider
+ whose authority is contained in the content URI. The access is only for the URI itself.
+</p>
+<p>
+ A provider defines URI permissions for content URIs in its manifest, using the
+ <code><a href="{@docRoot}guide/topics/manifest/provider-element.html#gprmsn">
+ android:grantUriPermission</a></code>
+ attribute of the
+ {@code <a href="guide/topics/manifest/provider-element.html"><provider></a>}
+ element, as well as the
+ {@code <a href="guide/topics/manifest/grant-uri-permission-element.html">
+ <grant-uri-permission></a>} child element of the
+ {@code <a href="guide/topics/manifest/provider-element.html"><provider></a>}
+ element. The URI permissions mechanism is explained in more detail in the
+ <a href="{@docRoot}guide/topics/security/security.html">Security and Permissions</a> guide,
+ in the section "URI Permissions".
+</p>
+<p>
+ For example, you can retrieve data for a contact in the Contacts Provider, even if you don't
+ have the {@link android.Manifest.permission#READ_CONTACTS} permission. You might want to do
+ this in an application that sends e-greetings to a contact on his or her birthday. Instead of
+ requesting {@link android.Manifest.permission#READ_CONTACTS}, which gives you access to all of
+ the user's contacts and all of their information, you prefer to let the user control which
+ contacts are used by your application. To do this, you use the following process:
+</p>
+<ol>
+ <li>
+ Your application sends an intent containing the action
+ {@link android.content.Intent#ACTION_PICK} and the "contacts" MIME type
+ {@link android.provider.ContactsContract.RawContacts#CONTENT_ITEM_TYPE}, using the
+ method {@link android.app.Activity#startActivityForResult(Intent, int)
+ startActivityForResult()}.
+ </li>
+ <li>
+ Because this intent matches the intent filter for the
+ People app's "selection" activity, the activity will come to the foreground.
+ </li>
+ <li>
+ In the selection activity, the user selects a
+ contact to update. When this happens, the selection activity calls
+ {@link android.app.Activity#setResult(int, Intent) setResult(resultcode, intent)}
+ to set up a intent to give back to your application. The intent contains the content URI
+ of the contact the user selected, and the "extras" flags
+ {@link android.content.Intent#FLAG_GRANT_READ_URI_PERMISSION}. These flags grant URI
+ permission to your app to read data for the contact pointed to by the
+ content URI. The selection activity then calls {@link android.app.Activity#finish()} to
+ return control to your application.
+ </li>
+ <li>
+ Your activity returns to the foreground, and the system calls your activity's
+ {@link android.app.Activity#onActivityResult(int, int, Intent) onActivityResult()}
+ method. This method receives the result intent created by the selection activity in
+ the People app.
+ </li>
+ <li>
+ With the content URI from the result intent, you can read the contact's data
+ from the Contacts Provider, even though you didn't request permanent read access permission
+ to the provider in your manifest. You can then get the contact's birthday information
+ or his or her email address and then send the e-greeting.
+ </li>
+</ol>
+<h4>Using another application</h4>
+<p>
+ A simple way to allow the user to modify data to which you don't have access permissions is to
+ activate an application that has permissions and let the user do the work there.
+</p>
+<p>
+ For example, the Calendar application accepts an
+ {@link android.content.Intent#ACTION_INSERT} intent, which allows you to activate the
+ application's insert UI. You can pass "extras" data in this intent, which the application
+ uses to pre-populate the UI. Because recurring events have a complex syntax, the preferred
+ way of inserting events into the Calendar Provider is to activate the Calendar app with an
+ {@link android.content.Intent#ACTION_INSERT} and then let the user insert the event there.
+</p>
+<!-- Contract Classes -->
+<h2 id="ContractClasses">Contract Classes</h2>
+<p>
+ A contract class defines constants that help applications work with the content URIs, column
+ names, intent actions, and other features of a content provider. Contract classes are not
+ included automatically with a provider; the provider's developer has to define them and then
+ make them available to other developers. Many of the providers included with the Android
+ platform have corresponding contract classes in the package {@link android.provider}.
+</p>
+<p>
+ For example, the User Dictionary Provider has a contract class
+ {@link android.provider.UserDictionary} containing content URI and column name constants. The
+ content URI for the "words" table is defined in the constant
+ {@link android.provider.UserDictionary.Words#CONTENT_URI UserDictionary.Words.CONTENT_URI}.
+ The {@link android.provider.UserDictionary.Words} class also contains column name constants,
+ which are used in the example snippets in this guide. For example, a query projection can be
+ defined as:
+</p>
+<pre>
+String[] mProjection =
+{
+ UserDictionary.Words._ID,
+ UserDictionary.Words.WORD,
+ UserDictionary.Words.LOCALE
+};
+</pre>
+<p>
+ Another contract class is {@link android.provider.ContactsContract} for the Contacts Provider.
+ The reference documentation for this class includes example code snippets. One of its
+ subclasses, {@link android.provider.ContactsContract.Intents.Insert}, is a contract
+ class that contains constants for intents and intent data.
+</p>
+
+
+<!-- MIME Type Reference -->
+<h2 id="MIMETypeReference">MIME Type Reference</h2>
+<p>
+ Content providers can return standard MIME media types, or custom MIME type strings, or both.
+</p>
+<p>
+ MIME types have the format
+</p>
+<pre>
+<em>type</em>/<em>subtype</em>
+</pre>
+<p>
+ For example, the well-known MIME type <code>text/html</code> has the <code>text</code> type and
+ the <code>html</code> subtype. If the provider returns this type for a URI, it means that a
+ query using that URI will return text containing HTML tags.
+</p>
+<p>
+ Custom MIME type strings, also called "vendor-specific" MIME types, have more
+ complex <em>type</em> and <em>subtype</em> values. The <em>type</em> value is always
+</p>
+<pre>
+vnd.android.cursor.<strong>dir</strong>
+</pre>
+<p>
+ for multiple rows, or
+</p>
+<pre>
+vnd.android.cursor.<strong>item</strong>
+</pre>
+<p>
+ for a single row.
+</p>
+<p>
+ The <em>subtype</em> is provider-specific. The Android built-in providers usually have a simple
+ subtype. For example, the when the Contacts application creates a row for a telephone number,
+ it sets the following MIME type in the row:
+</p>
+<pre>
+vnd.android.cursor.item/phone_v2
+</pre>
+<p>
+ Notice that the subtype value is simply <code>phone_v2</code>.
+</p>
+<p>
+ Other provider developers may create their own pattern of subtypes based on the provider's
+ authority and table names. For example, consider a provider that contains train timetables.
+ The provider's authority is <code>com.example.trains</code>, and it contains the tables
+ Line1, Line2, and Line3. In response to the content URI
+</p>
+<p>
+<pre>
+content://com.example.trains/Line1
+</pre>
+<p>
+ for table Line1, the provider returns the MIME type
+</p>
+<pre>
+vnd.android.cursor.<strong>dir</strong>/vnd.example.line1
+</pre>
+<p>
+ In response to the content URI
+</p>
+<pre>
+content://com.example.trains/Line2/5
+</pre>
+<p>
+ for row 5 in table Line2, the provider returns the MIME type
+</p>
+<pre>
+vnd.android.cursor.<strong>item</strong>/vnd.example.line2
+</pre>
+<p>
+ Most content providers define contract class constants for the MIME types they use. The
+ Contacts Provider contract class {@link android.provider.ContactsContract.RawContacts},
+ for example, defines the constant
+ {@link android.provider.ContactsContract.RawContacts#CONTENT_ITEM_TYPE} for the MIME type of
+ a single raw contact row.
+</p>
+<p>
+ Content URIs for single rows are described in the section
+ <a href="#ContentURIs">Content URIs</a>.
+</p>
diff --git a/docs/html/guide/topics/providers/content-provider-creating.jd b/docs/html/guide/topics/providers/content-provider-creating.jd
new file mode 100644
index 0000000..4ebdb50
--- /dev/null
+++ b/docs/html/guide/topics/providers/content-provider-creating.jd
@@ -0,0 +1,1215 @@
+page.title=Creating a Content Provider
+@jd:body
+<div id="qv-wrapper">
+<div id="qv">
+
+
+<h2>In this document</h2>
+<ol>
+ <li>
+ <a href="#DataStorage">Designing Data Storage</a>
+ </li>
+ <li>
+ <a href="#ContentURI">Designing Content URIs</a>
+ </li>
+ <li>
+ <a href="#ContentProvider">Implementing the ContentProvider Class</a>
+ <ol>
+ <li>
+ <a href="#RequiredAccess">Required Methods</a>
+ </li>
+ <li>
+ <a href="#Query">Implementing the query() method</a>
+ </li>
+ <li>
+ <a href="#Insert">Implementing the insert() method</a>
+ </li>
+ <li>
+ <a href="#Delete">Implementing the delete() method</a>
+ </li>
+ <li>
+ <a href="#Update">Implementing the update() method</a>
+ </li>
+ <li>
+ <a href="#OnCreate">Implementing the onCreate() method</a>
+ </li>
+ </ol>
+ </li>
+ <li>
+ <a href="#MIMETypes">Implementing Content Provider MIME Types</a>
+ <ol>
+ <li>
+ <a href="#TableMIMETypes">MIME types for tables</a>
+ </li>
+ <li>
+ <a href="#FileMIMETypes">MIME types for files</a>
+ </li>
+ </ol>
+ </li>
+ <li>
+ <a href="#ContractClass">Implementing a Contract Class</a>
+ </li>
+ <li>
+ <a href="#Permissions">Implementing Content Provider Permissions</a>
+ </li>
+ <li>
+ <a href="#ProviderElement">The <provider> Element</a>
+ </li>
+ <li>
+ <a href="#Intents">Intents and Data Access</a>
+ </li>
+</ol>
+<h2>Key classes</h2>
+ <ol>
+ <li>
+ {@link android.content.ContentProvider}
+ </li>
+ <li>
+ {@link android.database.Cursor}
+ </li>
+ <li>
+ {@link android.net.Uri}
+ </li>
+ </ol>
+<h2>Related Samples</h2>
+ <ol>
+ <li>
+ <a
+ href="{@docRoot}resources/samples/NotePad/index.html">
+ Note Pad sample application
+ </a>
+ </li>
+ </ol>
+<h2>See also</h2>
+ <ol>
+ <li>
+ <a href="{@docRoot}guide/topics/providers/content-provider-basics.html">
+ Content Provider Basics</a>
+ </li>
+ <li>
+ <a href="{@docRoot}guide/topics/providers/calendar-provider.html">
+ Calendar Provider</a>
+ </li>
+ </ol>
+</div>
+</div>
+
+
+<p>
+ A content provider manages access to a central repository of data. You implement a
+ provider as one or more classes in an Android application, along with elements in
+ the manifest file. One of your classes implements a subclass
+ {@link android.content.ContentProvider}, which is the interface between your provider and
+ other applications. Although content providers are meant to make data available to other
+ applications, you may of course have activities in your application that allow the user
+ to query and modify the data managed by your provider.
+</p>
+<p>
+ The rest of this topic is a basic list of steps for building a content provider and a list
+ of APIs to use.
+</p>
+
+
+<!-- Before You Start Building -->
+<h2 id="BeforeYouStart">Before You Start Building</h2>
+<p>
+ Before you start building a provider, do the following:
+</p>
+<ol>
+ <li>
+ <strong>Decide if you need a content provider</strong>. You need to build a content
+ provider if you want to provide one or more of the following features:
+ <ul>
+ <li>You want to offer complex data or files to other applications.</li>
+ <li>You want to allow users to copy complex data from your app into other apps.</li>
+ <li>You want to provide custom search suggestions using the search framework.</li>
+ </ul>
+ <p>
+ You <em>don't</em> need a provider to use an SQLite database if the use is entirely within
+ your own application.
+ </p>
+ </li>
+ <li>
+ If you haven't done so already, read the topic
+ <a href="{@docRoot}guide/topics/providers/content-provider-basics.html">
+ Content Provider Basics</a> to learn more about providers.
+ </li>
+</ol>
+<p>
+ Next, follow these steps to build your provider:
+</p>
+<ol>
+ <li>
+ Design the raw storage for your data. A content provider offers data in two ways:
+ <dl>
+ <dt>
+ File data
+ </dt>
+ <dd>
+ Data that normally goes into files, such as
+ photos, audio, or videos. Store the files in your application's private
+ space. In response to a request for a file from another application, your
+ provider can offer a handle to the file.
+ </dd>
+ <dt>
+ "Structured" data
+ </dt>
+ <dd>
+ Data that normally goes into a database, array, or similar structure.
+ Store the data in a form that's compatible with tables of rows and columns. A row
+ represents an entity, such as a person or an item in inventory. A column represents
+ some data for the entity, such a person's name or an item's price. A common way to
+ store this type of data is in an SQLite database, but you can use any type of
+ persistent storage. To learn more about the storage types available in the
+ Android system, see the section <a href="#DataStorage">
+ Designing Data Storage</a>.
+ </dd>
+ </dl>
+ </li>
+ <li>
+ Define a concrete implementation of the {@link android.content.ContentProvider} class and
+ its required methods. This class is the interface between your data and the rest of the
+ Android system. For more information about this class, see the section
+ <a href="#ContentProvider">Implementing the ContentProvider Class</a>.
+ </li>
+ <li>
+ Define the provider's authority string, its content URIs, and column names. If you want
+ the provider's application to handle intents, also define intent actions, extras data,
+ and flags. Also define the permissions that you will require for applications that want
+ to access your data. You should consider defining all of these values as constants in a
+ separate contract class; later, you can expose this class to other developers. For more
+ information about content URIs, see the
+ section <a href="#ContentURI">Designing Content URIs</a>.
+ For more information about intents, see the
+ section <a href="#Intents">Intents and Data Access</a>.
+ </li>
+ <li>
+ Add other optional pieces, such as sample data or an implementation
+ of {@link android.content.AbstractThreadedSyncAdapter} that can synchronize data between
+ the provider and cloud-based data.
+ </li>
+</ol>
+
+
+<!-- Designing Data Storage -->
+<h2 id="DataStorage">Designing Data Storage</h2>
+<p>
+ A content provider is the interface to data saved in a structured format. Before you create
+ the interface, you must decide how to store the data. You can store the data in any form you
+ like, and then design the interface to read and write the data as necessary.
+</p>
+<p>
+ These are some of the data storage technologies that are available in Android:
+</p>
+<ul>
+ <li>
+ The Android system includes an SQLite database API that Android's own providers use
+ to store table-oriented data. The
+ {@link android.database.sqlite.SQLiteOpenHelper} class helps you create databases, and the
+ {@link android.database.sqlite.SQLiteDatabase} class is the base class for accessing
+ databases.
+ <p>
+ Remember that you don't have to use a database to implement your repository. A provider
+ appears externally as a set of tables, similar to a relational database, but this is
+ not a requirement for the provider's internal implementation.
+ </p>
+ </li>
+ <li>
+ For storing file data, Android has a variety of file-oriented APIs.
+ To learn more about file storage, read the topic
+ <a href="{@docRoot}guide/topics/data/data-storage.html">Data Storage</a>. If you're
+ designing a provider that offers media-related data such as music or videos, you can
+ have a provider that combines table data and files.
+ </li>
+ <li>
+ For working with network-based data, use classes in {@link java.net} and
+ {@link android.net}. You can also synchronize network-based data to a local data
+ store such as a database, and then offer the data as tables or files.
+ The <a href="{@docRoot}resources/samples/SampleSyncAdapter/index.html">
+ Sample Sync Adapter</a> sample application demonstrates this type of synchronization.
+ </li>
+</ul>
+<h3 id="DataDesign">
+ Data design considerations
+</h3>
+<p>
+ Here are some tips for designing your provider's data structure:
+</p>
+<ul>
+ <li>
+ Table data should always have a "primary key" column that the provider maintains
+ as a unique numeric value for each row. You can use this value to link the row to related
+ rows in other tables (using it as a "foreign key"). Although you can use any name
+ for this column, using {@link android.provider.BaseColumns#_ID BaseColumns._ID} is the best
+ choice, because linking the results of a provider query to a
+ {@link android.widget.ListView} requires one of the retrieved columns to have the name
+ <code>_ID</code>.
+ </li>
+ <li>
+ If you want to provide bitmap images or other very large pieces of file-oriented data, store
+ the data in a file and then provide it indirectly rather than storing it directly in a
+ table. If you do this, you need to tell users of your provider that they need to use a
+ {@link android.content.ContentResolver} file method to access the data.
+ </li>
+ <li>
+ Use the Binary Large OBject (BLOB) data type to store data that varies in size or has a
+ varying structure. For example, you can use a BLOB column to store a
+ <a href="http://code.google.com/p/protobuf">protocol buffer</a> or
+ <a href="http://www.json.org">JSON structure</a>.
+ <p>
+ You can also use a BLOB to implement a <em>schema-independent</em> table. In
+ this type of table, you define a primary key column, a MIME type column, and one or
+ more generic columns as BLOB. The meaning of the data in the BLOB columns is indicated
+ by the value in the MIME type column. This allows you to store different row types in
+ the same table. The Contacts Provider's "data" table
+ {@link android.provider.ContactsContract.Data} is an example of a schema-independent
+ table.
+ </p>
+ </li>
+</ul>
+<!-- Designing Content URIs -->
+<h2 id="ContentURI">Designing Content URIs</h2>
+<p>
+ A <strong>content URI</strong> is a URI that identifies data in a provider. Content URIs include
+ the symbolic name of the entire provider (its <strong>authority</strong>) and a
+ name that points to a table or file (a <strong>path</strong>). The optional id part points to
+ an individual row in a table. Every data access method of
+ {@link android.content.ContentProvider} has a content URI as an argument; this allows you to
+ determine the table, row, or file to access.
+</p>
+<p>
+ The basics of content URIs are described in the topic
+ <a href="{@docRoot}guide/topics/providers/content-provider-basics.html">
+ Content Provider Basics</a>.
+</p>
+<h3>Designing an authority</h3>
+<p>
+ A provider usually has a single authority, which serves as its Android-internal name. To
+ avoid conflicts with other providers, you should use Internet domain ownership (in reverse)
+ as the basis of your provider authority. Because this recommendation is also true for Android
+ package names, you can define your provider authority as an extension of the name
+ of the package containing the provider. For example, if your Android package name is
+ <code>com.example.<appname></code>, you should give your provider the
+ authority <code>com.example.<appname>.provider</code>.
+</p>
+<h3>Designing a path structure</h3>
+<p>
+ Developers usually create content URIs from the authority by appending paths that point to
+ individual tables. For example, if you have two tables <em>table1</em> and
+ <em>table2</em>, you combine the authority from the previous example to yield the
+ content URIs
+ <code>com.example.<appname>.provider/table1</code> and
+ <code>com.example.<appname>.provider/table2</code>. Paths aren't
+ limited to a single segment, and there doesn't have to be a table for each level of the path.
+</p>
+<h3>Handling content URI IDs</h3>
+<p>
+ By convention, providers offer access to a single row in a table by accepting a content URI
+ with an ID value for the row at the end of the URI. Also by convention, providers match the
+ ID value to the table's <code>_ID</code> column, and perform the requested access against the
+ row that matches.
+</p>
+<p>
+ This convention facilitates a common design pattern for apps accessing a provider. The app
+ does a query against the provider and displays the resulting {@link android.database.Cursor}
+ in a {@link android.widget.ListView} using a {@link android.widget.CursorAdapter}.
+ The definition of {@link android.widget.CursorAdapter} requires one of the columns in the
+ {@link android.database.Cursor} to be <code>_ID</code>
+</p>
+<p>
+ The user then picks one of the displayed rows from the UI in order to look at or modify the
+ data. The app gets the corresponding row from the {@link android.database.Cursor} backing the
+ {@link android.widget.ListView}, gets the <code>_ID</code> value for this row, appends it to
+ the content URI, and sends the access request to the provider. The provider can then do the
+ query or modification against the exact row the user picked.
+</p>
+<h3>Content URI patterns</h3>
+<p>
+ To help you choose which action to take for an incoming content URI, the provider API includes
+ the convenience class {@link android.content.UriMatcher}, which maps content URI "patterns" to
+ integer values. You can use the integer values in a <code>switch</code> statement that
+ chooses the desired action for the content URI or URIs that match a particular pattern.
+</p>
+<p>
+ A content URI pattern matches content URIs using wildcard characters:
+</p>
+ <ul>
+ <li>
+ <strong><code>*</code>:</strong> Matches a string of any valid characters of any length.
+ </li>
+ <li>
+ <strong><code>#</code>:</strong> Matches a string of numeric characters of any length.
+ </li>
+ </ul>
+<p>
+ As an example of designing and coding content URI handling, consider a provider with the
+ authority <code>com.example.app.provider</code> that recognizes the following content URIs
+ pointing to tables:
+</p>
+<ul>
+ <li>
+ <code>content://com.example.app.provider/table1</code>: A table called <code>table1</code>.
+ </li>
+ <li>
+ <code>content://com.example.app.provider/table2/dataset1</code>: A table called
+ <code>dataset1</code>.
+ </li>
+ <li>
+ <code>content://com.example.app.provider/table2/dataset2</code>: A table called
+ <code>dataset2</code>.
+ </li>
+ <li>
+ <code>content://com.example.app.provider/table3</code>: A table called <code>table3</code>.
+ </li>
+</ul>
+<p>
+ The provider also recognizes these content URIs if they have a row ID appended to them, as
+ for example <code>content://com.example.app.provider/table3/1</code> for the row identified by
+ <code>1</code> in <code>table3</code>.
+</p>
+<p>
+ The following content URI patterns would be possible:
+</p>
+<dl>
+ <dt>
+ <code>content://com.example.app.provider/*</code>
+ </dt>
+ <dd>
+ Matches any content URI in the provider.
+ </dd>
+ <dt>
+ <code>content://com.example.app.provider/table2/*</code>:
+ </dt>
+ <dd>
+ Matches a content URI for the tables <code>dataset1</code>
+ and <code>dataset2</code>, but doesn't match content URIs for <code>table1</code> or
+ <code>table3</code>.
+ </dd>
+ <dt>
+ <code>content://com.example.app.provider/table3/#</code>: Matches a content URI
+ for single rows in <code>table3</code>, such as
+ <code>content://com.example.app.provider/table3/6</code> for the row identified by
+ <code>6</code>.
+ </dt>
+</dl>
+<p>
+ The following code snippet shows how the methods in {@link android.content.UriMatcher} work.
+ This code handles URIs for an entire table differently from URIs for a
+ single row, by using the content URI pattern
+ <code>content://<authority>/<path></code> for tables, and
+ <code>content://<authority>/<path>/<id></code> for single rows.
+</p>
+<p>
+ The method {@link android.content.UriMatcher#addURI(String, String, int) addURI()} maps an
+ authority and path to an integer value. The method android.content.UriMatcher#match(Uri)
+ match()} returns the integer value for a URI. A <code>switch</code> statement
+ chooses between querying the entire table, and querying for a single record:
+</p>
+<pre class="prettyprint">
+public class ExampleProvider extends ContentProvider {
+...
+ // Creates a UriMatcher object.
+ private static final UriMatcher sUriMatcher;
+...
+ /*
+ * The calls to addURI() go here, for all of the content URI patterns that the provider
+ * should recognize. For this snippet, only the calls for table 3 are shown.
+ */
+...
+ /*
+ * Sets the integer value for multiple rows in table 3 to 1. Notice that no wildcard is used
+ * in the path
+ */
+ sUriMatcher.addURI("com.example.app.provider", "table3", 1);
+
+ /*
+ * Sets the code for a single row to 2. In this case, the "#" wildcard is
+ * used. "content://com.example.app.provider/table3/3" matches, but
+ * "content://com.example.app.provider/table3 doesn't.
+ */
+ sUriMatcher.addURI("com.example.app.provider", "table3/#", 2);
+...
+ // Implements ContentProvider.query()
+ public Cursor query(
+ Uri uri,
+ String[] projection,
+ String selection,
+ String[] selectionArgs,
+ String sortOrder) {
+...
+ /*
+ * Choose the table to query and a sort order based on the code returned for the incoming
+ * URI. Here, too, only the statements for table 3 are shown.
+ */
+ switch (sUriMatcher.match(uri)) {
+
+
+ // If the incoming URI was for all of table3
+ case 1:
+
+ if (TextUtils.isEmpty(sortOrder)) sortOrder = "_ID ASC";
+ break;
+
+ // If the incoming URI was for a single row
+ case 2:
+
+ /*
+ * Because this URI was for a single row, the _ID value part is
+ * present. Get the last path segment from the URI; this is the _ID value.
+ * Then, append the value to the WHERE clause for the query
+ */
+ selection = selection + "_ID = " uri.getLastPathSegment();
+ break;
+
+ default:
+ ...
+ // If the URI is not recognized, you should do some error handling here.
+ }
+ // call the code to actually do the query
+ }
+</pre>
+<p>
+ Another class, {@link android.content.ContentUris}, provides convenience methods for working
+ with the <code>id</code> part of content URIs. The classes {@link android.net.Uri} and
+ {@link android.net.Uri.Builder} include convenience methods for parsing existing
+ {@link android.net.Uri} objects and building new ones.
+</p>
+
+<!-- Implementing the ContentProvider class -->
+<h2 id="ContentProvider">Implementing the ContentProvider Class</h2>
+<p>
+ The {@link android.content.ContentProvider} instance manages access
+ to a structured set of data by handling requests from other applications. All forms
+ of access eventually call {@link android.content.ContentResolver}, which then calls a concrete
+ method of {@link android.content.ContentProvider} to get access.
+</p>
+<h3 id="RequiredAccess">Required methods</h3>
+<p>
+ The abstract class {@link android.content.ContentProvider} defines six abstract methods that
+ you must implement as part of your own concrete subclass. All of these methods except
+ {@link android.content.ContentProvider#onCreate() onCreate()} are called by a client application
+ that is attempting to access your content provider:
+</p>
+<dl>
+ <dt>
+ {@link android.content.ContentProvider#query(Uri, String[], String, String[], String)
+ query()}
+ </dt>
+ <dd>
+ Retrieve data from your provider. Use the arguments to select the table to
+ query, the rows and columns to return, and the sort order of the result.
+ Return the data as a {@link android.database.Cursor} object.
+ </dd>
+ <dt>
+ {@link android.content.ContentProvider#insert(Uri, ContentValues) insert()}
+ </dt>
+ <dd>
+ Insert a new row into your provider. Use the arguments to select the
+ destination table and to get the column values to use. Return a content URI for the
+ newly-inserted row.
+ </dd>
+ <dt>
+ {@link android.content.ContentProvider#update(Uri, ContentValues, String, String[])
+ update()}
+ </dt>
+ <dd>
+ Update existing rows in your provider. Use the arguments to select the table and rows
+ to update and to get the updated column values. Return the number of rows updated.
+ </dd>
+ <dt>
+ {@link android.content.ContentProvider#delete(Uri, String, String[]) delete()}
+ </dt>
+ <dd>
+ Delete rows from your provider. Use the arguments to select the table and the rows to
+ delete. Return the number of rows deleted.
+ </dd>
+ <dt>
+ {@link android.content.ContentProvider#getType(Uri) getType()}
+ </dt>
+ <dd>
+ Return the MIME type corresponding to a content URI. This method is described in more
+ detail in the section <a href="#MIMETypes">Implementing Content Provider MIME Types</a>.
+ </dd>
+ <dt>
+ {@link android.content.ContentProvider#onCreate() onCreate()}
+ </dt>
+ <dd>
+ Initialize your provider. The Android system calls this method immediately after it
+ creates your provider. Notice that your provider is not created until a
+ {@link android.content.ContentResolver} object tries to access it.
+ </dd>
+</dl>
+<p>
+ Notice that these methods have the same signature as the identically-named
+ {@link android.content.ContentResolver} methods.
+</p>
+<p>
+ Your implementation of these methods should account for the following:
+</p>
+<ul>
+ <li>
+ All of these methods except {@link android.content.ContentProvider#onCreate() onCreate()}
+ can be called by multiple threads at once, so they must be thread-safe. To learn
+ more about multiple threads, see the topic
+ <a href="{@docRoot}guide/topics/fundamentals/processes-and-threads.html">
+ Processes and Threads</a>.
+ </li>
+ <li>
+ Avoid doing lengthy operations in {@link android.content.ContentProvider#onCreate()
+ onCreate()}. Defer initialization tasks until they are actually needed.
+ The section <a href="#OnCreate">Implementing the onCreate() method</a>
+ discusses this in more detail.
+ </li>
+ <li>
+ Although you must implement these methods, your code does not have to do anything except
+ return the expected data type. For example, you may want to prevent other applications
+ from inserting data into some tables. To do this, you can ignore the call to
+ {@link android.content.ContentProvider#insert(Uri, ContentValues) insert()} and return
+ 0.
+ </li>
+</ul>
+<h3 id="Query">Implementing the query() method</h3>
+<p>
+ The
+ {@link android.content.ContentProvider#query(Uri, String[], String, String[], String)
+ ContentProvider.query()} method must return a {@link android.database.Cursor} object, or if it
+ fails, throw an {@link java.lang.Exception}. If you are using an SQLite database as your data
+ storage, you can simply return the {@link android.database.Cursor} returned by one of the
+ <code>query()</code> methods of the {@link android.database.sqlite.SQLiteDatabase} class.
+ If the query does not match any rows, you should return a {@link android.database.Cursor}
+ instance whose {@link android.database.Cursor#getCount()} method returns 0.
+ You should return <code>null</code> only if an internal error occurred during the query process.
+</p>
+<p>
+ If you aren't using an SQLite database as your data storage, use one of the concrete subclasses
+ of {@link android.database.Cursor}. For example, the {@link android.database.MatrixCursor} class
+ implements a cursor in which each row is an array of {@link java.lang.Object}. With this class,
+ use {@link android.database.MatrixCursor#addRow(Object[]) addRow()} to add a new row.
+</p>
+<p>
+ Remember that the Android system must be able to communicate the {@link java.lang.Exception}
+ across process boundaries. Android can do this for the following exceptions that may be useful
+ in handling query errors:
+</p>
+<ul>
+ <li>
+ {@link java.lang.IllegalArgumentException} (You may choose to throw this if your provider
+ receives an invalid content URI)
+ </li>
+ <li>
+ {@link java.lang.NullPointerException}
+ </li>
+</ul>
+<h3 id="Insert">Implementing the insert() method</h3>
+<p>
+ The {@link android.content.ContentProvider#insert(Uri, ContentValues) insert()} method adds a
+ new row to the appropriate table, using the values in the {@link android.content.ContentValues}
+ argument. If a column name is not in the {@link android.content.ContentValues} argument, you
+ may want to provide a default value for it either in your provider code or in your database
+ schema.
+</p>
+<p>
+ This method should return the content URI for the new row. To construct this, append the new
+ row's <code>_ID</code> (or other primary key) value to the table's content URI, using
+ {@link android.content.ContentUris#withAppendedId(Uri, long) withAppendedId()}.
+</p>
+<h3 id="Delete">Implementing the delete() method</h3>
+<p>
+ The {@link android.content.ContentProvider#delete(Uri, String, String[]) delete()} method
+ does not have to physically delete rows from your data storage. If you are using a sync adapter
+ with your provider, you should consider marking a deleted row
+ with a "delete" flag rather than removing the row entirely. The sync adapter can
+ check for deleted rows and remove them from the server before deleting them from the provider.
+</p>
+<h3 id="Update">Implementing the update() method</h3>
+<p>
+ The {@link android.content.ContentProvider#update(Uri, ContentValues, String, String[])
+ update()} method takes the same {@link android.content.ContentValues} argument used by
+ {@link android.content.ContentProvider#insert(Uri, ContentValues) insert()}, and the
+ same <code>selection</code> and <code>selectionArgs</code> arguments used by
+ {@link android.content.ContentProvider#delete(Uri, String, String[]) delete()} and
+ {@link android.content.ContentProvider#query(Uri, String[], String, String[], String)
+ ContentProvider.query()}. This may allow you to re-use code between these methods.
+</p>
+<h3 id="OnCreate">Implementing the onCreate() method</h3>
+<p>
+ The Android system calls {@link android.content.ContentProvider#onCreate()
+ onCreate()} when it starts up the provider. You should perform only fast-running initialization
+ tasks in this method, and defer database creation and data loading until the provider actually
+ receives a request for the data. If you do lengthy tasks in
+ {@link android.content.ContentProvider#onCreate() onCreate()}, you will slow down your
+ provider's startup. In turn, this will slow down the response from the provider to other
+ applications.
+</p>
+<p>
+ For example, if you are using an SQLite database you can create
+ a new {@link android.database.sqlite.SQLiteOpenHelper} object in
+ {@link android.content.ContentProvider#onCreate() ContentProvider.onCreate()},
+ and then create the SQL tables the first time you open the database. To facilitate this, the
+ first time you call {@link android.database.sqlite.SQLiteOpenHelper#getWritableDatabase
+ getWritableDatabase()}, it automatically calls the
+ {@link android.database.sqlite.SQLiteOpenHelper#onCreate(SQLiteDatabase)
+ SQLiteOpenHelper.onCreate()} method.
+</p>
+<p>
+ The following two snippets demonstrate the interaction between
+ {@link android.content.ContentProvider#onCreate() ContentProvider.onCreate()} and
+ {@link android.database.sqlite.SQLiteOpenHelper#onCreate(SQLiteDatabase)
+ SQLiteOpenHelper.onCreate()}. The first snippet is the implementation of
+ {@link android.content.ContentProvider#onCreate() ContentProvider.onCreate()}:
+</p>
+<pre class="prettyprint">
+public class ExampleProvider extends ContentProvider
+
+ /*
+ * Defines a handle to the database helper object. The MainDatabaseHelper class is defined
+ * in a following snippet.
+ */
+ private MainDatabaseHelper mOpenHelper;
+
+ // Defines the database name
+ private static final String DBNAME = "mydb";
+
+ // Holds the database object
+ private SQLiteDatabase db;
+
+ public boolean onCreate() {
+
+ /*
+ * Creates a new helper object. This method always returns quickly.
+ * Notice that the database itself isn't created or opened
+ * until SQLiteOpenHelper.getWritableDatabase is called
+ */
+ mOpenHelper = new SQLiteOpenHelper(
+ getContext(), // the application context
+ DBNAME, // the name of the database)
+ null, // uses the default SQLite cursor
+ 1 // the version number
+ );
+
+ return true;
+ }
+
+ ...
+
+ // Implements the provider's insert method
+ public Cursor insert(Uri uri, ContentValues values) {
+ // Insert code here to determine which table to open, handle error-checking, and so forth
+
+ ...
+
+ /*
+ * Gets a writeable database. This will trigger its creation if it doesn't already exist.
+ *
+ */
+ db = mOpenHelper.getWritableDatabase();
+ }
+}
+</pre>
+<p>
+ The next snippet is the implementation of
+ {@link android.database.sqlite.SQLiteOpenHelper#onCreate(SQLiteDatabase)
+ SQLiteOpenHelper.onCreate()}, including a helper class:
+</p>
+<pre class="prettyprint">
+...
+// A string that defines the SQL statement for creating a table
+private static final String SQL_CREATE_MAIN = "CREATE TABLE " +
+ "main " + // Table's name
+ "(" + // The columns in the table
+ " _ID INTEGER PRIMARY KEY, " +
+ " WORD TEXT"
+ " FREQUENCY INTEGER " +
+ " LOCALE TEXT )";
+...
+/**
+ * Helper class that actually creates and manages the provider's underlying data repository.
+ */
+protected static final class MainDatabaseHelper extends SQLiteOpenHelper {
+
+ /*
+ * Instantiates an open helper for the provider's SQLite data repository
+ * Do not do database creation and upgrade here.
+ */
+ MainDatabaseHelper(Context context) {
+ super(context, DBNAME, null, 1);
+ }
+
+ /*
+ * Creates the data repository. This is called when the provider attempts to open the
+ * repository and SQLite reports that it doesn't exist.
+ */
+ public void onCreate(SQLiteDatabase db) {
+
+ // Creates the main table
+ db.execSQL(SQL_CREATE_MAIN);
+ }
+}
+</pre>
+
+
+<!-- Implementing ContentProvider MIME Types -->
+<h2 id="MIMETypes">Implementing ContentProvider MIME Types</h2>
+<p>
+ The {@link android.content.ContentProvider} class has two methods for returning MIME types:
+</p>
+<dl>
+ <dt>
+ {@link android.content.ContentProvider#getType(Uri) getType()}
+ </dt>
+ <dd>
+ One of the required methods that you must implement for any provider.
+ </dd>
+ <dt>
+ {@link android.content.ContentProvider#getStreamTypes(Uri, String) getStreamTypes()}
+ </dt>
+ <dd>
+ A method that you're expected to implement if your provider offers files.
+ </dd>
+</dl>
+<h3 id="TableMIMETypes">MIME types for tables</h3>
+<p>
+ The {@link android.content.ContentProvider#getType(Uri) getType()} method returns a
+ {@link java.lang.String} in MIME format that describes the type of data returned by the content
+ URI argument. The {@link android.net.Uri} argument can be a pattern rather than a specific URI;
+ in this case, you should return the type of data associated with content URIs that match the
+ pattern.
+</p>
+<p>
+ For common types of data such as as text, HTML, or JPEG,
+ {@link android.content.ContentProvider#getType(Uri) getType()} should return the standard
+ MIME type for that data. A full list of these standard types is available on the
+ <a href="http://www.iana.org/assignments/media-types/index.htm">IANA MIME Media Types</a>
+ website.
+</p>
+<p>
+ For content URIs that point to a row or rows of table data,
+ {@link android.content.ContentProvider#getType(Uri) getType()} should return
+ a MIME type in Android's vendor-specific MIME format:
+</p>
+<ul>
+ <li>
+ Type part: <code>vnd</code>
+ </li>
+ <li>
+ Subtype part:
+ <ul>
+ <li>
+ If the URI pattern is for a single row: <code>android.cursor.<strong>item</strong>/</code>
+ </li>
+ <li>
+ If the URI pattern is for more than one row: <code>android.cursor.<strong>dir</strong>/</code>
+ </li>
+ </ul>
+ </li>
+ <li>
+ Provider-specific part: <code>vnd.<name></code>.<code><type></code>
+ <p>
+ You supply the <code><name></code> and <code><type></code>.
+ The <code><name></code> value should be globally unique,
+ and the <code><type></code> value should be unique to the corresponding URI
+ pattern. A good choice for <code><name></code> is your company's name or
+ some part of your application's Android package name. A good choice for the
+ <code><type></code> is a string that identifies the table associated with the
+ URI.
+ </p>
+
+ </li>
+</ul>
+<p>
+ For example, if a provider's authority is
+ <code>com.example.app.provider</code>, and it exposes a table named
+ <code>table1</code>, the MIME type for multiple rows in <code>table1</code> is:
+</p>
+<pre>
+vnd.android.cursor.<strong>dir</strong>/vnd.com.example.provider.table1
+</pre>
+<p>
+ For a single row of <code>table1</code>, the MIME type is:
+</p>
+<pre>
+vnd.android.cursor.<strong>item</strong>/vnd.com.example.provider.table1
+</pre>
+<h3 id="FileMIMETypes">MIME types for files</h3>
+<p>
+ If your provider offers files, implement
+ {@link android.content.ContentProvider#getStreamTypes(Uri, String) getStreamTypes()}.
+ The method returns a {@link java.lang.String} array of MIME types for the files your provider
+ can return for a given content URI. You should filter the MIME types you offer by the MIME type
+ filter argument, so that you return only those MIME types that the client wants to handle.
+</p>
+<p>
+ For example, consider a provider that offers photo images as files in <code>.jpg</code>,
+ <code>.png</code>, and <code>.gif</code> format.
+ If an application calls {@link android.content.ContentResolver#getStreamTypes(Uri, String)
+ ContentResolver.getStreamTypes()} with the filter string <code>image/*</code> (something that
+ is an "image"),
+ then the {@link android.content.ContentProvider#getStreamTypes(Uri, String)
+ ContentProvider.getStreamTypes()} method should return the array:
+</p>
+<pre>
+{ "image/jpeg", "image/png", "image/gif"}
+</pre>
+<p>
+ If the app is only interested in <code>.jpg</code> files, then it can call
+ {@link android.content.ContentResolver#getStreamTypes(Uri, String)
+ ContentResolver.getStreamTypes()} with the filter string <code>*\/jpeg</code>, and
+ {@link android.content.ContentProvider#getStreamTypes(Uri, String)
+ ContentProvider.getStreamTypes()} should return:
+<pre>
+{"image/jpeg"}
+</pre>
+<p>
+ If your provider doesn't offer any of the MIME types requested in the filter string,
+ {@link android.content.ContentProvider#getStreamTypes(Uri, String) getStreamTypes()}
+ should return <code>null</code>.
+</p>
+
+
+<!-- Implementing a Contract Class -->
+<h2 id="ContractClass">Implementing a Contract Class</h2>
+<p>
+ A contract class is a <code>public final</code> class that contains constant definitions for the
+ URIs, column names, MIME types, and other meta-data that pertain to the provider. The class
+ establishes a contract between the provider and other applications by ensuring that the provider
+ can be correctly accessed even if there are changes to the actual values of URIs, column names,
+ and so forth.
+</p>
+<p>
+ A contract class also helps developers because it usually has mnemonic names for its constants,
+ so developers are less likely to use incorrect values for column names or URIs. Since it's a
+ class, it can contain Javadoc documentation. Integrated development environments such as
+ Eclipse can auto-complete constant names from the contract class and display Javadoc for the
+ constants.
+</p>
+<p>
+ Developers can't access the contract class's class file from your application, but they can
+ statically compile it into their application from a <code>.jar</code> file you provide.
+</p>
+<p>
+ The {@link android.provider.ContactsContract} class and its nested classes are examples of
+ contract classes.
+</p>
+<h2 id="Permissions">Implementing Content Provider Permissions</h2>
+<p>
+ Permissions and access for all aspects of the Android system are described in detail in the
+ topic <a href="{@docRoot}guide/topics/security/security.html">Security and Permissions</a>.
+ The topic <a href="{@docRoot}guide/topics/data/data-storage.html">Data Storage</a> also
+ described the security and permissions in effect for various types of storage.
+ In brief, the important points are:
+</p>
+<ul>
+ <li>
+ By default, data files stored on the device's internal storage are private to your
+ application and provider.
+ </li>
+ <li>
+ {@link android.database.sqlite.SQLiteDatabase} databases you create are private to your
+ application and provider.
+ </li>
+ <li>
+ By default, data files that you save to external storage are <em>public</em> and
+ <em>world-readable</em>. You can't use a content provider to restrict access to files in
+ external storage, because other applications can use other API calls to read and write them.
+ </li>
+ <li>
+ The method calls for opening or creating files or SQLite databases on your device's internal
+ storage can potentially give both read and write access to all other applications. If you
+ use an internal file or database as your provider's repository, and you give it
+ "world-readable" or "world-writeable" access, the permissions you set for your provider in
+ its manifest won't protect your data. The default access for files and databases in
+ internal storage is "private", and for your provider's repository you shouldn't change this.
+ </li>
+</ul>
+<p>
+ If you want to use content provider permissions to control access to your data, then you should
+ store your data in internal files, SQLite databases, or the "cloud" (for example,
+ on a remote server), and you should keep files and databases private to your application.
+</p>
+<h3>Implementing permissions</h3>
+<p>
+ All applications can read from or write to your provider, even if the underlying data is
+ private, because by default your provider does not have permissions set. To change this,
+ set permissions for your provider in your manifest file, using attributes or child
+ elements of the <code><a href="{@docRoot}guide/topics/manifest/provider-element.html">
+ <provider></a></code> element. You can set permissions that apply to the entire provider,
+ or to certain tables, or even to certain records, or all three.
+</p>
+<p>
+ You define permissions for your provider with one or more
+ <code><a href="{@docRoot}guide/topics/manifest/permission-element.html">
+ <permission></a></code> elements in your manifest file. To make the
+ permission unique to your provider, use Java-style scoping for the
+ <code><a href="{@docRoot}guide/topics/manifest/permission-element.html#nm">
+ android:name</a></code> attribute. For example, name the read permission
+ <code>com.example.app.provider.permission.READ_PROVIDER</code>.
+
+</p>
+<p>
+ The following list describes the scope of provider permissions, starting with the
+ permissions that apply to the entire provider and then becoming more fine-grained.
+ More fine-grained permissions take precedence over ones with larger scope:
+</p>
+<dl>
+ <dt>
+ Single read-write provider-level permission
+ </dt>
+ <dd>
+ One permission that controls both read and write access to the entire provider, specified
+ with the <code><a href="{@docRoot}guide/topics/manifest/provider-element.html#prmsn">
+ android:permission</a></code> attribute of the
+ <code><a href="{@docRoot}guide/topics/manifest/provider-element.html">
+ <provider></a></code> element.
+ </dd>
+ <dt>
+ Separate read and write provider-level permission
+ </dt>
+ <dd>
+ A read permission and a write permission for the entire provider. You specify them
+ with the <code><a href="{@docRoot}guide/topics/manifest/provider-element.html#rprmsn">
+ android:readPermission</a></code> and
+ <code><a href="{@docRoot}guide/topics/manifest/provider-element.html#wprmsn">
+ android:writePermission</a></code> attributes of the
+ <code><a href="{@docRoot}guide/topics/manifest/provider-element.html">
+ <provider></a></code> element. They take precedence over the permission required by
+ <code><a href="{@docRoot}guide/topics/manifest/provider-element.html#prmsn">
+ android:permission</a></code>.
+ </dd>
+ <dt>
+ Path-level permission
+ </dt>
+ <dd>
+ Read, write, or read/write permission for a content URI in your provider. You specify
+ each URI you want to control with a
+ <code><a href="{@docRoot}guide/topics/manifest/path-permission-element.html">
+ <path-permission></a></code> child element of the
+ <code><a href="{@docRoot}guide/topics/manifest/provider-element.html">
+ <provider></a></code> element. For each content URI you specify, you can specify a
+ read/write permission, a read permission, or a write permission, or all three. The read and
+ write permissions take precedence over the read/write permission. Also, path-level
+ permission takes precedence over provider-level permissions.
+ </dd>
+ <dt>
+ Temporary permission
+ </dt>
+ <dd>
+ A permission level that grants temporary access to an application, even if the application
+ doesn't have the permissions that are normally required. The temporary
+ access feature reduces the number of permissions an application has to request in
+ its manifest. When you turn on temporary permissions, the only applications that need
+ "permanent" permissions for your provider are ones that continually access all
+ your data.
+ <p>
+ Consider the permissions you need to implement an email provider and app, when you
+ want to allow an outside image viewer application to display photo attachments from your
+ provider. To give the image viewer the necessary access without requiring permissions,
+ set up temporary permissions for content URIs for photos. Design your email app so
+ that when the user wants to display a photo, the app sends an intent containing the
+ photo's content URI and permission flags to the image viewer. The image viewer can
+ then query your email provider to retrieve the photo, even though the viewer doesn't
+ have the normal read permission for your provider.
+ </p>
+ <p>
+ To turn on temporary permissions, either set the
+ <code><a href="{@docRoot}guide/topics/manifest/provider-element.html#gprmsn">
+ android:grantUriPermissions</a></code> attribute of the
+ <code><a href="{@docRoot}guide/topics/manifest/provider-element.html">
+ <provider></a></code> element, or add one or more
+ <code><a href="{@docRoot}guide/topics/manifest/grant-uri-permission-element.html">
+ <grant-uri-permission></a></code> child elements to your
+ <code><a href="{@docRoot}guide/topics/manifest/provider-element.html">
+ <provider></a></code> element. If you use temporary permissions, you have to call
+ {@link android.content.Context#revokeUriPermission(Uri, int)
+ Context.revokeUriPermission()} whenever you remove support for a content URI from your
+ provider, and the content URI is associated with a temporary permission.
+ </p>
+ <p>
+ The attribute's value determines how much of your provider is made accessible.
+ If the attribute is set to <code>true</code>, then the system will grant temporary
+ permission to your entire provider, overriding any other permissions that are required
+ by your provider-level or path-level permissions.
+ </p>
+ <p>
+ If this flag is set to <code>false</code>, then you must add
+ <code><a href="{@docRoot}guide/topics/manifest/grant-uri-permission-element.html">
+ <grant-uri-permission></a></code> child elements to your
+ <code><a href="{@docRoot}guide/topics/manifest/provider-element.html">
+ <provider></a></code> element. Each child element specifies the content URI or
+ URIs for which temporary access is granted.
+ </p>
+ <p>
+ To delegate temporary access to an application, an intent must contain
+ the {@link android.content.Intent#FLAG_GRANT_READ_URI_PERMISSION} or the
+ {@link android.content.Intent#FLAG_GRANT_WRITE_URI_PERMISSION} flags, or both. These
+ are set with the {@link android.content.Intent#setFlags(int) setFlags()} method.
+ </p>
+ <p>
+ If the <code><a href="{@docRoot}guide/topics/manifest/provider-element.html#gprmsn">
+ android:grantUriPermissions</a></code> attribute is not present, it's assumed to be
+ <code>false</code>.
+ </p>
+ </dd>
+</dl>
+
+
+
+<!-- The Provider Element -->
+<h2 id="ProviderElement">The <provider> Element</h2>
+<p>
+ Like {@link android.app.Activity} and {@link android.app.Service} components,
+ a subclass of {@link android.content.ContentProvider}
+ must be defined in the manifest file for its application, using the
+ <code><a href="{@docRoot}guide/topics/manifest/provider-element.html">
+ <provider></a></code> element. The Android system gets the following information from
+ the element:
+<dl>
+ <dt>
+ Authority
+ (<a href="{@docRoot}guide/topics/manifest/provider-element.html#auth">{@code
+ android:authorities}</a>)
+ </dt>
+ <dd>
+ Symbolic names that identify the entire provider within the system. This
+ attribute is described in more detail in the section
+ <a href="#ContentURI">Designing Content URIs</a>.
+ </dd>
+ <dt>
+ Provider class name
+ (<code>
+<a href="{@docRoot}guide/topics/manifest/provider-element.html#nm">android:name</a>
+ </code>)
+ </dt>
+ <dd>
+ The class that implements {@link android.content.ContentProvider}. This class is
+ described in more detail in the section
+ <a href="#ContentProvider">Implementing the ContentProvider Class</a>.
+ </dd>
+ <dt>
+ Permissions
+ </dt>
+ <dd>
+ Attributes that specify the permissions that other applications must have in order to access
+ the provider's data:
+ <ul>
+ <li>
+ <code><a href="{@docRoot}guide/topics/manifest/provider-element.html#gprmsn">
+ android:grantUriPermssions</a></code>: Temporary permission flag.
+ </li>
+ <li>
+ <code><a href="{@docRoot}guide/topics/manifest/provider-element.html#prmsn">
+ android:permission</a></code>: Single provider-wide read/write permission.
+ </li>
+ <li>
+ <code><a href="{@docRoot}guide/topics/manifest/provider-element.html#rprmsn">
+ android:readPermission</a></code>: Provider-wide read permission.
+ </li>
+ <li>
+ <code><a href="{@docRoot}guide/topics/manifest/provider-element.html#wprmsn">
+ android:writePermission</a></code>: Provider-wide write permission.
+ </li>
+ </ul>
+ <p>
+ Permissions and their corresponding attributes are described in more
+ detail in the section
+ <a href="#Permissions">Implementing Content Provider Permissions</a>.
+ </p>
+ </dd>
+ <dt>
+ Startup and control attributes
+ </dt>
+ <dd>
+ These attributes determine how and when the Android system starts the provider, the
+ process characteristics of the provider, and other run-time settings:
+ <ul>
+ <li>
+ <code><a href="{@docRoot}guide/topics/manifest/provider-element.html#enabled">
+ android:enabled</a></code>: Flag allowing the system to start the provider.
+ </li>
+ <li>
+ <code><a href="{@docRoot}guide/topics/manifest/provider-element.html#exported">
+ android:exported</a></code>: Flag allowing other applications to use this provider.
+ </li>
+ <li>
+ <code><a href="{@docRoot}guide/topics/manifest/provider-element.html#init">
+ android:initOrder</a></code>: The order in which this provider should be started,
+ relative to other providers in the same process.
+ </li>
+ <li>
+ <code><a href="{@docRoot}guide/topics/manifest/provider-element.html#multi">
+ android:multiProcess</a></code>: Flag allowing the system to start the provider
+ in the same process as the calling client.
+ </li>
+ <li>
+ <code><a href="{@docRoot}guide/topics/manifest/provider-element.html#proc">
+ android:process</a></code>: The name of the process in which the provider should
+ run.
+ </li>
+ <li>
+ <code><a href="{@docRoot}guide/topics/manifest/provider-element.html#sync">
+ android:syncable</a></code>: Flag indicating that the provider's data is to be
+ sync'ed with data on a server.
+ </li>
+ </ul>
+ <p>
+ The attributes are fully documented in the dev guide topic for the
+ <code><a href="{@docRoot}guide/topics/manifest/provider-element.html">
+ <provider></a></code>
+ element.
+ </p>
+ </dd>
+ <dt>
+ Informational attributes
+ </dt>
+ <dd>
+ An optional icon and label for the provider:
+ <ul>
+ <li>
+ <code><a href="{@docRoot}guide/topics/manifest/provider-element.html#icon">
+ android:icon</a></code>: A drawable resource containing an icon for the provider.
+ The icon appears next to the provider's label in the list of apps in
+ <em>Settings</em> > <em>Apps</em> > <em>All</em>.
+ </li>
+ <li>
+ <code><a href="{@docRoot}guide/topics/manifest/provider-element.html#label">
+ android:label</a></code>: An informational label describing the provider or its
+ data, or both. The label appears in the list of apps in
+ <em>Settings</em> > <em>Apps</em> > <em>All</em>.
+ </li>
+ </ul>
+ <p>
+ The attributes are fully documented in the dev guide topic for the
+ <code><a href="{@docRoot}guide/topics/manifest/provider-element.html">
+ <provider></a></code> element.
+ </p>
+ </dd>
+</dl>
+
+<!-- Intent Access -->
+<h2 id="Intents">Intents and Data Access</h2>
+<p>
+ Applications can access a content provider indirectly with an {@link android.content.Intent}.
+ The application does not call any of the methods of {@link android.content.ContentResolver} or
+ {@link android.content.ContentProvider}. Instead, it sends an intent that starts an activity,
+ which is often part of the provider's own application. The destination activity is in charge of
+ retrieving and displaying the data in its UI. Depending on the action in the intent, the
+ destination activity may also prompt the user to make modifications to the provider's data.
+ An intent may also contain "extras" data that the destination activity displays
+ in the UI; the user then has the option of changing this data before using it to modify the
+ data in the provider.
+</p>
+<p>
+
+</p>
+<p>
+ You may want to use intent access to help ensure data integrity. Your provider may depend
+ on having data inserted, updated, and deleted according to strictly defined business logic. If
+ this is the case, allowing other applications to directly modify your data may lead to
+ invalid data. If you want developers to use intent access, be sure to document it thoroughly.
+ Explain to them why intent access using your own application's UI is better than trying to
+ modify the data with their code.
+</p>
+<p>
+ Handling an incoming intent that wishes to modify your provider's data is no different from
+ handling other intents. You can learn more about using intents by reading the topic
+ <a href="{@docRoot}guide/topics/intents/intents-filters.html">Intents and Intent Filters</a>.
+</p>
diff --git a/docs/html/guide/topics/providers/content-providers.jd b/docs/html/guide/topics/providers/content-providers.jd
index 95331ce..1707f03 100644
--- a/docs/html/guide/topics/providers/content-providers.jd
+++ b/docs/html/guide/topics/providers/content-providers.jd
@@ -1,922 +1,96 @@
page.title=Content Providers
@jd:body
-
<div id="qv-wrapper">
<div id="qv">
-<h2>In this document</h2>
+
+<!-- In this document -->
+<h2>Topics</h2>
<ol>
-<li><a href="#basics">Content provider basics</a></li>
-<li><a href="#querying">Querying a content provider</a></li>
-<li><a href="#modifying">Modifying data in a provider</a></li>
-<li><a href="#creating">Creating a content provider</a></li>
-<li><a href="#urisum">Content URI summary</a></li>
+ <li>
+ <a href="{@docRoot}guide/topics/providers/content-provider-basics.html">
+ Content Provider Basics</a>
+ </li>
+ <li>
+ <a href="{@docRoot}guide/topics/providers/content-provider-creating.html">
+ Creating a Content Provider</a>
+ </li>
+ <li>
+ <a href="{@docRoot}guide/topics/providers/calendar-provider.html">Calendar Provider</a>
+ </li>
</ol>
-<h2>Key classes</h2>
-<ol>
-<li>{@link android.content.ContentProvider}</li>
-<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>
+ <!-- Related Samples -->
+<h2>Related Samples</h2>
+ <ol>
+ <li>
+ <a href="{@docRoot}resources/samples/ContactManager/index.html">
+ Contact Manager</a> application
+ </li>
+ <li>
+ <a
+ href="{@docRoot}resources/samples/ApiDemos/src/com/example/android/apis/view/List2.html">
+ "Cursor (People)"
+ </a>
+ </li>
+ <li>
+ <a
+ href="{@docRoot}resources/samples/ApiDemos/src/com/example/android/apis/view/List7.html">
+ "Cursor (Phones)"</a>
+ </li>
+ </ol>
</div>
</div>
-
<p>
-Content providers store and retrieve data and make it accessible to all
-applications. They're the only way to share data across applications; there's
-no common storage area that all Android packages can access.
-</p>
-
-<p>
-Android ships with a number of content providers for common data types
-(audio, video, images, personal contact information, and so on). You can
-see some of them listed in the {@link android.provider android.provider}
-package. You can query these providers for the data they contain (although,
-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}
-subclass) or you can add the data to an existing provider — if there's
-one that controls the same type of data and you have permission to write to it.
-</p>
-
-<p>
-This document is an introduction to using content providers. After a
-brief discussion of the fundamentals, it explores how to query a content
-provider, how to modify data controlled by a provider, and how to create
-a content provider of your own.
-</p>
-
-
-<h2><a name="basics"></a>Content Provider Basics</h2>
-
-<p>
-How a content provider actually stores its data under the covers is
-up to its designer. But all content providers implement a common interface
-for querying the provider and returning results — as well as for
-adding, altering, and deleting data.
-</p>
-
-<p>
-It's an interface that clients use indirectly, most generally through
-{@link android.content.ContentResolver} objects. You get a ContentResolver
-by calling <code>{@link android.content.Context#getContentResolver
-getContentResolver()}</code> from within the implementation of an Activity
-or other application component:
-</p>
-
-<pre>ContentResolver cr = getContentResolver();</pre>
-
-<p>
-You can then use the ContentResolver's methods to interact with whatever
-content providers you're interested in.
-</p>
-
-<p>
-When a query is initiated, the Android system identifies the content provider
-that's the target of the query and makes sure that it is up and running.
-The system instantiates all ContentProvider objects; you never need to do it
-on your own. In fact, you never deal directly with ContentProvider objects
-at all. Typically, there's just a single instance of each type of
-ContentProvider. But it can communicate with multiple ContentResolver objects
-in different applications and processes. The interaction between processes is
-handled by the ContentResolver and ContentProvider classes.
-</p>
-
-
-<h3>The data model</h3>
-
-<p>
-Content providers expose their data as a simple table on a database model,
-where each row is a record and each column is data of a particular type
-and meaning. For example, information about people and their phone numbers
-might be exposed as follows:
-</p>
-
-<table>
- <tr>
- <th scope="col">_ID</th>
- <th scope="col">NUMBER</th>
- <th scope="col">NUMBER_KEY</th>
- <th scope="col">LABEL</th>
- <th scope="col">NAME</th>
- <th scope="col">TYPE</th>
- </tr>
- <tr>
- <td>13</td>
- <td>(425) 555 6677</td>
- <td>425 555 6677</td>
- <td>Kirkland office</td>
- <td>Bully Pulpit</td>
- <td>{@code TYPE_WORK}</td>
- </tr>
- <tr>
- <td>44</td>
- <td>(212) 555-1234</td>
- <td>212 555 1234</td>
- <td>NY apartment</td>
- <td>Alan Vain</td>
- <td>{@code TYPE_HOME}</td>
- </tr>
- <tr>
- <td>45</td>
- <td>(212) 555-6657</td>
- <td>212 555 6657</td>
- <td>Downtown office</td>
- <td>Alan Vain</td>
- <td>{@code TYPE_MOBILE}</td>
- </tr>
- <tr>
- <td>53</td>
- <td>201.555.4433</td>
- <td>201 555 4433</td>
- <td>Love Nest</td>
- <td>Rex Cars</td>
- <td>{@code TYPE_HOME}</td>
- </tr>
-</table>
-
-<p>
-Every record includes a numeric {@code _ID} field that uniquely identifies
-the record within the table. IDs can be used to match records in related
-tables — for example, to find a person's phone number in one table
-and pictures of that person in another.
-</p>
-
-<p>
-A query returns a {@link android.database.Cursor} object that can move from
-record to record and column to column to read the contents of each field.
-It has specialized methods for reading each type of data. So, to read a field,
-you must know what type of data the field contains. (There's more on query
-results and Cursor objects later.)
-</p>
-
-
-<h3><a name="uri"></a>URIs</h3>
-
-<p>
-Each 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 "{@code content://}". The {@code content:}
-scheme identifies the data as being controlled by a content provider.
-</p>
-
-<p>
-If you're defining a content provider, it's a good idea to also define a
-constant for its URI, to simplify client code and make future updates cleaner.
-Android defines {@code CONTENT_URI} constants for all the providers that come
-with the platform. For example, the URI for the table that matches
-phone numbers to people and the URI for the table that holds pictures of
-people (both controlled by the Contacts content provider) are:
-</p>
-
-<p>
-<p style="margin-left: 2em">{@code android.provider.Contacts.Phones.CONTENT_URI}
-<br/>{@code android.provider.Contacts.Photos.CONTENT_URI}
+ Content providers manage access to a structured set of data. They encapsulate the
+ data, and provide mechanisms for defining data security. Content providers are the standard
+ interface that connects data in one process with code running in another process.
</p>
-
<p>
-The URI constant is used in all interactions with the content provider.
-Every {@link android.content.ContentResolver} method takes the URI
-as its first argument. It's what identifies which provider the ContentResolver
-should talk to and which table of the provider is being targeted.
-</p>
-
-
-<h2><a name="querying"></a>Querying a Content Provider</h2>
-
-<p>
-You need three pieces of information to query a content provider:
-</p>
-
-<ul>
-<li>The URI that identifies the provider</li>
-<li>The names of the data fields you want to receive</li>
-<li>The data types for those fields</li>
-</ul>
-
-<p>
-If you're querying a particular record, you also need the ID for that record.
-</p>
-
-
-<h3>Making the query</h3>
-
-<p>
-To query a content provider, you can use either the
-<code>{@link android.content.ContentResolver#query ContentResolver.query()}</code>
-method or the <code>{@link android.app.Activity#managedQuery
-Activity.managedQuery()}</code> method.
-Both methods take the same set of arguments, and both return a
-Cursor object. However, {@code managedQuery()}
-causes the activity to manage the life cycle of the Cursor. A managed Cursor
-handles all of the niceties, such as unloading itself when the activity pauses,
-and requerying itself when the activity restarts. You can ask an Activity to
-begin managing an unmanaged Cursor object for you by calling
-<code>{@link android.app.Activity#startManagingCursor
-Activity.startManagingCursor()}</code>.
-</p>
-
-<p>
-The first argument to either <code>{@link android.content.ContentResolver#query query()}</code>
-or <code>{@link android.app.Activity#managedQuery managedQuery()}</code> is the provider URI
-— the {@code CONTENT_URI} constant that identifies a particular
-ContentProvider and data set (see <a href="#uri">URIs</a> earlier).
-</p>
-
-<p>
-To restrict a query to just one record, you can append the {@code _ID} value for
-that record to the URI — that is, place a string matching the ID as the
-last segment of the path part of the URI. For example, if the ID is 23,
-the URI would be:
-</p>
-
-<p style="margin-left: 2em">{@code content://. . . ./23}</p>
-
-<p>
-There are some helper methods, particularly
-<code>{@link android.content.ContentUris#withAppendedId
-ContentUris.withAppendedId()}</code> and <code>{@link
-android.net.Uri#withAppendedPath Uri.withAppendedPath()}</code>,
-that make it easy to append an ID to a URI. Both are static methods that return
-a Uri object with the ID added. So, for example, if you were looking for record
-23 in the database of people contacts, you might construct a query as follows:
-</p>
-
-<pre>
-import android.provider.Contacts.People;
-import android.content.ContentUris;
-import android.net.Uri;
-import android.database.Cursor;
-
-// Use the ContentUris method to produce the base URI for the contact with _ID == 23.
-Uri myPerson = ContentUris.withAppendedId(People.CONTENT_URI, 23);
-
-// Alternatively, use the Uri method to produce the base URI.
-// It takes a string rather than an integer.
-Uri myPerson = Uri.withAppendedPath(People.CONTENT_URI, "23");
-
-// Then query for this specific record:
-Cursor cur = managedQuery(myPerson, null, null, null, null);
-</pre>
-
-<p>
-The other arguments to the <code>{@link android.content.ContentResolver#query query()}</code>
-and <code>{@link android.app.Activity#managedQuery managedQuery()}</code> methods delimit
-the query in more detail. They are:
-</p>
-
-<ul>
-<li>The names of the data columns that should be returned. A {@code null}
-value returns all columns. Otherwise, only columns that are listed by name
-are returned. All the content providers that come with the platform define
-constants for their columns. For example, the
-{@link android.provider.Contacts.Phones android.provider.Contacts.Phones} class
-defines constants for the names of the columns in the phone table illustrated
-earlier — {@code _ID}, {@code NUMBER}, {@code NUMBER_KEY}, {@code NAME},
-and so on.</li>
-
-<li><p>A filter detailing which rows to return, formatted as an SQL {@code WHERE}
-clause (excluding the {@code WHERE} itself). A {@code null} value returns
-all rows (unless the URI limits the query to a single record).</p></li>
-
-<li><p>Selection arguments.</p></li>
-
-<li><p>A sorting order for the rows that are returned, formatted as an SQL
-{@code ORDER BY} clause (excluding the {@code ORDER BY} itself). A {@code null}
-value returns the records in the default order for the table, which may be
-unordered.</p></li>
-</ul>
-
-<p>
-Let's look at an example query to retrieve a list of contact names and their
-primary phone numbers:
+ When you want to access data in a content provider, you use the
+ {@link android.content.ContentResolver} object in your
+ application's {@link android.content.Context} to communicate with the provider as a client.
+ The {@link android.content.ContentResolver} object communicates with the provider object, an
+ instance of a class that implements {@link android.content.ContentProvider}. The provider
+ object receives data requests from clients, performs the requested action, and
+ returns the results.
</p>
-
-<pre>
-import android.provider.Contacts.People;
-import android.database.Cursor;
-
-// Form an array specifying which columns to return.
-String[] projection = new String[] {
- People._ID,
- People._COUNT,
- People.NAME,
- People.NUMBER
- };
-
-// Get the base URI for the People table in the Contacts content provider.
-Uri contacts = People.CONTENT_URI;
-
-// Make the query.
-Cursor managedCursor = managedQuery(contacts,
- projection, // Which columns to return
- null, // Which rows to return (all rows)
- null, // Selection arguments (none)
- // Put the results in ascending order by name
- People.NAME + " ASC");
-</pre>
-
<p>
-This query retrieves data from the People table of the Contacts content
-provider. It gets the name, primary phone number, and unique record ID for
-each contact. It also reports the number of records that are returned as
-the {@code _COUNT} field of each record.
+ You don't need to develop your own provider if you don't intend to share your data with
+ other applications. However, you do need your own provider to provide custom search
+ suggestions in your own application. You also need your own provider if you want to copy and
+ paste complex data or files from your application to other applications.
</p>
-
<p>
-The constants for the names of the columns are defined in various interfaces
-— {@code _ID} and {@code _COUNT} in
-{@link android.provider.BaseColumns BaseColumns}, {@code NAME} in {@link android.provider.Contacts.PeopleColumns PeopleColumns}, and {@code NUMBER}
-in {@link android.provider.Contacts.PhonesColumns PhoneColumns}. The
-{@link android.provider.Contacts.People Contacts.People} class implements
-each of these interfaces, which is why the code example above could refer
-to them using just the class name.
+ Android itself includes content providers that manage data such as audio, video, images, and
+ personal contact information. You can see some of them listed in the reference
+ documentation for the
+ <code><a href="{@docRoot}reference/android/provider/package-summary.html">android.provider</a>
+ </code> package. With some restrictions, these providers are accessible to any Android
+ application.
+</p><p>
+ The following topics describe content providers in more detail:
</p>
-
-
-<h3>What a query returns</h3>
-
-<p>
-A query returns a set of zero or more database records. The names of the
-columns, their default order, and their data types are specific to each
-content provider.
-But every provider has an {@code _ID} column, which holds a unique numeric
-ID for each record. Every provider can also report the number
-of records returned as the {@code _COUNT} column; its value
-is the same for all rows.
-</p>
-
-<p>
-Here is an example result set for the query in the previous section:
-</p>
-
-<table border="1">
- <tbody>
- <tr>
- <th scope="col">_ID</th>
- <th scope="col">_COUNT</th>
- <th scope="col">NAME</th>
- <th scope="col">NUMBER</th>
- </tr>
- <tr>
- <td>44</td>
- <td>3</td>
- <td>Alan Vain</td>
- <td>212 555 1234</td>
- </tr>
- <tr>
- <td>13</td>
- <td>3</td>
- <td>Bully Pulpit</td>
- <td>425 555 6677</td>
- </tr>
- <tr>
- <td>53</td>
- <td>3</td>
- <td>Rex Cars</td>
- <td>201 555 4433</td>
- </tr>
- </tbody>
-</table>
-
-<p>
-The retrieved data is exposed by a {@link android.database.Cursor Cursor}
-object that can be used to iterate backward or forward through the result
-set. You can use this object only to read the data. To add, modify, or
-delete data, you must use a ContentResolver object.
-</p>
-
-
-<h3>Reading retrieved data</h3>
-
-<p>
-The Cursor object returned by a query provides access to a recordset of
-results. If you have queried for a specific record by ID, this set will
-contain only one value. Otherwise, it can contain multiple values.
-(If there are no matches, it can also be empty.) You
-can read data from specific fields in the record, but you must know the
-data type of the field, because the Cursor object has a separate method
-for reading each type of data — such as <code>{@link
-android.database.Cursor#getString getString()}</code>, <code>{@link
-android.database.Cursor#getInt getInt()}</code>, and <code>{@link
-android.database.Cursor#getFloat getFloat()}</code>.
-(However, for most types, if you call the method for reading strings,
-the Cursor object will give you the String representation of the data.)
-The Cursor lets you request the column name from the index of the column,
-or the index number from the column name.
-</p>
-
-<p>
-The following snippet demonstrates reading names and phone numbers from
-the query illustrated earlier:
-</p>
-
-<pre>
-import android.provider.Contacts.People;
-
-private void getColumnData(Cursor cur){
- if (cur.moveToFirst()) {
-
- String name;
- String phoneNumber;
- int nameColumn = cur.getColumnIndex(People.NAME);
- int phoneColumn = cur.getColumnIndex(People.NUMBER);
- String imagePath;
-
- do {
- // Get the field values
- name = cur.getString(nameColumn);
- phoneNumber = cur.getString(phoneColumn);
-
- // Do something with the values.
- ...
-
- } while (cur.moveToNext());
-
- }
-}
-</pre>
-
-<p>
-If a query can return binary data, such as an image or sound, the data
-may be directly entered in the table or the table entry for that data may be
-a string specifying a {@code content:} URI that you can use to get the data.
-In general, smaller amounts of data (say, from 20 to 50K or less) are most often
-directly entered in the table and can be read by calling
-<code>{@link android.database.Cursor#getBlob Cursor.getBlob()}</code>.
-It returns a byte array.
-</p>
-
-<p>
-If the table entry is a {@code content:} URI, you should never try to open
-and read the file directly (for one thing, permissions problems can make this
-fail). Instead, you should call
-<code>{@link android.content.ContentResolver#openInputStream
-ContentResolver.openInputStream()}</code> to get an
-{@link java.io.InputStream} object that you can use to read the data.
-</p>
-
-
-<h2><a name="modifying"></a>Modifying Data</h2>
-
-<p>
-Data kept by a content provider can be modified by:
-</p>
-
-<ul>
-<p><li>Adding new records</li>
-<li>Adding new values to existing records</li>
-<li>Batch updating existing records</li>
-<li>Deleting records</li>
-</ul>
-
-<p>
-All data modification is accomplished using {@link android.content.ContentResolver}
-methods. Some content providers require a more restrictive permission for writing
-data than they do for reading it. If you don't have permission to write to a
-content provider, the ContentResolver methods will fail.
-</p>
-
-
-<h3>Adding records</h3>
-
-<p>
-To add a new record to a content provider, first set up a map of key-value pairs
-in a {@link android.content.ContentValues} object, where each key matches
-the name of a column in the content provider and the value is the desired
-value for the new record in that column. Then call <code>{@link
-android.content.ContentResolver#insert ContentResolver.insert()}</code> and pass
-it the URI of the provider and the ContentValues map. This method returns
-the full URI of the new record — that is, the provider's URI with
-the appended ID for the new record. You can then use this URI to query and
-get a Cursor over the new record, and to further modify the record.
-Here's an example:
-</p>
-
-<pre>
-import android.provider.Contacts.People;
-import android.content.ContentResolver;
-import android.content.ContentValues;
-
-ContentValues values = new ContentValues();
-
-// Add Abraham Lincoln to contacts and make him a favorite.
-values.put(People.NAME, "Abraham Lincoln");
-// 1 = the new contact is added to favorites
-// 0 = the new contact is not added to favorites
-values.put(People.STARRED, 1);
-
-Uri uri = getContentResolver().insert(People.CONTENT_URI, values);
-</pre>
-
-
-<h3>Adding new values</h3>
-
-<p>
-Once a record exists, you can add new information to it or modify
-existing information. For example, the next step in the example above would
-be to add contact information — like a phone number or an IM or e-mail
-address — to the new entry.
-</p>
-
-<p>
-The best way to add to a record in the Contacts database is to append
-the name of the table where the new data goes to the URI for the
-record, then use the amended URI to add the new data values. Each
-Contacts table exposes a name for this purpose as a {@code
-CONTENT_DIRECTORY} constant. The following code continues the previous
-example by adding a phone number and e-mail address for the record
-just created:
-</p>
-
-<pre>
-Uri phoneUri = null;
-Uri emailUri = null;
-
-// Add a phone number for Abraham Lincoln. Begin with the URI for
-// the new record just returned by insert(); it ends with the _ID
-// of the new record, so we don't have to add the ID ourselves.
-// Then append the designation for the phone table to this URI,
-// and use the resulting URI to insert the phone number.
-phoneUri = Uri.withAppendedPath(uri, People.Phones.CONTENT_DIRECTORY);
-
-values.clear();
-values.put(People.Phones.TYPE, People.Phones.TYPE_MOBILE);
-values.put(People.Phones.NUMBER, "1233214567");
-getContentResolver().insert(phoneUri, values);
-
-// Now add an email address in the same way.
-emailUri = Uri.withAppendedPath(uri, People.ContactMethods.CONTENT_DIRECTORY);
-
-values.clear();
-// ContactMethods.KIND is used to distinguish different kinds of
-// contact methods, such as email, IM, etc.
-values.put(People.ContactMethods.KIND, Contacts.KIND_EMAIL);
-values.put(People.ContactMethods.DATA, "test@example.com");
-values.put(People.ContactMethods.TYPE, People.ContactMethods.TYPE_HOME);
-getContentResolver().insert(emailUri, values);
-</pre>
-
-<p>
-You can place small amounts of binary data into a table by calling
-the version of <code>{@link android.content.ContentValues#put
-ContentValues.put()}</code> that takes a byte array.
-That would work for a small icon-like image or a short audio clip, for example.
-However, if you have a large amount of binary data to add, such as a photograph
-or a complete song, put a {@code content:} URI for the data in the table and call
-<code>{@link android.content.ContentResolver#openOutputStream
-ContentResolver.openOutputStream()}</code>
-with the file's URI. (That causes the content provider to store the data
-in a file and record the file path in a hidden field of the record.)
-</p>
-
-<p>
-In this regard, the {@link android.provider.MediaStore} content
-provider, the main provider that dispenses image, audio, and video
-data, employs a special convention: The same URI that is used with
-{@code query()} or {@code managedQuery()} to get meta-information
-about the binary data (such as, the caption of a photograph or the
-date it was taken) is used with {@code openInputStream()}
-to get the data itself. Similarly, the same URI that is used with
-{@code insert()} to put meta-information into a MediaStore record
-is used with {@code openOutputStream()} to place the binary data there.
-The following code snippet illustrates this convention:
-</p>
-
-<pre>
-import android.provider.MediaStore.Images.Media;
-import android.content.ContentValues;
-import java.io.OutputStream;
-
-// Save the name and description of an image in a ContentValues map.
-ContentValues values = new ContentValues(3);
-values.put(Media.DISPLAY_NAME, "road_trip_1");
-values.put(Media.DESCRIPTION, "Day 1, trip to Los Angeles");
-values.put(Media.MIME_TYPE, "image/jpeg");
-
-// Add a new record without the bitmap, but with the values just set.
-// insert() returns the URI of the new record.
-Uri uri = getContentResolver().insert(Media.EXTERNAL_CONTENT_URI, values);
-
-// Now get a handle to the file for that record, and save the data into it.
-// Here, sourceBitmap is a Bitmap object representing the file to save to the database.
-try {
- OutputStream outStream = getContentResolver().openOutputStream(uri);
- sourceBitmap.compress(Bitmap.CompressFormat.JPEG, 50, outStream);
- outStream.close();
-} catch (Exception e) {
- Log.e(TAG, "exception while writing image", e);
-}
-</pre>
-
-
-<h3>Batch updating records</h3>
-
-<p>
-To batch update a group of records (for example, to change "NY" to "New York"
-in all fields), call the <code>{@link
-android.content.ContentResolver#update ContentResolver.update()}</code>
-method with the columns and values to change.
-</p>
-
-
-<h3><a name="deletingrecord"></a>Deleting a record</h3>
-
-<p>
-To delete a single record, call {<code>{@link
-android.content.ContentResolver#delete ContentResolver.delete()}</code>
-with the URI of a specific row.
-</p>
-
-<p>
-To delete multiple rows, call <code>{@link
-android.content.ContentResolver#delete ContentResolver.delete()}</code>
-with the URI of the type of record to delete (for example, {@code android.provider.Contacts.People.CONTENT_URI}) and an SQL {@code WHERE}
-clause defining which rows to delete. (<i><b>Caution</b>:
-Be sure to include a valid {@code WHERE} clause if you're deleting a general
-type, or you risk deleting more records than you intended!</i>).
-</p>
-
-
-<h2><a name="creating"></a>Creating a Content Provider</h2>
-
-<p>
-To create a content provider, you must:
-</p>
-
-<ul>
-<li>Set up a system for storing the data. Most content providers
-store their data using Android's file storage methods or SQLite databases,
-but you can store your data any way you want. Android provides the
-{@link android.database.sqlite.SQLiteOpenHelper SQLiteOpenHelper}
-class to help you create a database and {@link
-android.database.sqlite.SQLiteDatabase SQLiteDatabase} to manage it.</li>
-
-<li><p>Extend the {@link android.content.ContentProvider} class to provide
-access to the data.</p></li>
-
-<li><p>Declare the content provider in the manifest file for your
-application (AndroidManifest.xml).</p></li>
-</ul>
-
-<p>
-The following sections have notes on the last two of these tasks.
-</p>
-
-
-<h3>Extending the ContentProvider class</h3>
-
-<p>
-You define a {@link android.content.ContentProvider} subclass to
-expose your data to others using the conventions expected by
-ContentResolver and Cursor objects. Principally, this means
-implementing six abstract methods declared in the ContentProvider class:
-</p>
-
-<p style="margin-left: 2em">{@code query()}
-<br/>{@code insert()}
-<br/>{@code update()}
-<br/>{@code delete()}
-<br/>{@code getType()}
-<br/>{@code onCreate()}</p>
-
-<p>
-The {@code query()} method must return a {@link android.database.Cursor} object
-that can iterate over the requested data. Cursor itself is an interface, but
-Android provides some ready-made Cursor objects that you can use. For example,
-{@link android.database.sqlite.SQLiteCursor} can iterate over data stored in
-an SQLite database. You get the Cursor object by calling any of the {@link
-android.database.sqlite.SQLiteDatabase SQLiteDatabase} class's {@code query()}
-methods. There are other Cursor implementations — such as {@link
-android.database.MatrixCursor} — for data not stored in a database.
-</p>
-
-<p>
-Because these ContentProvider methods can be called from
-various ContentResolver objects in different processes and threads,
-they must be implemented in a thread-safe manner.
-</p>
-
-<p>
-As a courtesy, you might also want to call <code>{@link android.content.ContentResolver#notifyChange(android.net.Uri,android.database.ContentObserver)
-ContentResolver.notifyChange()}</code> to notify listeners when there are
-modifications to the data.
-</p>
-
-<p>
-Beyond defining the subclass itself, there are other steps you should take
-to simplify the work of clients and make the class more accessible:
-</p>
-
-<ul>
-<li>Define a {@code public static final} {@link android.net.Uri}
-named {@code CONTENT_URI}. This is the string that represents the full
-{@code content:} URI that your content provider handles. You must define a
-unique string for this value. The best solution is to use the fully-qualified
-class name of the content provider (made lowercase). So, for example, the
-URI for a TransportationProvider class could be defined as follows:
-
-<pre>public static final Uri CONTENT_URI =
- Uri.parse("content://com.example.codelab.transportationprovider");</pre>
-
-<p>
-If the provider has subtables, also define {@code CONTENT_URI} constants for
-each of the subtables. These URIs should all have the same authority (since
-that identifies the content provider), and be distinguished only by their paths.
-For example:
-</p>
-
-<p style="margin-left: 2em">{@code content://com.example.codelab.transportationprovider/train}
-<br/>{@code content://com.example.codelab.transportationprovider/air/domestic}
-<br/>{@code content://com.example.codelab.transportationprovider/air/international}</p>
-
-<p>
-For an overview of {@code content:} URIs, see the <a href="#urisum">Content URI
-Summary</a> at the end of this document.
-</p></li>
-
-<li><p>Define the column names that the content provider will return to clients.
-If you are using an underlying database, these column names are typically
-identical to the SQL database column names they represent. Also define
-{@code public static} String constants that clients can use to specify
-the columns in queries and other instructions.
-</p>
-
-<p>
-Be sure to include an integer column named "{@code _id}"
-(with the constant {@code _ID}) for
-the IDs of the records. You should have this field whether or not you have
-another field (such as a URL) that is also unique among all records. If
-you're using the SQLite database, the {@code _ID} field should be the
-following type:
-</p>
-
-<p style="margin-left: 2em">{@code INTEGER PRIMARY KEY AUTOINCREMENT}</p>
-
-<p>
-The {@code AUTOINCREMENT} descriptor is optional. But without it, SQLite
-increments an ID counter field to the next number above the largest
-existing number in the column. If you delete the last row, the next row added
-will have the same ID as the deleted row. {@code AUTOINCREMENT} avoids this
-by having SQLite increment to the next largest value whether deleted or not.
-</p>
-</li>
-
-<li><p>Carefully document the data type of each column. Clients need this
-information to read the data.</p></li>
-
-<li><p>If you are handling a new data type, you must define a new MIME type
-to return in your implementation of <code>{@link
-android.content.ContentProvider#getType ContentProvider.getType()}</code>.
-The type depends in part on whether or not the {@code content:} URI submitted
-to {@code getType()} limits the request to a specific record. There's one
-form of the MIME type for a single record and another for multiple records.
-Use the {@link android.net.Uri Uri} methods to help determine what is being
-requested. Here is the general format for each type:</p></li>
-
-<ul>
-<li><p>For a single record: {@code vnd.android.cursor.item/vnd.<em>yourcompanyname.contenttype</em>}</p>
-
-<p>For example, a request for train record 122, like this URI,</p>
-<p style="margin-left: 2em">{@code content://com.example.transportationprovider/trains/122}</p>
-
-<p>might return this MIME type:</p>
-<p style="margin-left: 2em">{@code vnd.android.cursor.item/vnd.example.rail}</p>
-</li>
-
-<li><p>For multiple records: {@code vnd.android.cursor.dir/vnd.<em>yourcompanyname.contenttype</em>}</p>
-
-<p>For example, a request for all train records, like the following URI,</p>
-<p style="margin-left: 2em">{@code content://com.example.transportationprovider/trains}</p>
-
-<p>might return this MIME type:</p>
-<p style="margin-left: 2em">{@code vnd.android.cursor.dir/vnd.example.rail}</p>
-</li>
-</ul>
-
-<li><p>If you are exposing byte data that's too big to put in the table itself
-— such as a large bitmap file — the field that exposes the
-data to clients should actually contain a {@code content:} URI string.
-This is the field that gives clients access to the data file. The record
-should also have another field, named "{@code _data}" that lists the exact file
-path on the device for that file. This field is not intended to be read by
-the client, but by the ContentResolver. The client will call <code>{@link
-android.content.ContentResolver#openInputStream ContentResolver.openInputStream()}</code>
-on the user-facing field holding the URI for the item. The ContentResolver
-will request the "{@code _data}" field for that record, and because
-it has higher permissions than a client, it should be able to access
-that file directly and return a read wrapper for the file to the client.</p></li>
-
-</ul>
-
-<p>
-For an example of a private content provider implementation, see the
-NodePadProvider class in the Notepad sample application that ships with the SDK.
-</p>
-
-
-<h3>Declaring the content provider</h3>
-
-<p>
-To let the Android system know about the content provider you've developed,
-declare it with a {@code <provider>} element in the application's
-AndroidManifest.xml file. Content providers that are not declared in the
-manifest are not visible to the Android system
-</p>
-
-<p>
-The {@code name} attribute is the fully qualified name of the ContentProvider
-subclass. The {@code authorities} attribute is the authority part of the
-{@code content:} URI that identifies the provider.
-For example if the ContentProvider subclass is AutoInfoProvider, the
-{@code <provider>} element might look like this:
-</p>
-
-<pre>
-<provider android:name="com.example.autos.AutoInfoProvider"
- android:authorities="com.example.autos.autoinfoprovider"
- . . . />
-</provider>
-</pre>
-
-<p>
-Note that the {@code authorities} attribute omits the path part of a
-{@code content:} URI. For example, if AutoInfoProvider controlled subtables
-for different types of autos or different manufacturers,
-</p>
-
-<p style="margin-left: 2em">{@code content://com.example.autos.autoinfoprovider/honda}
-<br/>{@code content://com.example.autos.autoinfoprovider/gm/compact}
-<br/>{@code content://com.example.autos.autoinfoprovider/gm/suv}</p>
-
-<p>
-those paths would not be declared in the manifest. The authority is what
-identifies the provider, not the path; your provider can interpret the path
-part of the URI in any way you choose.
-</p>
-
-<p>
-Other {@code <provider>} attributes can set permissions to read and
-write data, provide for an icon and text that can be displayed to users,
-enable and disable the provider, and so on. Set the {@code multiprocess}
-attribute to "{@code true}" if data does not need to be synchronized between
-multiple running versions of the content provider. This permits an instance
-of the provider to be created in each client process, eliminating the need
-to perform IPC.
-</p>
-
-
-<h2><a name="urisum"></a>Content URI Summary</h2>
-
-<p>
-Here is a recap of the important parts of a content URI:
-</p>
-
-<p>
-<img src="{@docRoot}images/content_uri.png" alt="Elements of a content URI"
-height="80" width="528">
-</p>
-
-<ol type="A">
-<li>Standard prefix indicating that the data is controlled by a
-content provider. It's never modified.</li>
-
-<li><p>The authority part of the URI; it identifies the content provider.
-For third-party applications, this should be a fully-qualified class name
-(reduced to lowercase) to ensure uniqueness. The authority is declared in
-the {@code <provider>} element's {@code authorities} attribute:</p>
-
-<pre><provider android:name=".TransportationProvider"
- android:authorities="com.example.transportationprovider"
- . . . ></pre></li>
-
-<li><p>The path that the content provider uses to determine what kind of data is
-being requested. This can be zero or more segments long. If the content provider
-exposes only one type of data (only trains, for example), it can be absent.
-If the provider exposes several types, including subtypes, it can be several
-segments long — for example, "{@code land/bus}", "{@code land/train}",
-"{@code sea/ship}", and "{@code sea/submarine}" to give four possibilities.</p></li>
-
-<li><p>The ID of the specific record being requested, if any. This is the
-{@code _ID} value of the requested record. If the request is not limited to
-a single record, this segment and the trailing slash are omitted:</p>
-
-<p style="margin-left: 2em">{@code content://com.example.transportationprovider/trains}</p>
-</li>
-</ol>
-
-
+<dl>
+ <dt>
+ <strong><a href="{@docRoot}guide/topics/providers/content-provider-basics.html">
+ Content Provider Basics</a></strong>
+ </dt>
+ <dd>
+ How to access data in a content provider when the data is organized in tables.
+ </dd>
+ <dt>
+ <strong><a href="{@docRoot}guide/topics/providers/content-provider-creating.html">
+ Creating a Content Provider</a></strong>
+ </dt>
+ <dd>
+ How to create your own content provider.
+ </dd>
+ <dt>
+ <strong><a href="{@docRoot}guide/topics/providers/calendar-provider.html">
+ Calendar Provider</a></strong>
+ </dt>
+ <dd>
+ How to access the Calendar Provider that is part of the Android platform.
+ </dd>
+</dl>
diff --git a/docs/html/guide/topics/renderscript/compute.jd b/docs/html/guide/topics/renderscript/compute.jd
index 8f08f59..e827f00 100644
--- a/docs/html/guide/topics/renderscript/compute.jd
+++ b/docs/html/guide/topics/renderscript/compute.jd
@@ -1,38 +1,253 @@
page.title=Compute
-parent.title=RenderScript
+parent.title=Renderscript
parent.link=index.html
+
@jd:body
- <div id="qv-wrapper">
- <div id="qv">
+<div id="qv-wrapper">
+ <div id="qv">
+ <h2>In this document</h2>
- <h2>Related Samples</h2>
+ <ol>
+ <li>
+ <a href="#creating">Creating a Compute Renderscript</a>
- <ol>
- <li><a href="{@docRoot}resources/samples/RenderScript/HelloCompute/index.html">Hello
- Compute</a></li>
- <li><a href="{@docRoot}resources/samples/RenderScript/Balls/index.html">Balls</a></li>
- </ol>
- </div>
+ <ol>
+ <li><a href="#creating-renderscript">Creating the Renderscript file</a></li>
+
+ <li><a href="#calling">Calling the Renderscript code</a></li>
+ </ol>
+ </li>
+ </ol>
+
+ <h2>Related Samples</h2>
+
+ <ol>
+ <li><a href="{@docRoot}resources/samples/RenderScript/HelloCompute/index.html">Hello
+ Compute</a></li>
+
+ <li><a href="{@docRoot}resources/samples/RenderScript/Balls/index.html">Balls</a></li>
+ </ol>
</div>
+</div>
- <p>RenderScript exposes a set of compute APIs that you can use to do intensive computational operations.
- You can use the compute APIs in the context of a graphics RenderScript such as calculating the
- transformation of many geometric objects in a scene. You can also create a standalone compute RenderScript that does not
- draw anything to the screen such as bitmap image processing for a photo editor application.
- The RenderScript compute APIs are mainly defined in the <code>rs_cl.rsh</code> header</p>
-
- <p>Compute RenderScripts are simpler to setup and implement as there is no graphics rendering involved.
- You can offload computational aspects of your application to RenderScript by creating a native RenderScript
- file (.rs) and using the generated reflected layer class to call functions in the <code>.rs</code> file.
+<p>Renderscript exposes a set of compute APIs that you can use to do intensive computational
+operations. You can use the compute APIs in the context of a graphics Renderscript such as
+calculating the positions of many objects in a scene. You can also create standalone compute
+Renderscripts such as one that does image processing for a photo editor application.</p>
- <p>See the <a href="{@docRoot}resources/samples/RenderScript/HelloCompute/index.html">HelloCompute</a>
- sample in the Android SDK for more
- information on how to create a simple compute RenderScript.</p>
- <p>
- See the <a href="{@docRoot}resources/samples/RenderScript/Balls/index.html">Balls</a>
- sample in the Android SDK for more
- information on how to create a compute RenderScript that is used in a graphics RenderScript.
- The compute RenderScript is contained in
- <a href="{@docRoot}resources/samples/RenderScript/Balls/src/com/example/android/rs/balls/ball_physics.html">balls_physics.rs</a>.
- </p>
\ No newline at end of file
+<p>Compute Renderscripts scale to the amount of
+processing cores available on the device. This is enabled through a function named
+<code>rsForEach()</code> (or the <code>forEach_root()</code> method at the Android framework level).
+that automatically partitions work across available processing cores on the device.
+For now, compute Renderscripts can only take advantage of CPU
+cores, but in the future, they can potentially run on other types of processors such as GPUs and
+DSPs.</p>
+
+<h2 id="creating-renderscript">Creating a Compute Renderscript</h2>
+
+<p>Implementing a compute Renderscript creating a <code>.rs</code> file that contains
+your Renderscript code and calling it at the Android framework level with the
+<code>forEach_root()</code> or at the Renderscript runtime level with the
+<code>rsForEach()</code> function. The following diagram describes how a typical compute
+Renderscript is set up:</p><img src="{@docRoot}images/rs_compute.png">
+
+<p class="img-caption"><strong>Figure 1.</strong> Compute Renderscript overview</p>
+
+<p>The following sections describe how to create a simple compute Renderscript and use it in an
+Android application. This example uses the <a href=
+"{@docRoot}resources/samples/RenderScript/HelloCompute/index.html">HelloCompute Renderscript
+sample</a> that is provided in the SDK as a guide (some code has been modified from its original
+form for simplicity).</p>
+
+<h3 id="creating-renderscript">Creating the Renderscript file</h3>
+
+<p>Your Renderscript code resides in <code>.rs</code> and <code>.rsh</code> files in the
+<code><project_root>/src/</code> directory. This code contains the compute logic
+and declares all necessary variables and pointers.
+Every compute <code>.rs</code> file generally contains the following items:</p>
+
+<ul>
+ <li>A pragma declaration (<code>#pragma rs java_package_name(<em>package.name</em>)</code>)
+ that declares the package name of the <code>.java</code> reflection of this Renderscript.</li>
+
+ <li>A pragma declaration (<code>#pragma version(1)</code>) that declares the version of
+ Renderscript that you are using (1 is the only value for now).</li>
+
+ <li>A <code>root()</code> function that is the main worker function. The root function is
+ called by the <code>rsForEach</code> function, which allows the Renderscript code to be called and
+ executed on multiple cores if they are available. The <code>root()</code> function must return
+ <code>void</code> and accept the following arguments:
+
+ <ul>
+ <li>Pointers to memory allocations that are used for the input and output of the compute
+ Renderscript. Both of these pointers are required for Android 3.2 (API level 13) platform
+ versions or older. Android 4.0 (API level 14) and later requires one or both of these
+ allocations.</li>
+ </ul>
+
+ <p>The following arguments are optional, but both must be supplied if you choose to use
+ them:</p>
+
+ <ul>
+ <li>A pointer for user-defined data that the Renderscript might need to carry out
+ computations in addition to the necessary allocations. This can be a pointer to a simple
+ primitive or a more complex struct.</li>
+
+ <li>The size of the user-defined data.</li>
+ </ul>
+ </li>
+
+ <li>An optional <code>init()</code> function. This allows you to do any initialization
+ before the <code>root()</code> function runs, such as initializing variables. This
+ function runs once and is called automatically when the Renderscript starts, before anything
+ else in your Renderscript.</li>
+
+ <li>Any variables, pointers, and structures that you wish to use in your Renderscript code (can
+ be declared in <code>.rsh</code> files if desired)</li>
+</ul>
+
+<p>The following code shows how the <a href=
+"{@docRoot}resources/samples/RenderScript/HelloCompute/src/com/example/android/rs/hellocompute/mono.html">
+mono.rs</a> file is implemented:</p>
+<pre>
+#pragma version(1)
+#pragma rs java_package_name(com.example.android.rs.hellocompute)
+
+//multipliers to convert a RGB colors to black and white
+const static float3 gMonoMult = {0.299f, 0.587f, 0.114f};
+
+void root(const uchar4 *v_in, uchar4 *v_out) {
+ //unpack a color to a float4
+ float4 f4 = rsUnpackColor8888(*v_in);
+ //take the dot product of the color and the multiplier
+ float3 mono = dot(f4.rgb, gMonoMult);
+ //repack the float to a color
+ *v_out = rsPackColorTo8888(mono);
+}
+</pre>
+
+<h3 id="calling">Calling the Renderscript code</h3>
+
+<p>You can do Renderscript to Renderscript calls with <code>rsForEach</code> in situations
+such as when a graphics Renderscript needs to do a lot of computational operations. The Renderscript
+<a href="{@docRoot}resources/samples/RenderScript/Balls/index.html">Balls</a> sample shows how
+this is setup. The <a href=
+"resources/samples/RenderScript/Balls/src/com/example/android/rs/balls/balls.html">balls.rs</a>
+graphics Renderscript calls the <a href=
+"resources/samples/RenderScript/Balls/src/com/example/android/rs/balls/balls.html">balls_physics.rs</a>
+compute Renderscript to calculate the location of the balls that are rendered to the screen.</p>
+
+<p>Another way to use a compute Renderscript is to call it from your Android framework code by
+creating a Renderscript object by instantiating the (<code>ScriptC_<em>script_name</em></code>)
+class. This class contains a method, <code>forEach_root()</code>, that lets you invoke
+<code>rsForEach</code>. You give it the same parameters that you would if you were invoking it
+at the Renderscript runtime level. This technique allows your Android application to offload
+intensive mathematical calculations to Renderscript. See the <a href=
+"{@docRoot}resources/samples/RenderScript/HelloCompute/index.html">HelloCompute</a> sample to see
+how a simple Android application can utilize a compute Renderscript.</p>
+
+<p>To call a compute Renderscript at the Android framework level:</p>
+
+<ol>
+ <li>Allocate memory that is needed by the compute Renderscript in your Android framework code.
+ You need an input and output {@link android.renderscript.Allocation} for Android 3.2 (API level
+ 13) platform versions and older. The Android 4.0 (API level 14) platform version requires only
+ one or both {@link android.renderscript.Allocation}s.</li>
+
+ <li>Create an instance of the <code>ScriptC_<em>script_name</em></code> class.</li>
+
+ <li>Call <code>forEach_root()</code>, passing in the allocations, the
+ Renderscript, and any optional user-defined data. The output allocation will contain the output
+ of the compute Renderscript.</li>
+</ol>
+
+<p>In the following example, taken from the <a href=
+"{@docRoot}resources/samples/RenderScript/HelloCompute/index.html">HelloCompute</a> sample, processes
+a bitmap and outputs a black and white version of it. The
+<code>createScript()</code> method carries out the steps described previously. This method the compute
+Renderscript, <code>mono.rs</code>, passing in memory allocations that store the bitmap to be processed
+as well as the eventual output bitmap. It then displays the processed bitmap onto the screen:</p>
+<pre>
+package com.example.android.rs.hellocompute;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.graphics.BitmapFactory;
+import android.graphics.Bitmap;
+import android.renderscript.RenderScript;
+import android.renderscript.Allocation;
+import android.widget.ImageView;
+
+public class HelloCompute extends Activity {
+ private Bitmap mBitmapIn;
+ private Bitmap mBitmapOut;
+
+ private RenderScript mRS;
+ private Allocation mInAllocation;
+ private Allocation mOutAllocation;
+ private ScriptC_mono mScript;
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.main);
+
+ mBitmapIn = loadBitmap(R.drawable.data);
+ mBitmapOut = Bitmap.createBitmap(mBitmapIn.getWidth(), mBitmapIn.getHeight(),
+ mBitmapIn.getConfig());
+
+ ImageView in = (ImageView) findViewById(R.id.displayin);
+ in.setImageBitmap(mBitmapIn);
+
+ ImageView out = (ImageView) findViewById(R.id.displayout);
+ out.setImageBitmap(mBitmapOut);
+
+ createScript();
+ }
+ private void createScript() {
+ mRS = RenderScript.create(this);
+ mInAllocation = Allocation.createFromBitmap(mRS, mBitmapIn,
+ Allocation.MipmapControl.MIPMAP_NONE,
+ Allocation.USAGE_SCRIPT);
+ mOutAllocation = Allocation.createTyped(mRS, mInAllocation.getType());
+ mScript = new ScriptC_mono(mRS, getResources(), R.raw.mono);
+ mScript.forEach_root(mInAllocation, mOutAllocation);
+ mOutAllocation.copyTo(mBitmapOut);
+ }
+
+ private Bitmap loadBitmap(int resource) {
+ final BitmapFactory.Options options = new BitmapFactory.Options();
+ options.inPreferredConfig = Bitmap.Config.ARGB_8888;
+ return BitmapFactory.decodeResource(getResources(), resource, options);
+ }
+}
+</pre>
+
+<p>To call a compute Renderscript from another Renderscript file:</p>
+<ol>
+ <li>Allocate memory that is needed by the compute Renderscript in your Android framework code.
+ You need an input and output {@link android.renderscript.Allocation} for Android 3.2 (API level
+ 13) platform versions and older. The Android 4.0 (API level 14) platform version requires only
+ one or both {@link android.renderscript.Allocation}s.</li>
+
+ <li>Call <code>rsForEach()</code>, passing in the allocations and any optional user-defined data.
+ The output allocation will contain the output of the compute Renderscript.</li>
+</ol>
+<p>The following example, taken from the <a href=
+"{@docRoot}resources/samples/RenderScript/Balls/src/com/example/android/rs/balls/balls.html">Renderscript
+Balls sample</a>, demonstrates how to do make a script to script call:</p>
+<pre>
+rs_script script;
+rs_allocation in_allocation;
+rs_allocation out_allocation;
+UserData_t data;
+...
+rsForEach(script, in_allocation, out_allocation, &data, sizeof(data));
+</pre>
+
+<p>In this example, assume that the script and memory allocations have already been
+allocated and bound at the Android framework level and that <code>UserData_t</code> is a struct
+declared previously. Passing a pointer to a struct and the size of the struct to <code>rsForEach</code>
+is optional, but useful if your compute Renderscript requires additional information other than
+the necessary memory allocations.</p>
diff --git a/docs/html/guide/topics/renderscript/graphics.jd b/docs/html/guide/topics/renderscript/graphics.jd
index 2fefecc..1c6d0de 100644
--- a/docs/html/guide/topics/renderscript/graphics.jd
+++ b/docs/html/guide/topics/renderscript/graphics.jd
@@ -1,6 +1,7 @@
-page.title=3D Graphics
-parent.title=RenderScript
+page.title=Graphics
+parent.title=Renderscript
parent.link=index.html
+
@jd:body
<div id="qv-wrapper">
@@ -11,16 +12,16 @@
<li>
<a href="#creating-graphics-rs">Creating a Graphics Renderscript</a>
<ol>
- <li><a href="#creating-native">Creating the native Renderscript file</a></li>
+ <li><a href="#creating-native">Creating the Renderscript file</a></li>
<li><a href="#creating-entry">Creating the Renderscript entry point class</a></li>
- <li><a href="#creating-view">Creating the surface view</a></li>
- <li><a href="#creating-activity">Creating the activity</a></li>
+ <li><a href="#creating-view">Creating the view class</a></li>
+ <li><a href="#creating-activity">Creating the activity class</a></li>
</ol>
</li>
<li>
<a href="#drawing">Drawing</a>
<ol>
- <li><a href="#drawing-rsg">Drawing using the rsgDraw functions</a></li>
+ <li><a href="#drawing-rsg">Simple drawing</a></li>
<li><a href="#drawing-mesh">Drawing with a mesh</a></li>
</ol>
</li>
@@ -31,6 +32,9 @@
<li><a href="#shader-sampler">Defining a sampler</a></li>
</ol>
</li>
+ <li>
+ <a href="#fbo">Rendering to a Framebuffer Object</a>
+ </li>
</ol>
<h2>Related Samples</h2>
@@ -40,8 +44,9 @@
<li><a href="{@docRoot}resources/samples/RenderScript/Fountain/index.html">Fountain</a></li>
- <li><a href="{@docRoot}resources/samples/RenderScript/HelloWorld/index.html">Hello
- World</a></li>
+ <li><a href="{@docRoot}resources/samples/RenderScript/FountainFbo/index.html">FountainFbo</a></li>
+
+ <li><a href="{@docRoot}resources/samples/RenderScript/HelloWorld/index.html">Hello World</a></li>
<li><a
href="{@docRoot}resources/samples/RenderScript/MiscSamples/index.html">Misc Samples</a></li>
@@ -49,310 +54,476 @@
</div>
</div>
- <p>RenderScript provides a number of graphics APIs for 3D rendering, both at the Android
- framework level as well as at the native level. For instance, the Android framework APIs let you
+ <p>Renderscript provides a number of graphics APIs for rendering, both at the Android
+ framework level as well as at the Renderscript runtime level. For instance, the Android framework APIs let you
create meshes and define shaders to customize the graphical rendering pipeline. The native
- RenderScript graphics APIs lets you draw the actual meshes to render your scene. In general, you
- will need to be familiar with APIs to appropriately render 3D graphics on an Android-powered
- device.</p>
+ Renderscript graphics APIs let you draw the actual meshes to render your scene. You need to
+ be familiar with both APIs to appropriately render graphics on an Android-powered device.</p>
- <h2 id="creating-graphics-rs">Creating a Graphics RenderScript</h2>
+ <h2 id="creating-graphics-rs">Creating a Graphics Renderscript</h2>
- <p>Because of the various layers of code when writing a RenderScript application, it is useful to
- create the following files for a scene that you want to render:</p>
+ <p>Renderscript applications require various layers of code, so it is useful to create the following
+ files to help keep your application organized:</p>
- <ul>
- <li>The native RenderScript <code>.rs</code> file. This file contains the logic to do the
- graphics rendering.</li>
+ <dl>
+ <dt>The Renderscript <code>.rs</code> file</dt>
- <li>The RenderScript entry point class that allows your view to interact with the code defined
- in the <code>.rs</code> file. This class contains a RenderScript object(instance of
+ <dd>This file contains the logic to do the graphics rendering.</dd>
+
+ <dt>The Renderscript entry point <code>.java</code> class</dt>
+
+ <dd>This class allows the view class to interact with the code defined in the <code>.rs</code>
+ file. This class contains a Renderscript object (instance of
<code>ScriptC_<em>renderscript_file</em></code>), which allows your Android framework code to
- call the native RenderScript code. This class also creates the {@link
- android.renderscript.RenderScriptGL} context object, which contains the current rendering state
- of the RenderScript such as programs (vertex and fragment shaders, for example) that you want
- to define and bind to the graphics pipeline. The context object attaches to the RenderScript
- object (instance of <code><em>ScriptC_renderscript_file</em></code>) that does the rendering.
- Our example names this class <code>HelloWorldRS</code>.</li>
+ call the Renderscript code. In general, this class does much of the setup for Renderscript
+ such as shader and mesh building and memory allocation and binding. The SDK samples follow the
+ convention of naming this file ActivityRS.java,
+ where Activity is the name of your main activity class.</dd>
- <li>Create a class that extends {@link android.renderscript.RSSurfaceView} to provide a surface
- to render on. If you want to implement callbacks from events inherited from {@link
+ <dt>The view <code>.java</code> class</dt>
+
+ <dd>This class extends {@link android.renderscript.RSSurfaceView} or {@link
+ android.renderscript.RSTextureView} to provide a surface to render on. A {@link
+ android.renderscript.RSSurfaceView} consumes a whole window, but a {@link
+ android.renderscript.RSTextureView} allows you to draw Renderscript graphics inside of a
+ view and add it to a {@link android.view.ViewGroup} alongside
+ other views. In this class, you create a {@link android.renderscript.RenderScriptGL} context object
+ with a call to {@link android.renderscript.RSSurfaceView#createRenderScriptGL
+ RSSurfaceView.createRenderscriptGL()} or {@link android.renderscript.RSTextureView#createRenderScriptGL
+ RSTextureView.createRenderscriptGL()}. The {@link android.renderscript.RenderScriptGL} context object
+ contains information about the current rendering state of Renderscript such as the vertex and
+ fragment shaders. You pass this context object to the Renderscript entry point class, so that
+ class can modify the rendering context if needed and bind the Renderscript code to the context. Once bound,
+ the view class can use the Renderscript code to display graphics.
+ The view class should also implement callbacks for events inherited from {@link
android.view.View}, such as {@link android.view.View#onTouchEvent onTouchEvent()} and {@link
- android.view.View#onKeyDown onKeyDown()}, do so in this class as well.</li>
+ android.view.View#onKeyDown onKeyDown()} if you want to detect these types of user interactions.
+ The SDK samples follow the convention of naming this file ActivityView.java,
+ where Activity is the name of your main activity class</dd>
- <li>Create a class that is the main Activity class, like you would with any Android
- application. This class sets your {@link android.renderscript.RSSurfaceView} as the content
- view for this Activity.</li>
- </ul>
+ <dt>The activity <code>.java</code> class</dt>
- <p>The following sections describe how to implement these three classes by using the HelloWorld
- RenderScript sample that is provided in the SDK as a guide (some code has been modified from its
- original form for simplicity).</p>
+ <dd>This class is the main activity class and sets your {@link android.renderscript.RSSurfaceView} as the main content
+ view for this activity or uses the {@link android.renderscript.RSTextureView} alongside other views.</dd>
+ </dl>
+ <p>Figure 1 describes how these classes interact with one another in a graphics Renderscript:</p>
+
+ <img src="{@docRoot}images/rs_graphics.png">
+ <p class="img-caption"><strong>Figure 1.</strong> Graphics Renderscript overview</p>
- <h3 id="creating-native">Creating the native RenderScript file</h3>
- <p>Your native RenderScript code resides in a <code>.rs</code> file in the
- <code><project_root>/src/</code> directory. You can also define <code>.rsh</code> header
- files. This code contains the logic to render your graphics and declares all necessary variables
+ <p>The following sections describe how to create an application that uses a graphics Renderscript by using
+ the <a href="{@docRoot}resources/samples/RenderScript/Fountain/index.html">Renderscript Fountain
+ sample</a> that is provided in the SDK as a guide (some code has been modified from its original
+ form for simplicity).</p>
+
+ <h3 id="creating-native">Creating the Renderscript file</h3>
+
+ <p>Your Renderscript code resides in <code>.rs</code> and <code>.rsh</code> (headers) files in the
+ <code><project_root>/src/</code> directory. This code contains the logic to render your
+ graphics and declares all other necessary items such as variables, structs,
and pointers. Every graphics <code>.rs</code> file generally contains the following items:</p>
<ul>
- <li>A pragma (<code>#pragma rs java_package_name(<em>package.name</em>)</code>) that declares
- the package name of the <code>.java</code> reflection of this RenderScript.</li>
+ <li>A pragma declaration (<code>#pragma rs java_package_name(<em>package.name</em>)</code>) that declares
+ the package name of the <code>.java</code> reflection of this Renderscript.</li>
- <li>A pragma (<code>#pragma version(1)</code>) that declares the version of RenderScript that
+ <li>A pragma declaration (<code>#pragma version(1)</code>) that declares the version of Renderscript that
you are using (1 is the only value for now).</li>
- <li>A <code>#include</code> of the rs_graphics.rsh header file.</li>
+ <li>A <code>#include "rs_graphics.rsh"</code> declaration.</li>
- <li>A <code>root()</code> function. This is the main worker function for your RenderScript and
- calls RenderScript graphics APIs to draw meshes to the surface. This function is called every
- time a frame refresh occurs, which is specified as its return value. A <code>0</code> specified
- for the return value says to only render the frame when a property of the scene that you are
+ <li>A <code>root()</code> function. This is the main worker function for your Renderscript and
+ calls Renderscript graphics functions to render scenes. This function is called every time a
+ frame refresh occurs, which is specified as its return value. A <code>0</code> (zero) specified for
+ the return value says to only render the frame when a property of the scene that you are
rendering changes. A non-zero positive integer specifies the refresh rate of the frame in
milliseconds.
- <p class="note"><strong>Note:</strong> The RenderScript runtime makes its best effort to
+ <p class="note"><strong>Note:</strong> The Renderscript runtime makes its best effort to
refresh the frame at the specified rate. For example, if you are creating a live wallpaper
- and set the return value to 50, the runtime renders the wallpaper at 20fps if it has just
- enough or more resources to do so, and renders as fast as it can if it does not.</p>
-
- <p>For more
- information on using the RenderScript graphics functions, see the <a href=
+ and set the return value to 20, the Renderscript runtime renders the wallpaper at 20fps if it has just
+ enough or more resources to do so. It renders as fast as it can if not enough resources
+ are available.</p>
+
+ <p>For more information on using the Renderscript graphics functions, see the <a href=
"#drawing">Drawing</a> section.</p>
</li>
- <li>An <code>init()</code> function. This allows you to do any initialization of your
- RenderScript before the <code>root()</code> function runs, such as initializing variables. This
- function runs once and is called automatically when the RenderScript starts, before anything
- else in your RenderScript. Creating this function is optional.</li>
+ <li>An <code>init()</code> function. This allows you to do initialization of your
+ Renderscript before the <code>root()</code> function runs, such as assigning values to variables. This
+ function runs once and is called automatically when the Renderscript starts, before anything
+ else in your Renderscript. Creating this function is optional.</li>
- <li>Any variables, pointers, and structures that you wish to use in your RenderScript code (can
+ <li>Any variables, pointers, and structures that you wish to use in your Renderscript code (can
be declared in <code>.rsh</code> files if desired)</li>
</ul>
- <p>The following code shows how the <code>helloworld.rs</code> file is implemented:</p>
+ <p>The following code shows how the <code>fountain.rs</code> file is implemented:</p>
<pre>
#pragma version(1)
// Tell which java package name the reflected files should belong to
-#pragma rs java_package_name(com.android.rs.helloworld)
+#pragma rs java_package_name(com.example.android.rs.fountain)
-// Built-in header with graphics APIs
+//declare shader binding
+#pragma stateFragment(parent)
+
+// header with graphics APIs, must include explicitly
#include "rs_graphics.rsh"
-// gTouchX and gTouchY are variables that are reflected for use
-// by the Android framework API. This RenderScript uses them to be notified of touch events.
-int gTouchX;
-int gTouchY;
+static int newPart = 0;
-// This is invoked automatically when the script is created and initializes the variables
-// in the Android framework layer as well.
-void init() {
- gTouchX = 50.0f;
- gTouchY = 50.0f;
+// the mesh to render
+rs_mesh partMesh;
+
+// the point representing where a particle is rendered
+typedef struct __attribute__((packed, aligned(4))) Point {
+ float2 delta;
+ float2 position;
+ uchar4 color;
+} Point_t;
+Point_t *point;
+
+// main worker function that renders particles onto the screen
+int root() {
+ float dt = min(rsGetDt(), 0.1f);
+ rsgClearColor(0.f, 0.f, 0.f, 1.f);
+ const float height = rsgGetHeight();
+ const int size = rsAllocationGetDimX(rsGetAllocation(point));
+ float dy2 = dt * (10.f);
+ Point_t * p = point;
+ for (int ct=0; ct < size; ct++) {
+ p->delta.y += dy2;
+ p->position += p->delta;
+ if ((p->position.y > height) && (p->delta.y > 0)) {
+ p->delta.y *= -0.3f;
+ }
+ p++;
+ }
+
+ rsgDrawMesh(partMesh);
+ return 1;
}
-int root(int launchID) {
+// adds particles to the screen to render
+static float4 partColor[10];
+void addParticles(int rate, float x, float y, int index, bool newColor)
+{
+ if (newColor) {
+ partColor[index].x = rsRand(0.5f, 1.0f);
+ partColor[index].y = rsRand(1.0f);
+ partColor[index].z = rsRand(1.0f);
+ }
+ float rMax = ((float)rate) * 0.02f;
+ int size = rsAllocationGetDimX(rsGetAllocation(point));
+ uchar4 c = rsPackColorTo8888(partColor[index]);
- // Clear the background color
- rsgClearColor(0.0f, 0.0f, 0.0f, 0.0f);
- // Tell the runtime what the font color should be
- rsgFontColor(1.0f, 1.0f, 1.0f, 1.0f);
- // Introuduce ourselves to the world by drawing a greeting
- // at the position user touched on the screen
- rsgDrawText("Hello World!", gTouchX, gTouchY);
-
- // Return value tells RS roughly how often to redraw
- // in this case 20 ms
- return 20;
+ Point_t * np = &point[newPart];
+ float2 p = {x, y};
+ while (rate--) {
+ float angle = rsRand(3.14f * 2.f);
+ float len = rsRand(rMax);
+ np->delta.x = len * sin(angle);
+ np->delta.y = len * cos(angle);
+ np->position = p;
+ np->color = c;
+ newPart++;
+ np++;
+ if (newPart >= size) {
+ newPart = 0;
+ np = &point[newPart];
+ }
+ }
}
</pre>
- <h3 id="creating-entry">Creating the RenderScript entry point class</h3>
+ <h3 id="creating-entry">Creating the Renderscript entry point class</h3>
- <p>When you create a RenderScript (<code>.rs</code>) file, it is helpful to create a
- corresponding Android framework class that is an entry point into the <code>.rs</code> file. In
- this entry point class, you create a RenderScript object by instantiating a
- <code>ScriptC_<em>rs_filename</em></code> and binding it to the RenderScript context. The
- RenderScript object is attached to the RenderScript bytecode, which is platform-independent and
- gets compiled on the device when the RenderScript application runs. Both the
- <code>ScriptC_<em>rs_filename</em></code> class and bytecode is generated by the Android build
- tools and is packaged with the <code>.apk</code> file. The bytecode file is located in the
- <code><project_root>/res/raw/</code> directory and is named <code>rs_filename.bc</code>.
- You refer to the bytecode as a resource (<code>R.raw.<em>rs_filename</em></code>). when creating
- the RenderScript object..</p>
+ <p>When you create a Renderscript (<code>.rs</code>) file, it is helpful to create a
+ corresponding Android framework class that is an entry point into the <code>.rs</code> file.
+ The most important thing this class does is receive a {@link android.renderscript.RenderScriptGL} rendering context
+ object from the <a href="#creating-view">view class</a> and binds the actual Renderscript
+ code to the rendering context. This notifies your view class of the code that it needs
+ to render graphics.
+ </p>
- <p>You then bind the RenderScript object to the RenderScript context, so that the surface view
- knows what code to use to render graphics. The following code shows how the
- <code>HelloWorldRS</code> class is implemented:</p>
+ <p>In addition, this class should contain all of the things needed to set up Renderscript.
+ Some important things that you need to do in this class are:</p>
+
+ <ul>
+ <li>Create a Renderscript object
+ <code>ScriptC_<em>rs_filename</em></code>. The Renderscript object is attached to the Renderscript bytecode, which is platform-independent and
+ gets compiled on the device when the Renderscript application runs. The bytecode is referenced
+ as a raw resource and is passed into the constructor for the Renderscript object.
+ For example, this is how the <a href="{@docRoot}resources/samples/RenderScript/Fountain/index.html">Fountain</a>
+ sample creates the Renderscript object:
<pre>
-package com.android.rs.helloworld;
+ RenderScriptGL rs; //obtained from the view class
+ Resources res; //obtained from the view class
+ ...
+ ScriptC_fountain mScript = new ScriptC_fountain(mRS, mRes, R.raw.fountain);
+ </pre>
+ </li>
+ <li>Allocate any necessary memory and bind it to your Renderscript code via the Renderscript object.</li>
+ <li>Build any necessary meshes and bind them to the Renderscript code via the Renderscript object.</li>
+ <li>Create any necessary programs and bind them to the Renderscript code via the Renderscript object.</li>
+ </ul>
+
+ <p>The following code shows how the <a href=
+ "{@docRoot}resources/samples/RenderScript/Fountain/src/com/example/android/rs/fountain/FountainRS.html">
+ FountainRS</a> class is implemented:</p>
+ <pre>
+package com.example.android.rs.fountain;
import android.content.res.Resources;
import android.renderscript.*;
+import android.util.Log;
-public class HelloWorldRS {
- //context and resources are obtained from RSSurfaceView, which calls init()
+public class FountainRS {
+ public static final int PART_COUNT = 50000;
+
+ public FountainRS() {
+ }
+
+ /**
+ * This provides us with the Renderscript context and resources
+ * that allow us to create the Renderscript object
+ */
private Resources mRes;
private RenderScriptGL mRS;
- //Declare the RenderScript object
- private ScriptC_helloworld mScript;
+ // Renderscript object
+ private ScriptC_fountain mScript;
- public HelloWorldRS() {
- }
-
- /**
- * This provides us with the RenderScript context and resources
- * that allow us to create the RenderScript object
- */
+ // Called by the view class to initialize the Renderscript context and renderer
public void init(RenderScriptGL rs, Resources res) {
mRS = rs;
mRes = res;
- initRS();
- }
- /**
- * Calls native RenderScript functions (set_gTouchX and set_gTouchY)
- * through the reflected layer class ScriptC_helloworld to pass in
- * touch point data.
- */
- public void onActionDown(int x, int y) {
- mScript.set_gTouchX(x);
- mScript.set_gTouchY(y);
- }
- /**
- * Binds the RenderScript object to the RenderScript context
- */
- private void initRS() {
- //create the RenderScript object
- mScript = new ScriptC_helloworld(mRS, mRes, R.raw.helloworld);
- //bind the RenderScript object to the RenderScript context
+
+ /**
+ * Create a shader and bind to the Renderscript context
+ */
+ ProgramFragmentFixedFunction.Builder pfb = new ProgramFragmentFixedFunction.Builder(rs);
+ pfb.setVaryingColor(true);
+ rs.bindProgramFragment(pfb.create());
+
+ /**
+ * Allocate memory for the particles to render and create the mesh to draw
+ */
+ ScriptField_Point points = new ScriptField_Point(mRS, PART_COUNT);
+ Mesh.AllocationBuilder smb = new Mesh.AllocationBuilder(mRS);
+ smb.addVertexAllocation(points.getAllocation());
+ smb.addIndexSetType(Mesh.Primitive.POINT);
+ Mesh sm = smb.create();
+
+ /**
+ * Create and bind the Renderscript object to the Renderscript context
+ */
+ mScript = new ScriptC_fountain(mRS, mRes, R.raw.fountain);
+ mScript.set_partMesh(sm);
+ mScript.bind_point(points);
mRS.bindRootScript(mScript);
}
-}
+ boolean holdingColor[] = new boolean[10];
+
+ /**
+ * Calls Renderscript functions (invoke_addParticles)
+ * via the Renderscript object to add particles to render
+ * based on where a user touches the screen.
+ */
+ public void newTouchPosition(float x, float y, float pressure, int id) {
+ if (id >= holdingColor.length) {
+ return;
+ }
+ int rate = (int)(pressure * pressure * 500.f);
+ if (rate > 500) {
+ rate = 500;
+ }
+ if (rate > 0) {
+ mScript.invoke_addParticles(rate, x, y, id, !holdingColor[id]);
+ holdingColor[id] = true;
+ } else {
+ holdingColor[id] = false;
+ }
+
+ }
+}
</pre>
- <h3 id="creating-view">Creating the surface view</h3>
- <p>To create a surface view to render graphics on, create a class that extends {@link
- android.renderscript.RSSurfaceView}. This class also creates a RenderScript context object
- ({@link android.renderscript.RenderScriptGL} and passes it to the Rendscript entry point class to
- bind the two. The following code shows how the <code>HelloWorldView</code> class is
- implemented:</p>
+ <h3 id="creating-view">Creating the view class</h3>
+
+
+ <p>To display graphics, you need a view to render on. Create a class that extends {@link
+ android.renderscript.RSSurfaceView} or {@link android.renderscript.RSTextureView}. This class
+ allows you to create a {@link android.renderscript.RenderScriptGL} context object by calling and
+ pass it to the Rendscript entry point class to bind the two. Once bound, the content is aware
+ of the code that it needs to use to render graphics with. If your Renderscript code
+ depends on any type of information that the view is aware of, such as touches from the user,
+ you can also use this class to relay that information to the Renderscript entry point class.
+ The following code shows how the <code>FountainView</code> class is implemented:</p>
<pre>
-package com.android.rs.helloworld;
+package com.example.android.rs.fountain;
-import android.renderscript.RSSurfaceView;
+import android.renderscript.RSTextureView;
import android.renderscript.RenderScriptGL;
import android.content.Context;
import android.view.MotionEvent;
-public class HelloWorldView extends RSSurfaceView {
- // RenderScript context
- private RenderScriptGL mRS;
- // RenderScript entry point object that does the rendering
- private HelloWorldRS mRender;
+public class FountainView extends RSTextureView {
- public HelloWorldView(Context context) {
+ public FountainView(Context context) {
super(context);
- initRS();
}
+ // Renderscript context
+ private RenderScriptGL mRS;
+ // Renderscript entry point object that calls Renderscript code
+ private FountainRS mRender;
- private void initRS() {
+ /**
+ * Create Renderscript context and initialize Renderscript entry point
+ */
+ @Override
+ protected void onAttachedToWindow() {
+ super.onAttachedToWindow();
+ android.util.Log.e("rs", "onAttachedToWindow");
if (mRS == null) {
- // Initialize RenderScript with default surface characteristics.
RenderScriptGL.SurfaceConfig sc = new RenderScriptGL.SurfaceConfig();
- //Create the RenderScript context
mRS = createRenderScriptGL(sc);
- // Create an instance of the RenderScript entry point class
- mRender = new HelloWorldRS();
- // Call the entry point class to bind it to this context
+ mRender = new FountainRS();
mRender.init(mRS, getResources());
}
}
- /**
- * Rebind everything when the window becomes attached
- */
- protected void onAttachedToWindow() {
- super.onAttachedToWindow();
- initRS();
- }
-
- /**
- * Stop rendering when window becomes detached
- */
+ @Override
protected void onDetachedFromWindow() {
- // Handle the system event and clean up
- mRender = null;
+ super.onDetachedFromWindow();
+ android.util.Log.e("rs", "onDetachedFromWindow");
if (mRS != null) {
mRS = null;
destroyRenderScriptGL();
}
}
- /**
- * Use callbacks to relay data to RenderScript entry point class
- */
- public boolean onTouchEvent(MotionEvent ev) {
- // Pass touch events from the system to the rendering script
- if (ev.getAction() == MotionEvent.ACTION_DOWN) {
- mRender.onActionDown((int)ev.getX(), (int)ev.getY());
- return true;
- }
- return false;
+ /**
+ * Use callbacks to relay data to Renderscript entry point class
+ */
+ @Override
+ public boolean onTouchEvent(MotionEvent ev)
+ {
+ int act = ev.getActionMasked();
+ if (act == ev.ACTION_UP) {
+ mRender.newTouchPosition(0, 0, 0, ev.getPointerId(0));
+ return false;
+ } else if (act == MotionEvent.ACTION_POINTER_UP) {
+ // only one pointer going up, we can get the index like this
+ int pointerIndex = ev.getActionIndex();
+ int pointerId = ev.getPointerId(pointerIndex);
+ mRender.newTouchPosition(0, 0, 0, pointerId);
+ }
+ int count = ev.getHistorySize();
+ int pcount = ev.getPointerCount();
+
+ for (int p=0; p < pcount; p++) {
+ int id = ev.getPointerId(p);
+ mRender.newTouchPosition(ev.getX(p),
+ ev.getY(p),
+ ev.getPressure(p),
+ id);
+
+ for (int i=0; i < count; i++) {
+ mRender.newTouchPosition(ev.getHistoricalX(p, i),
+ ev.getHistoricalY(p, i),
+ ev.getHistoricalPressure(p, i),
+ id);
+ }
+ }
+ return true;
}
}
-
</pre>
- <h3 id="creating-activity">Creating the Activity</h3>
+ <h3 id="creating-activity">Creating the activity class</h3>
- <p>Applications that use RenderScript still adhere to activity lifecyle, and are part of the same
- view hierarchy as traditional Android applications, which is handled by the Android VM. This
- Activity class sets its view to be the {@link android.renderscript.RSSurfaceView} and handles
- lifecycle callback events appropriately. The following code shows how the <code>HelloWorld</code>
- class is implemented:</p>
+ <p>Applications that use Renderscript still behave like normal Android applications, so you
+ need an activity class that handles activity lifecycle callback events appropriately. The activity class
+ also sets your {@link android.renderscript.RSSurfaceView} view class to be the main content view of the
+ activity or uses your {@link android.renderscript.RSTextureView}
+ in a {@link android.view.ViewGroup} alongside other views.</p>
+
+ <p>The following code shows how the <a href="{@docRoot}resources/samples/RenderScript/Fountain/index.html">Fountain</a>
+ sample declares its activity class:</p>
<pre>
-public class HelloWorldActivity extends Activity {
+package com.example.android.rs.fountain;
- //Custom view to use with RenderScript
- private HelloWorldView view;
+import android.app.Activity;
+import android.os.Bundle;
+import android.util.Log;
+public class Fountain extends Activity {
+
+ private static final String LOG_TAG = "libRS_jni";
+ private static final boolean DEBUG = false;
+ private static final boolean LOG_ENABLED = false;
+
+ private FountainView mView;
+
+ @Override
public void onCreate(Bundle icicle) {
super.onCreate(icicle);
- // Create surface view and set it as the content of our Activity
- mView = new HelloWorldView(this);
- setContentView(view);
+
+ // Create our Preview view and set it as
+ // the content of our activity
+ mView = new FountainView(this);
+ setContentView(mView);
}
+ @Override
protected void onResume() {
- // Ideally an app should implement onResume() and onPause()
- // to take appropriate action when the activity loses focus
+ Log.e("rs", "onResume");
+
+ // Ideally a game should implement onResume() and onPause()
+ // to take appropriate action when the activity looses focus
super.onResume();
- view.resume();
+ mView.resume();
}
+ @Override
protected void onPause() {
- // Ideally an app should implement onResume() and onPause()
- // to take appropriate action when the activity loses focus
+ Log.e("rs", "onPause");
+
+ // Ideally a game should implement onResume() and onPause()
+ // to take appropriate action when the activity looses focus
super.onPause();
- view.pause();
+ mView.pause();
+
+ }
+
+ static void log(String message) {
+ if (LOG_ENABLED) {
+ Log.v(LOG_TAG, message);
+ }
}
}
</pre>
+<p>Now that you have an idea of what is involved in a Renderscript graphics application, you can
+start building your own. It might be easiest to begin with one of the
+<a href="{@docRoot}resources/samples/RenderScript/index.html">Renderscript samples</a> as a starting
+point if this is your first time using Renderscript.</p>
+
<h2 id="drawing">Drawing</h2>
<p>The following sections describe how to use the graphics functions to draw with Renderscript.</p>
- <h3 id="drawing-rsg">Drawing using the rsgDraw functions</h3>
- <p>The native RenderScript APIs provide a few convenient functions to easily draw a polygon to
- the screen. You call these in your <code>root()</code> function to have them render to the
- surface view. These functions are available for simple drawing and should not be used for complex
- graphics rendering:</p>
+ <h3 id="drawing-rsg">Simple drawing</h3>
+
+ <p>The native Renderscript APIs provide a few convenient functions to easily draw a polygon or text to
+ the screen. You call these in your <code>root()</code> function to have them render to the {@link
+ android.renderscript.RSSurfaceView} or {@link android.renderscript.RSTextureView}. These functions are
+ available for simple drawing and should not be used for complex graphics rendering:</p>
<ul>
<li><code>rsgDrawRect()</code>: Sets up a mesh and draws a rectangle to the screen. It uses the
@@ -360,31 +531,32 @@
<li><code>rsgDrawQuad()</code>: Sets up a mesh and draws a quadrilateral to the screen.</li>
- <li><code>rsgDrawQuadTexCoords()</code>: Sets up a mesh and draws a textured quadrilateral to
- the screen.</li>
+ <li><code>rsgDrawQuadTexCoords()</code>: Sets up a mesh and draws a quadrilateral to the screen
+ using the provided coordinates of a texture.</li>
+
+ <li><code>rsgDrawText()</code>: Draws specified text to the screen. Use <code>rsgFontColor()</code>
+ to set the color of the text.</li>
</ul>
<h3 id="drawing-mesh">Drawing with a mesh</h3>
- <p>When you want to draw complex shapes and textures to the screen, instantiate a {@link
- android.renderscript.Mesh} and draw it to the screen with <code>rsgDrawMesh()</code>. A {@link
+ <p>When you want to render complex scenes to the screen, instantiate a {@link
+ android.renderscript.Mesh} and draw it with <code>rsgDrawMesh()</code>. A {@link
android.renderscript.Mesh} is a collection of allocations that represent vertex data (positions,
- normals, texture coordinates) and index data such as triangles and lines. You can build a Mesh in
- three different ways:</p>
+ normals, texture coordinates) and index data that provides information on how to draw triangles
+ and lines with the provided vertex data. You can build a Mesh in three different ways:</p>
<ul>
<li>Build the mesh with the {@link android.renderscript.Mesh.TriangleMeshBuilder} class, which
- allows you to specify a set of vertices and indices for each triangle that you want to draw.
- The downside of doing it this way is there is no way to specify the vertices in your native
- RenderScript code.</li>
+ allows you to specify a set of vertices and indices for each triangle that you want to draw.</li>
<li>Build the mesh using an {@link android.renderscript.Allocation} or a set of {@link
android.renderscript.Allocation}s with the {@link android.renderscript.Mesh.AllocationBuilder}
- class. This allows you to build a mesh with vertices already stored in memory, which allows you
- to set the vertices in native or Android code.</li>
+ class. This approach allows you to build a mesh with vertices already stored in memory, which allows you
+ to specify the vertices in Renderscript or Android framework code.</li>
- <li>Build the mesh with the {@link android.renderscript.Mesh.Builder} class. This is a
- convenience method for when you know what data types you want to use to build your mesh, but
+ <li>Build the mesh with the {@link android.renderscript.Mesh.Builder} class. You should use
+ this convenience method when you know the data types you want to use to build your mesh, but
don't want to make separate memory allocations like with {@link
android.renderscript.Mesh.AllocationBuilder}. You can specify the types that you want and this
mesh builder automatically creates the memory allocations for you.</li>
@@ -421,7 +593,7 @@
script.set_mesh(smP);
</pre>
- <p>In your native RenderScript code, draw the built mesh to the screen:</p>
+ <p>In your Renderscript code, draw the built mesh to the screen:</p>
<pre>
rs_mesh mesh;
...
@@ -435,18 +607,18 @@
}
</pre>
- <h2 id="shaders">Shaders</h2>
+ <h2 id="shader">Programs</h2>
<p>You can attach four program objects to the {@link android.renderscript.RenderScriptGL} context
to customize the rendering pipeline. For example, you can create vertex and fragment shaders in
- GLSL or build a raster program object with provided methods without writing GLSL code. The four
- program objects mirror a traditional graphical rendering pipeline:</p>
+ GLSL or build a raster program object that controls culling. The four programs mirror a
+ traditional graphical rendering pipeline:</p>
<table>
<tr>
<th>Android Object Type</th>
- <th>RenderScript Native Type</th>
+ <th>Renderscript Native Type</th>
<th>Description</th>
</tr>
@@ -457,17 +629,17 @@
<td>rs_program_vertex</td>
<td>
- <p>The RenderScript vertex program, also known as a vertex shader, describes the stage in
+ <p>The Renderscript vertex program, also known as a vertex shader, describes the stage in
the graphics pipeline responsible for manipulating geometric data in a user-defined way.
- The object is constructed by providing RenderScript with the following data:</p>
+ The object is constructed by providing Renderscript with the following data:</p>
<ul>
- <li>An Element describing its varying inputs or attributes</li>
+ <li>An {@link android.renderscript.Element} describing its varying inputs or attributes</li>
<li>GLSL shader string that defines the body of the program</li>
- <li>a Type that describes the layout of an Allocation containing constant or uniform
- inputs</li>
+ <li>a {@link android.renderscript.Type} that describes the layout of an
+ Allocation containing constant or uniform inputs</li>
</ul>
<p>Once the program is created, bind it to the {@link android.renderscript.RenderScriptGL}
@@ -475,22 +647,29 @@
bindProgramVertex()}. It is then used for all subsequent draw calls until you bind a new
program. If the program has constant inputs, the user needs to bind an allocation
containing those inputs. The allocation's type must match the one provided during creation.
- The RenderScript library then does all the necessary plumbing to send those constants to
- the graphics hardware. Varying inputs to the shader, such as position, normal, and texture
- coordinates are matched by name between the input Element and the Mesh object being drawn.
- The signatures don't have to be exact or in any strict order. As long as the input name in
- the shader matches a channel name and size available on the mesh, the run-time would take
- care of connecting the two. Unlike OpenGL, there is no need to link the vertex and fragment
- programs.</p>
+ </p>
- <p>To bind shader constructs to the Program, declare a struct containing the necessary
- shader constants in your native RenderScript code. This struct is generated into a
- reflected class that you can use as a constant input element during the Program's creation.
- It is an easy way to create an instance of this struct as an allocation. You would then
- bind this Allocation to the Program and the RenderScript system sends the data that is
- contained in the struct to the hardware when necessary. To update shader constants, you
- change the values in the Allocation and notify the native RenderScript code of the
- change.</p>
+ <p>The Renderscript runtime then does all the necessary plumbing to send those constants to
+ the graphics hardware. Varying inputs to the shader, such as position, normal, and texture
+ coordinates are matched by name between the input {@link android.renderscript.Element}
+ and the mesh object that is being drawn. The signatures don't have to be exact or in any
+ strict order. As long as the input name in the shader matches a channel name and size
+ available on the mesh, the Renderscript runtime handles connecting the two. Unlike OpenGL
+ there is no need to link the vertex and fragment programs.</p>
+
+ <p>To bind shader constants to the program, declare a <code>struct</code> that contains the necessary
+ shader constants in your Renderscript code. This <code>struct</code> is generated into a
+ reflected class that you can use as a constant input element during the program's creation.
+ It is an easy way to create an instance of this <code>struct</code> as an allocation. You would then
+ bind this {@link android.renderscript.Allocation} to the program and the
+ Renderscript runtime sends the data that is contained in the <code>struct</code> to the hardware
+ when necessary. To update shader constants, you change the values in the
+ {@link android.renderscript.Allocation} and notify the Renderscript
+ code of the change.</p>
+
+ <p>The {@link android.renderscript.ProgramVertexFixedFunction.Builder} class also
+ lets you build a simple vertex shader without writing GLSL code.
+ </p>
</td>
</tr>
@@ -500,26 +679,33 @@
<td>rs_program_fragment</td>
<td>
- <p>The RenderScript fragment program, also known as the fragment shader, is responsible for
+ <p>The Renderscript fragment program, also known as a fragment shader, is responsible for
manipulating pixel data in a user-defined way. It's constructed from a GLSL shader string
- containing the program body, textures inputs, and a Type object describing the constants
- used by the program. Like the vertex programs, when an allocation with constant input
+ containing the program body, texture inputs, and a {@link android.renderscript.Type}
+ object that describes the constants
+ used by the program. Like the vertex programs, when an {@link android.renderscript.Allocation}
+ with constant input
values is bound to the shader, its values are sent to the graphics program automatically.
- Note that the values inside the allocation are not explicitly tracked. If they change
- between two draw calls using the same program object, notify the runtime of that change by
- calling rsgAllocationSyncAll so it could send the new values to hardware. Communication
+ Note that the values inside the {@link android.renderscript.Allocation} are not explicitly tracked.
+ If they change between two draw calls using the same program object, notify the runtime of that change by
+ calling <code>rsgAllocationSyncAll()</code>, so it can send the new values to hardware. Communication
between the vertex and fragment programs is handled internally in the GLSL code. For
- example, if the fragment program is expecting a varying input called varTex0, the GLSL code
+ example, if the fragment program is expecting a varying input called <code>varTex0</code>, the GLSL code
inside the program vertex must provide it.</p>
- <p>To bind shader constants to this program, declare a struct containing the necessary
- shader constants in your native RenderScript code. This struct is generated into a
- reflected class that you can use as a constant input element during the Program's creation.
- It is an easy way to create an instance of this struct as an allocation. You would then
- bind this Allocation to the Program and the RenderScript system sends the data that is
- contained in the struct to the hardware when necessary. To update shader constants, you
- change the values in the Allocation and notify the native RenderScript code of the
- change.</p>
+ <p>To bind shader constructs to the program, declare a <code>struct</code> that contains the necessary
+ shader constants in your Renderscript code. This <code>struct</code> is generated into a
+ reflected class that you can use as a constant input element during the program's creation.
+ It is an easy way to create an instance of this <code>struct</code> as an allocation. You would then
+ bind this {@link android.renderscript.Allocation} to the program and the
+ Renderscript runtime sends the data that is contained in the <code>struct</code> to the hardware
+ when necessary. To update shader constants, you change the values in the
+ {@link android.renderscript.Allocation} and notify the Renderscript
+ code of the change.</p>
+
+ <p>The {@link android.renderscript.ProgramFragmentFixedFunction.Builder} class also
+ lets you build a simple fragment shader without writing GLSL code.
+ </p>
</td>
</tr>
@@ -528,7 +714,7 @@
<td>rs_program_store</td>
- <td>The RenderScript ProgramStore contains a set of parameters that control how the graphics
+ <td>The Renderscript store program contains a set of parameters that control how the graphics
hardware writes to the framebuffer. It could be used to enable and disable depth writes and
testing, setup various blending modes for effects like transparency and define write masks
for color components.</td>
@@ -539,12 +725,12 @@
<td>rs_program_raster</td>
- <td>Program raster is primarily used to specify whether point sprites are enabled and to
+ <td>The Renderscript raster program is primarily used to specify whether point sprites are enabled and to
control the culling mode. By default back faces are culled.</td>
</tr>
</table>
- <p>The following example defines a vertex shader in GLSL and binds it to the RenderScript:</p>
+ <p>The following example defines a vertex shader in GLSL and binds it to a Renderscript context object:</p>
<pre>
private RenderScriptGL glRenderer; //rendering context
private ScriptField_Point mPoints; //vertices
@@ -567,49 +753,37 @@
ProgramVertex pvs = sb.create();
pvs.bindConstants(mVpConsts.getAllocation(), 0);
glRenderer.bindProgramVertex(pvs);
-
-
</pre>
+
<p>The <a href=
"{@docRoot}resources/samples/RenderScript/MiscSamples/src/com/example/android/rs/miscsamples/RsRenderStatesRS.html">
RsRenderStatesRS</a> sample has many examples on how to create a shader without writing GLSL.</p>
- <h3 id="shader-bindings">Shader bindings</h3>
+ <h3 id="shader-bindings">Program bindings</h3>
- <p>You can also set four pragmas that control the shaders' default bindings to the {@link
+ <p>You can also declare four pragmas that control default program bindings to the {@link
android.renderscript.RenderScriptGL} context when the script is executing:</p>
<ul>
- <li>stateVertex</li>
+ <li><code>stateVertex</code></li>
- <li>stateFragment</li>
+ <li><code>stateFragment</code></li>
- <li>stateRaster</li>
+ <li><code>stateRaster</code></li>
- <li>stateStore</li>
+ <li><code>stateStore</code></li>
</ul>
<p>The possible values for each pragma are <code>parent</code> or <code>default</code>. Using
- <code>default</code> binds the shaders to the graphical context with the system defaults. The
- default shader is defined below:</p>
- <pre>
-("varying vec4 varColor;\n");
-("varying vec2 varTex0;\n");
-("void main() {\n");
-(" gl_Position = UNI_MVP * ATTRIB_position;\n");
-(" gl_PointSize = 1.0;\n");
-(" varColor = ATTRIB_color;\n");
-(" varTex0 = ATTRIB_texture0;\n");
-("}\n");
-</pre>
+ <code>default</code> binds the shaders to the graphical context with the system defaults.</p>
<p>Using <code>parent</code> binds the shaders in the same manner as it is bound in the calling
script. If this is the root script, the parent state is taken from the bind points that are set
by the {@link android.renderscript.RenderScriptGL} bind methods.</p>
- <p>For example, you can define this at the top of your native graphics RenderScript code to have
- the Vertex and Store shaders inherent the bind properties from their parent scripts:</p>
+ <p>For example, you can define this at the top of your graphics Renderscript code to have
+ the vertex and store programs inherent the bind properties from their parent scripts:</p>
<pre>
#pragma stateVertex(parent)
#pragma stateStore(parent)
@@ -618,18 +792,202 @@
<h3 id="shader-sampler">Defining a sampler</h3>
<p>A {@link android.renderscript.Sampler} object defines how data is extracted from textures.
- Samplers are bound to Program objects (currently only a Fragment Program) alongside the texture
- whose sampling they control. These objects are used to specify such things as edge clamping
- behavior, whether mip-maps are used, and the amount of anisotropy required. There might be
- situations where hardware does not support the desired behavior of the sampler. In these cases,
- the runtime attempts to provide the closest possible approximation. For example, the user
- requested 16x anisotropy, but only 8x was set because it's the best available on the
- hardware.</p>
+ Samplers are bound to a {@link android.renderscript.ProgramFragment} alongside the texture
+ whose sampling they control. These
+ objects are used to specify such things as edge clamping behavior, whether mip-maps are used, and
+ the amount of anisotropy required. There might be situations where hardware does not support the
+ desired behavior of the sampler. In these cases, the Renderscript runtime attempts to provide the
+ closest possible approximation. For example, the user requested 16x anisotropy, but only 8x was
+ set because it's the best available on the hardware.</p>
<p>The <a href=
"{@docRoot}resources/samples/RenderScript/MiscSamples/src/com/example/android/rs/miscsamples/RsRenderStatesRS.html">
RsRenderStatesRS</a> sample has many examples on how to create a sampler and bind it to a
Fragment program.</p>
-
-</body>
-</html>
+
+
+
+<h2 id="fbo">Rendering to a Framebuffer Object</h2>
+
+<p>Framebuffer objects allow you to render offscreen instead of in the default onscreen
+framebuffer. This approach might be useful for situations where you need to post-process a texture before
+rendering it to the screen, or when you want to composite two scenes in one such as rendering a rear-view
+mirror of a car. There are two buffers associated with a framebuffer object: a color buffer
+and a depth buffer. The color buffer (required) contains the actual pixel data of the scene
+that you are rendering, and the depth buffer (optional) contains the values necessary to figure
+out what vertices are drawn depending on their z-values.</p>
+
+<p>In general, you need to do the following to render to a framebuffer object:</p>
+
+<ul>
+ <li>Create {@link android.renderscript.Allocation} objects for the color buffer and
+ depth buffer (if needed). Specify the {@link
+ android.renderscript.Allocation#USAGE_GRAPHICS_RENDER_TARGET} usage attribute for these
+ allocations to notify the Renderscript runtime to use these allocations for the framebuffer
+ object. For the color buffer allocation, you most likely need to declare the {@link
+ android.renderscript.Allocation#USAGE_GRAPHICS_TEXTURE} usage attribute
+ to use the color buffer as a texture, which is the most common use of the framebuffer object.</li>
+
+ <li>Tell the Renderscript runtime to render to the framebuffer object instead of the default
+ framebuffer by calling <code>rsgBindColorTarget()</code> and passing it the color buffer
+ allocation. If applicable, call <code>rsgBindDepthTarget()</code> passing in the depth buffer
+ allocation as well.</li>
+
+ <li>Render your scene normally with the <code>rsgDraw</code> functions. The scene will be
+ rendered into the color buffer instead of the default onscreen framebuffer.</li>
+
+ <li>When done, tell the Renderscript runtime stop rendering to the color buffer and back
+ to the default framebuffer by calling <code>rsgClearAllRenderTargets()</code>.</li>
+
+ <li>Create a fragment shader and bind a the color buffer to it as a texture.</li>
+
+ <li>Render your scene to the default framebuffer. The texture will be used according
+ to the way you setup your fragment shader.</li>
+</ul>
+
+<p>The following example shows you how to render to a framebuffer object by modifying the
+<a href="{@docRoot}guide/resources/renderscript/Fountain/">Fountain</a> Renderscript sample. The end
+result is the <a href="{@docRoot}guide/resources/renderscript/FountainFBO/">FountainFBO</a> sample.
+The modifications render the exact same scene into a framebuffer object as it does the default
+framebuffer. The framebuffer object is then rendered into the default framebuffer in a small
+area at the top left corner of the screen.</p>
+
+<ol>
+ <li>Modify <code>fountain.rs</code> and add the following global variables. This creates setter
+ methods when this file is reflected into a <code>.java</code> file, allowing you to allocate
+ memory in your Android framework code and binding it to the Renderscript runtime.
+<pre>
+//allocation for color buffer
+rs_allocation gColorBuffer;
+//fragment shader for rendering without a texture (used for rendering to framebuffer object)
+rs_program_fragment gProgramFragment;
+//fragment shader for rendering with a texture (used for rendering to default framebuffer)
+rs_program_fragment gTextureProgramFragment;
+</pre>
+ </li>
+
+ <li>Modify the root function of <code>fountain.rs</code> to look like the following code. The
+ modifications are commented:
+<pre>
+int root() {
+ float dt = min(rsGetDt(), 0.1f);
+ rsgClearColor(0.f, 0.f, 0.f, 1.f);
+ const float height = rsgGetHeight();
+ const int size = rsAllocationGetDimX(rsGetAllocation(point));
+ float dy2 = dt * (10.f);
+ Point_t * p = point;
+ for (int ct=0; ct < size; ct++) {
+ p->delta.y += dy2;
+ p->position += p->delta;
+ if ((p->position.y > height) && (p->delta.y > 0)) {
+ p->delta.y *= -0.3f;
+ }
+ p++;
+ }
+ //Tell Renderscript runtime to render to the frame buffer object
+ rsgBindColorTarget(gColorBuffer, 0);
+ //Begin rendering on a white background
+ rsgClearColor(1.f, 1.f, 1.f, 1.f);
+ rsgDrawMesh(partMesh);
+
+ //When done, tell Renderscript runtime to stop rendering to framebuffer object
+ rsgClearAllRenderTargets();
+
+ //Bind a new fragment shader that declares the framebuffer object to be used as a texture
+ rsgBindProgramFragment(gTextureProgramFragment);
+
+ //Bind the framebuffer object to the fragment shader at slot 0 as a texture
+ rsgBindTexture(gTextureProgramFragment, 0, gColorBuffer);
+ //Draw a quad using the framebuffer object as the texture
+ float startX = 10, startY = 10;
+ float s = 256;
+ rsgDrawQuadTexCoords(startX, startY, 0, 0, 1,
+ startX, startY + s, 0, 0, 0,
+ startX + s, startY + s, 0, 1, 0,
+ startX + s, startY, 0, 1, 1);
+
+ //Rebind the original fragment shader to render as normal
+ rsgBindProgramFragment(gProgramFragment);
+
+ //Render the main scene
+ rsgDrawMesh(partMesh);
+
+ return 1;
+}
+</pre>
+ </li>
+
+ <li>In the <code>FountainRS.java</code> file, modify the <code>init()</code> method to look
+ like the following code. The modifications are commented:
+
+<pre>
+/* Add necessary members */
+private ScriptC_fountainfbo mScript;
+private Allocation mColorBuffer;
+private ProgramFragment mProgramFragment;
+private ProgramFragment mTextureProgramFragment;
+
+public void init(RenderScriptGL rs, Resources res) {
+ mRS = rs;
+ mRes = res;
+
+ ScriptField_Point points = new ScriptField_Point(mRS, PART_COUNT);
+
+ Mesh.AllocationBuilder smb = new Mesh.AllocationBuilder(mRS);
+ smb.addVertexAllocation(points.getAllocation());
+ smb.addIndexSetType(Mesh.Primitive.POINT);
+ Mesh sm = smb.create();
+
+ mScript = new ScriptC_fountainfbo(mRS, mRes, R.raw.fountainfbo);
+ mScript.set_partMesh(sm);
+ mScript.bind_point(points);
+
+ ProgramFragmentFixedFunction.Builder pfb = new ProgramFragmentFixedFunction.Builder(rs);
+ pfb.setVaryingColor(true);
+ mProgramFragment = pfb.create();
+ mScript.set_gProgramFragment(mProgramFragment);
+
+ /* Second fragment shader to use a texture (framebuffer object) to draw with */
+ pfb.setTexture(ProgramFragmentFixedFunction.Builder.EnvMode.REPLACE,
+ ProgramFragmentFixedFunction.Builder.Format.RGBA, 0);
+
+ /* Set the fragment shader in the Renderscript runtime */
+ mTextureProgramFragment = pfb.create();
+ mScript.set_gTextureProgramFragment(mTextureProgramFragment);
+
+ /* Create the allocation for the color buffer */
+ Type.Builder colorBuilder = new Type.Builder(mRS, Element.RGBA_8888(mRS));
+ colorBuilder.setX(256).setY(256);
+ mColorBuffer = Allocation.createTyped(mRS, colorBuilder.create(),
+ Allocation.USAGE_GRAPHICS_TEXTURE |
+ Allocation.USAGE_GRAPHICS_RENDER_TARGET);
+
+ /* Set the allocation in the Renderscript runtime */
+ mScript.set_gColorBuffer(mColorBuffer);
+
+ mRS.bindRootScript(mScript);
+}
+</pre>
+
+<p class="note"><strong>Note:</strong> This sample doesn't use a depth buffer, but the following code
+shows you how to declare an example depth buffer if you need to use
+one for your application. The depth buffer must have the same dimensions as the color buffer:
+
+<pre>
+Allocation mDepthBuffer;
+
+...
+
+Type.Builder b = new Type.Builder(mRS, Element.createPixel(mRS, DataType.UNSIGNED_16,
+ DataKind.PIXEL_DEPTH));
+b.setX(256).setY(256);
+mDepthBuffer = Allocation.createTyped(mRS, b.create(),
+Allocation.USAGE_GRAPHICS_RENDER_TARGET);
+
+</pre>
+</p>
+</li>
+
+ <li>Run and use the sample. The smaller, white quad on the top-left corner is using the
+ framebuffer object as a texture, which renders the same scene as the main rendering.</li>
+</ol>
diff --git a/docs/html/guide/topics/renderscript/index.jd b/docs/html/guide/topics/renderscript/index.jd
index 63f341a..a0e8876 100644
--- a/docs/html/guide/topics/renderscript/index.jd
+++ b/docs/html/guide/topics/renderscript/index.jd
@@ -1,4 +1,4 @@
-page.title=RenderScript
+page.title=Renderscript
@jd:body
<div id="qv-wrapper">
@@ -6,14 +6,14 @@
<h2>In this document</h2>
<ol>
- <li><a href="#overview">RenderScript System Overview</a></li>
- <li>
+ <li><a href="#overview">Renderscript Overview</a></li>
+ <li><a href="#native">Renderscript Runtime Layer</a></li>
+ <li><a href="#reflected">Reflected Layer</a>
<ol>
- <li><a href="#native">Native RenderScript layer</a></li>
-
- <li><a href="#reflected">Reflected layer</a></li>
-
- <li><a href="#framework">Android framework layer</a></li>
+ <li><a href="#func">Functions</a></li>
+ <li><a href="#var">Variables</a></li>
+ <li><a href="#pointer">Pointers</a></li>
+ <li><a href="#struct">Structs</a></li>
</ol>
</li>
@@ -21,540 +21,329 @@
<a href="#mem-allocation">Memory Allocation APIs</a>
</li>
<li>
- <a href="#dynamic">Dynamic Memory Allocations</a>
+ <a href="#memory">Working with Memory</a>
<ol>
- <li><a href="#pointers">Declaring pointers</a></li>
+ <li><a href="#allocating-mem">Allocating and binding memory to the Renderscript</a></li>
- <li><a href="#struct-pointer-reflection">How pointers are reflected</a></li>
-
- <li><a href="#binding">Allocating and binding memory to the RenderScript</a></li>
-
- <li><a href="#read-write-dynamic">Reading and writing to memory</a></li>
+ <li><a href="#read-write">Reading and writing to memory</a></li>
</ol>
</li>
- <li>
- <a href="#static">Static Memory Allocations</a>
- </li>
</ol>
</div>
</div>
- <p>RenderScript offers a high performance 3D graphics rendering and compute API at the native
- level, which you write in the C (C99 standard). The main advantages of RenderScript are:</p>
+ <p>Renderscript offers a high performance 3D graphics rendering and compute API at the native
+ level that you write in C (C99 standard). The main advantages of Renderscript are:</p>
<ul>
- <li>Portability: RenderScript is designed to run on many types of devices with different CPU
- and GPU architectures. It supports all of these architectures without having to target each
- device, because the code is compiled and cached on the device at runtime.</li>
+ <li>Portability: Renderscript is designed to run on many types of devices with different
+ processor (CPU, GPU, and DSP for instance) architectures. It supports all of these architectures without
+ having to target each device, because the code is compiled and cached on the device
+ at runtime.</li>
- <li>Performance: RenderScript provides similar performance to OpenGL with the NDK while
- offering the portability of the OpenGL APIs provided by the Android framework ({@link
- android.opengl}). In addition, it also offers a high performance compute API that is not
- offered by OpenGL.</li>
+ <li>Performance: Renderscript provides similar performance to OpenGL with the NDK and also
+ provides a high performance compute API that is not offered by OpenGL.</li>
- <li>Usability: RenderScript simplifies development when possible, such as eliminating JNI glue code
+ <li>Usability: Renderscript simplifies development when possible, such as eliminating JNI glue code
and simplifying mesh setup.</li>
</ul>
<p>The main disadvantages are:</p>
<ul>
- <li>Development complexity: RenderScript introduces a new set of APIs that you have to learn.
- RenderScript also handles memory differently compared to OpenGL with the Android framework APIs
- or NDK.</li>
+ <li>Development complexity: Renderscript introduces a new set of APIs that you have to learn.
+ Renderscript also allocates memory differently compared to OpenGL with the Android framework APIs.
+ However, these issues are not hard to understand and Renderscript offers many features that
+ make it easier than OpenGL to initialize rendering.</li>
- <li>Debugging visibility: RenderScript can potentially execute (planned feature for later releases)
- on processors other than the main CPU (such as the GPU), so if this occurs, debugging becomes more difficult.
+ <li>Debugging visibility: Renderscript can potentially execute (planned feature for later releases)
+ on processors other than the main CPU (such as the GPU), so if this occurs, debugging becomes more difficult.
</li>
-
- <li>Less features: RenderScript does not provide as many features as OpenGL such as all the compressed
- texture formats or GL extensions.</li>
</ul>
- <p>You need to consider all of the aspects of RenderScript before deciding when to use it. The following list describes
- general guidelines on when to use OpenGL (framework APIs or NDK) or RenderScript:</p>
- <ul>
- <li>If you are doing simple graphics rendering and performance is not critical, you probably want to use the
- Android framework OpenGL APIs, which still provide adequate performance, to eliminate the added coding and debugging complexity of
- RenderScript.</li>
- <li>If you want the most flexibility and features while maintaining relatively good debugging
- support, you probably want to use OpenGL and the NDK. Applications that require this are high end
- or complicated games, for example.</li>
-
- <li>If you want a solution that is portable, has good performance,
- and you don't need the full feature set of OpenGL, RenderScript is a good solution. If you also
- need a high performance compute language, then RenderScript offers that as well.
- Good candidates for RenderScript are graphics intensive UIs that require 3D rendering, live wallpapers,
- or applications that require intensive mathematical computation.</li>
- </ul>
-
- <p>For an example of RenderScript in action, install the RenderScript sample applications that
+ <p>For an example of Renderscript in action, install the Renderscript sample applications that
are shipped with the SDK in <code><sdk_root>/samples/android-11/RenderScript</code>.
- You can also see a typical use of RenderScript with the 3D carousel view in the Android 3.x
+ You can also see a typical use of Renderscript with the 3D carousel view in the Android 3.x
versions of Google Books and YouTube.</p>
- <h2 id="overview">RenderScript System Overview</h2>
+ <h2 id="overview">Renderscript Overview</h2>
+ <p>The Renderscript runtime operates at the native level and still needs to communicate
+with the Android VM, so the way a Renderscript application is setup is different from a pure VM
+application. An application that uses Renderscript is still a traditional Android application that
+runs in the VM, but you write Renderscript code for the parts of your program that require
+it. Using Renderscript can be as simple as offloading a few math calculations or as complicated as
+rendering an entire 3D game. No matter what you use it for, Renderscript remains platform
+independent, so you do not have to target multiple architectures (for example,
+ARM v5, ARM v7, x86).</p>
- <p>The RenderScript system adopts a control and slave architecture where the low-level native
+ <p>The Renderscript system adopts a control and slave architecture where the low-level Renderscript runtime
code is controlled by the higher level Android system that runs in a virtual machine (VM). The
- Android VM still retains all control of memory and lifecycle management and calls the native
- RenderScript code when necessary. The native code is compiled to intermediate bytecode (LLVM) and
- packaged inside your application's <code>.apk</code> file. On the device, the bytecode is
- compiled (just-in-time) to machine code that is further optimized for the device that it is
- running on. The compiled code on the device is cached, so subsequent uses of the RenderScript
- enabled application do not recompile the intermediate code. RenderScript has three layers of code
- to enable communication between the native and Android framework code:</p>
+ Android VM still retains all control of memory management and binds memory that it allocates to
+ the Renderscript runtime, so the Renderscript code can access it. The Android framework makes
+asynchronous calls to Renderscript, and the calls are placed in a message queue and processed
+as soon as possible. Figure 1 shows how the Renderscript system is structured.</p>
+
+ <img id="figure1" src="{@docRoot}images/rs_overview.png" />
+ <p class="img-caption"><strong>Figure 1.</strong> Renderscript system overview</p>
+
+ <p>When using Renderscript, there are three layers of APIs that enable communication between the
+ Renderscript runtime and Android framework code:</p>
<ul>
- <li>The native RenderScript layer does the intensive computation or graphics rendering. You
- define your native code in <code>.rs</code> and <code>.rsh</code> files.</li>
+ <li>The Renderscript runtime APIs allow you to do the computation or graphics rendering
+ that is required by your application.</li>
- <li>The reflected layer is a set of classes that are reflected from the native code. It is basically
- a wrapper around the native code that allows the Android framework to interact with native RenderScripts.
- The Android build tools automatically generate the classes for this layer during
- the build process and eliminates the need to write JNI glue code, like with the NDK.</li>
+ <li>The reflected layer APIs are a set of classes that are reflected from your Renderscript
+runtime code. It is basically a wrapper around the Renderscript code that allows the Android
+framework to interact with the Renderscript runtime. The Android build tools automatically generate the
+classes for this layer during the build process. These classes eliminate the need to write JNI glue
+code, like with the NDK.</li>
- <li>The Android framework layer is comprised of the Android framework
- APIs, which include the {@link android.renderscript} package. This layer gives high level commands
- like, "rotate the view" or "filter the bitmap", by calling the reflected layer, which in turn calls
- the native layer. </li>
+ <li>The Android framework APIs, which include the {@link android.renderscript} package, allow you to
+ build your application using traditional Android components such as activities and views. When
+ using Renderscript, this layer calls the reflected layer to access the Renderscript
+ runtime.</li>
</ul>
- <h3 id="native">Native RenderScript layer</h3>
+ <p></p>
- <p>The native RenderScript layer consists of your RenderScript code, which is compiled and
- executed in a compact and well defined runtime. Your RenderScript code has access to a limited
- amount of functions because it cannot access the NDK or standard C functions, since they must be guaranteed to
- run on a standard CPU. The RenderScript runtime was designed to run on different types of processors,
- which may not be the CPU, so it cannot guarantee support for standard C libraries. What
- RenderScript does offer is an API that supports intensive computation and graphics rendering with a collection of math
- and graphics APIs.</p>
+ <h2 id="native">Renderscript Runtime Layer</h2>
- <p>Some key features of the native RenderScript libraries include:</p>
+ <p>Your Renderscript code is compiled and
+ executed in a compact and well-defined runtime layer. The Renderscript runtime APIs offer support for
+intensive computation and graphics rendering that is portable and automatically scalable to the
+amount of cores available on a processor.
+</p>
+<p class="note"><strong>Note:</strong> The standard C functions in the NDK must be
+ guaranteed to run on a CPU, so Renderscript cannot access these libraries,
+ because Renderscript is designed to run on different types of processors.</p>
+
+<p>You define your Renderscript code in <code>.rs</code>
+ and <code>.rsh</code> files in the <code>src/</code> directory of your Android project. The code
+ is compiled to intermediate bytecode by the
+ <code>llvm</code> compiler that runs as part of an Android build. When your application
+ runs on a device, the bytecode is then compiled (just-in-time) to machine code by another
+ <code>llvm</code> compiler that resides on the device. The machine code is optimized for the
+ device and also cached, so subsequent uses of the Renderscript enabled application does not
+ recompile the bytecode.</p>
+
+ <p>Some key features of the Renderscript runtime libraries include:</p>
<ul>
- <li>A large collection of math functions with both scalar and vector typed overloaded versions
- of many common routines. Operations such as adding, multiplying, dot product, and cross product
- are available.</li>
-
- <li>Conversion routines for primitive data types and vectors, matrix routines, date and time
- routines, and graphics routines.</li>
-
- <li>Logging functions</li>
<li>Graphics rendering functions</li>
<li>Memory allocation request features</li>
- <li>Data types and structures to support the RenderScript system such as Vector types for
+ <li>A large collection of math functions with both scalar and vector typed overloaded versions
+ of many common routines. Operations such as adding, multiplying, dot product, and cross product
+ are available as well as atomic arithmetic and comparison functions.</li>
+
+ <li>Conversion routines for primitive data types and vectors, matrix routines, date and time
+ routines, and graphics routines.</li>
+
+ <li>Data types and structures to support the Renderscript system such as Vector types for
defining two-, three-, or four-vectors.</li>
+
+ <li>Logging functions</li>
</ul>
- <p>The RenderScript header files and LLVM front-end libraries are located in the <code>include/</code> and
- <code>clang-include/</code> directories in the
- <code><sdk_root>/platforms/android-11/renderscript/</code> directory of the Android SDK. The
- headers are automatically included for you, except for the RenderScript graphics specific header file, which
+ <p>See the Renderscript runtime API reference for more information on the available functions. The
+ Renderscript header files are automatically included for you, except for the Renderscript graphics header file, which
you can include as follows:</p>
- <pre>
-#include "rs_graphics.rsh"
-</pre>
- <h3 id="reflected">Reflected layer</h3>
+<pre>#include "rs_graphics.rsh"</pre>
+
+ <h2 id="reflected">Reflected Layer</h2>
<p>The reflected layer is a set of classes that the Android build tools generate to allow access
- to the native RenderScript code from the Android VM. This layer defines entry points for
- RenderScript functions and variables, so that you can interact with them with the Android
- framework. This layer also provides methods and constructors that allow you to allocate memory
- for pointers that are defined in your RenderScript code. The following list describes the major
+ to the Renderscript runtime from the Android framework. This layer also provides methods
+and constructors that allow you to allocate and work with memory for pointers that are defined in
+your Renderscript code. The following list describes the major
components that are reflected:</p>
<ul>
<li>Every <code>.rs</code> file that you create is generated into a class named
- <code>ScriptC_<em>renderscript_filename</em></code> of type {@link
- android.renderscript.ScriptC}. This is the <code>.java</code> version of your <code>.rs</code>
- file, which you can call from the Android framework. This class contains the following
- reflections:
+ <code>project_root/gen/package/name/ScriptC_<em>renderscript_filename</em></code> of
+type {@link android.renderscript.ScriptC}. This file is the <code>.java</code> version of your
+<code>.rs</code> file, which you can call from the Android framework. This class contains the
+following items reflected from the <code>.rs</code> file:
<ul>
- <li>Non-static functions in your <code>.rs</code> file.</li>
+ <li>Non-static functions</li>
- <li>Non-static, global RenderScript variables. Accessor methods are generated for each
- variable, so you can read and write the natively declared variables from the Android
- framework. The <code>get</code> method comes with a one-way communication restriction. The
- last value that is set from the Android framework is always returned during a call to a
- <code>get</code> method. If the native RenderScript code changes the value, the change does
- not propagate back to the Android framework layer.
- If the global variables are initialized
- in the native RenderScript code, those values are used to initialize the corresponding
- values in the Android framework layer. If global variables are marked as
- <code>const</code>, then a <code>set</code> method is not generated.</li>
- <li>Global pointers generate a special method named <code>bind_<em>pointer_name</em></code>
- instead of a <code>set()</code> method. This method allows you to bind the memory that is
- allocated in the Android VM for the pointer to the native RenderScript (you cannot allocate
- memory in your <code>.rs</code> file). You can read and write to this memory from both the
- Android framework and RenderScript code. For more information, see <a href="mem-mgmt">Working
- with Memory and Data</a></li>
+ <li>Non-static, global Renderscript variables. Accessor methods are generated for each
+ variable, so you can read and write the Renderscript variables from the Android
+ framework. If a global variable is initialized at the Renderscript runtime layer, those
+values are used to initialize the corresponding values in the Android framework layer. If global
+variables are marked as <code>const</code>, then a <code>set</code> method is not
+generated.</p></li>
+
+ <li>Global pointers</li>
</ul>
</li>
<li>A <code>struct</code> is reflected into its own class named
- <code>ScriptField_<em>struct_name</em></code>, which extends {@link
+
+ <code>project_root/gen/package/name/ScriptField_struct_name</em></code>, which extends {@link
android.renderscript.Script.FieldBase}. This class represents an array of the
<code>struct</code>, which allows you to allocate memory for one or more instances of this
<code>struct</code>.</li>
</ul>
- <h3 id="framework">Android framework layer</h3>
- <p>The Android framework layer consists of the usual Android framework APIs, which include the
- RenderScript APIs in {@link android.renderscript}. This layer handles things such as the
- Activity lifecycle and memory management of your application. It issues high level commands to
- the native RenderScript code through the reflected layer and receives events from the user such
- as touch and input events and relays them to your RenderScript code, if needed.
- </p>
+<h3 id="func">Functions</h3>
+<p>Functions are reflected into the script class itself, located in
+<code>project_root/gen/package/name/ScriptC_renderscript_filename</code>. For
+example, if you declare the following function in your Renderscript code:</p>
- <h2 id="mem-allocation">Memory Allocation APIs</h2>
+<pre>
+void touch(float x, float y, float pressure, int id) {
+ if (id >= 10) {
+ return;
+ }
- <p>Before you begin writing your first RenderScript application, you must understand how
- memory is allocated for your RenderScript code and how data is shared between the native and VM
- spaces. RenderScript allows you to access allocated memory in both the native layer
- and Android system layer. All dynamic and static memory is allocated by the Android VM.
- The Android VM also does reference counting and garbage collection for you.
- You can also explicitly free memory that you no longer need.</p>
-
- <p class="note"><strong>Note:</strong> To declare temporary memory in your native RenderScript
- code without allocating it in the Android VM, you can still do things like instantiate a scratch
- buffer using an array.</p>
-
- <p>The following classes support the memory management features of RenderScript in the Android
- VM. You normally do not need to work with these classes directly, because the reflected layer
- classes provide constructors and methods that set up the memory allocation for you. There are
- some situations where you would want to use these classes directly to allocate memory on your
- own, such as loading a bitmap from a resource or when you want to allocate memory for pointers to
- primitive types.</p>
-
- <table id="mem-mgmt-table">
- <tr>
- <th>Android Object Type</th>
-
- <th>Description</th>
- </tr>
-
- <tr>
- <td>{@link android.renderscript.Element}</td>
-
- <td>
- <p>An element represents one cell of a memory allocation and can have two forms: Basic or
- Complex.</p>
-
- <p>A basic element contains a single component of data of any valid RenderScript data type.
- Examples of basic element data types include a single float value, a float4 vector, or a
- single RGB-565 color.</p>
-
- <p>Complex elements contain a list of basic elements and are created from
- <code>struct</code>s that you declare in your RenderScript code. The most basic primitive
- type determines the data alignment of the memory. For example, a float4 vector subelement
- is alligned to <code>sizeof(float)</code> and not <code>sizeof(float4)</code>. The ordering
- of the elements in memory are the order in which they were added, with each component
- aligned as necessary.</p>
- </td>
- </tr>
-
- <tr>
- <td>{@link android.renderscript.Type}</td>
-
- <td>
- A type is a memory allocation template and consists of an element and one or more
- dimensions. It describes the layout of the memory (basically an array of {@link
- android.renderscript.Element}s) but does not allocate the memory for the data that it
- describes.
-
- <p>A type consists of five dimensions: X, Y, Z, LOD (level of detail), and Faces (of a cube
- map). You can assign the X,Y,Z dimensions to any positive integer value within the
- constraints of available memory. A single dimension allocation has an X dimension of
- greater than zero while the Y and Z dimensions are zero to indicate not present. For
- example, an allocation of x=10, y=1 is considered two dimensional and x=10, y=0 is
- considered one dimensional. The LOD and Faces dimensions are booleans to indicate present
- or not present.</p>
- </td>
- </tr>
-
- <tr>
- <td>{@link android.renderscript.Allocation}</td>
-
- <td>
- <p>An allocation provides the memory for applications based on a description of the memory
- that is represented by a {@link android.renderscript.Type}. Allocated memory can exist in
- many memory spaces concurrently. If memory is modified in one space, you must explicitly
- synchronize the memory, so that it is updated in all the other spaces that it exists
- in.</p>
-
- <p>Allocation data is uploaded in one of two primary ways: type checked and type unchecked.
- For simple arrays there are <code>copyFrom()</code> functions that take an array from the
- Android system and copy it to the native layer memory store. The unchecked variants allow
- the Android system to copy over arrays of structures because it does not support
- structures. For example, if there is an allocation that is an array of n floats, the data
- contained in a float[n] array or a byte[n*4] array can be copied.</p>
- </td>
- </tr>
- </table>
-
- <h2 id="dynamic">Working with dynamic memory allocations</h2>
-
- <p>RenderScript has support for pointers, but you must allocate the memory in your Android framework
- code. When you declare a global pointer in your <code>.rs</code> file, you allocate memory
- through the appropriate reflected layer class and bind that memory to the native
- RenderScript layer. You can read and write to this memory from the Android framework layer as well as the
- RenderScript layer, which offers you the flexibility to modify variables in the most appropriate
- layer. The following sections show you how to work with pointers, allocate memory for them, and
- read and write to the memory.</p>
-
- <h3 id="pointers">Declaring pointers</h3>
-
- <p>Because RenderScript is written in C99, declaring a pointer is done in a familiar way. You can
- declare pointers to a <code>struct</code> or a primitive type, but a <code>struct</code> cannot
- contain pointers or nested arrays. The following code declares a <code>struct</code>, a pointer
- to that <code>struct</code>, and a pointer of primitive type <code>int32_t</code> in an <code>.rs</code> file:</p>
- <pre>
-#pragma version(1)
-#pragma rs java_package_name(com.example.renderscript)
-
-...
-
-typedef struct Point {
- float2 point;
- } Point_t;
-
- Point_t *touchPoints;
- int32_t *intPointer;
-
-...
+ touchPos[id].x = x;
+ touchPos[id].y = y;
+ touchPressure[id] = pressure;
+}
</pre>
-<p>You cannot allocate memory for these pointers in your RenderScript code, but the Android
-build tools generate classes for you that allow you to allocate memory in the Android VM for use by
-your RenderScript code. These classes also let you read and write to the memory. The next section
-describes how these classes are generated through reflection.</p>
+<p>then the following code is generated:</p>
- <h3>How pointers are reflected</h3>
+<pre>
+public void invoke_touch(float x, float y, float pressure, int id) {
+ FieldPacker touch_fp = new FieldPacker(16);
+ touch_fp.addF32(x);
+ touch_fp.addF32(y);
+ touch_fp.addF32(pressure);
+ touch_fp.addI32(id);
+ invoke(mExportFuncIdx_touch, touch_fp);
+}
+</pre>
+<p>
+Functions cannot have a return value, because the Renderscript system is designed to be
+asynchronous. When your Android framework code calls into Renderscript, the call is queued and is
+executed when possible. This restriction allows the Renderscript system to function without constant
+interruption and increases efficiency. If functions were allowed to have return values, the call
+would block until the value was returned.</p>
- <p>Global variables have a getter and setter method generated. A global pointer generates a
- <code>bind_pointerName()</code> method instead of a set() method. This method allows you to bind
- the memory that is allocated in the Android VM to the native RenderScript. For example, the two
- pointers in the previous section generate the following accessor methods in the <code>ScriptC_<em>rs_filename</em></code> file:</p>
+<p>
+If you want the Renderscript code to send a value back to the Android framework, use the
+<code>rsSendToClient()</code> function.
+</p>
+
+<h3 id="var">Variables</h3>
+
+ <p>Variables of supported types are reflected into the script class itself, located in
+<code>project_root/gen/package/name/ScriptC_renderscript_filename</code>. A set of accessor
+methods are generated for each variable. For example, if you declare the following variable in
+your Renderscript code:</p>
+ <pre>uint32_t unsignedInteger = 1;</pre>
+
+ <p>then the following code is generated:</p>
+
+<pre>
+private long mExportVar_unsignedInteger;
+public void set_unsignedInteger(long v){
+ mExportVar_unsignedInteger = v;
+ setVar(mExportVarIdx_unsignedInteger, v);
+}
+
+public long get_unsignedInteger(){
+ return mExportVar_unsignedInteger;
+}
+ </pre>
+
+ <h3 id="pointer">Pointers</h3>
+ <p>Pointers are reflected into the script class itself, located in
+<code>project_root/gen/package/name/ScriptC_renderscript_filename</code>. You
+can declare pointers to a <code>struct</code> or any of the supported Renderscript types, but a
+<code>struct</code> cannot contain pointers or nested arrays. For example, if you declare the
+following pointers to a <code>struct</code> and <code>int32_t</code></p>
+
+<pre>
+typedef struct Point {
+ float2 point;
+} Point_t;
+
+Point_t *touchPoints;
+int32_t *intPointer;
+</pre>
+ <p>then the following code is generated in:</p>
+
<pre>
-
- private ScriptField_Point mExportVar_touchPoints;
- public void bind_touchPoints(ScriptField_Point v) {
- mExportVar_touchPoints = v;
- if (v == null) bindAllocation(null, mExportVarIdx_touchPoints);
- else bindAllocation(v.getAllocation(), mExportVarIdx_touchPoints);
+private ScriptField_Point mExportVar_touchPoints;
+public void bind_touchPoints(ScriptField_Point v) {
+ mExportVar_touchPoints = v;
+ if (v == null) bindAllocation(null, mExportVarIdx_touchPoints);
+ else bindAllocation(v.getAllocation(), mExportVarIdx_touchPoints);
}
public ScriptField_Point get_touchPoints() {
- return mExportVar_touchPoints;
+ return mExportVar_touchPoints;
}
private Allocation mExportVar_intPointer;
public void bind_intPointer(Allocation v) {
- mExportVar_intPointer = v;
- if (v == null) bindAllocation(null, mExportVarIdx_intPointer);
- else bindAllocation(v, mExportVarIdx_intPointer);
+ mExportVar_intPointer = v;
+ if (v == null) bindAllocation(null, mExportVarIdx_intPointer);
+ else bindAllocation(v, mExportVarIdx_intPointer);
}
public Allocation get_intPointer() {
return mExportVar_intPointer;
}
+ </pre>
-</pre>
+<p>A <code>get</code> method and a special method named <code>bind_<em>pointer_name</em></code>
+(instead of a <code>set()</code> method) is generated. This method allows you to bind the memory
+that is allocated in the Android VM to the Renderscript runtime (you cannot allocate
+memory in your <code>.rs</code> file). For more information, see <a href="#memory">Working
+with Allocated Memory</a>.
+</p>
- <h3>Allocating and binding memory to the RenderScript</h3>
-
- <p>When the build tools generate the reflected layer, you can use the appropriate class
- (<code>ScriptField_Point</code>, in our example) to allocate memory for a pointer. To do this,
- you call the constructor for the {@link android.renderscript.Script.FieldBase} class and specify
- the amount of structures that you want to allocate memory for. To allocate memory for a primitive
- type pointer, you must build an allocation manually, using the memory management classes
- described in <a href="#mem-mgmt-table">Table 1</a>. The example below allocates memory for both
- the <code>intPointer</code> and <code>touchPoints</code> pointer and binds it to the
- RenderScript:</p>
- <pre>
-private RenderScriptGL glRenderer;
-private ScriptC_example script;
-private Resources resources;
-
-public void init(RenderScriptGL rs, Resources res) {
- //get the rendering context and resources from the calling method
- glRenderer = rs;
- resources = res;
-
- //allocate memory for the struct pointer, calling the constructor
- ScriptField_Point touchPoints = new ScriptField_Point(glRenderer, 2);
-
- //Create an element manually and allocate memory for the int pointer
- intPointer = Allocation.createSized(glRenderer, Element.I32(glRenderer), 2);
-
- //create an instance of the RenderScript, pointing it to the bytecode resource
- mScript = new ScriptC_example(glRenderer, resources, R.raw.example);
-
- // bind the struct and int pointers to the RenderScript
- mScript.bind_touchPoints(touchPoints);
- script.bind_intPointer(intPointer);
-
- //bind the RenderScript to the rendering context
- glRenderer.bindRootScript(script);
-}
-</pre>
-
- <h3>Reading and writing to memory</h3>
-
- <p>Although you have to allocate memory within the Android VM, you can work with the memory both
- in your native RenderScript code and in your Android code. Once memory is bound, the native
- RenderScript can read and write to the memory directly. You can also just use the accessor
- methods in the reflected classes to access the memory. If you modify memory in the Android
- framework, it gets automatically synchronized to the native layer. If you modify memory in the <code>.rs</code>
- file, these changes do not get propagated back to the Android framework.
- For example, you can modify the struct in your Android code like this:</p>
- <pre>
-int index = 0;
-boolean copyNow = true;
-Float2 point = new Float2(0.0f, 0.0f);
-touchPoints.set_point(index, point, copyNow);
-</pre>then read it in your native RenderScript code like this:
- <pre>
-rsDebug("Printing out a Point", touchPoints[0].point.x, touchPoints[0].point.y);
-</pre>
-
- <h2>Working with statically allocated memory</h2>
-
- <p>Non-static, global primitives and structs that you declare in your RenderScript are easier to work with,
- because the memory is statically allocated at compile time. Accessor methods to set and get these
- variables are generated when the Android build tools generate the reflected layer classes. You
- can get and set these variables using the provided accessor methods.
- <p class="note"><strong>Note:</strong> The <code>get</code> method comes with a one-way communication restriction. The last value
- that is set from the Android framework is always returned during a call to a <code>get</code>
- method. If the native RenderScript code changes the value, the change does not propagate back to
- the Android framework layer. If the global variables are initialized in the native RenderScript
- code, those values are used to initialize the corresponding values in the Android framework
- layer. If global variables are marked as <code>const</code>, then a <code>set</code> method is
- not generated.</p>
- </p>
-
- <p>For example, if you declare the following primitive in your RenderScript code:</p>
- <pre>
- uint32_t unsignedInteger = 1;
-
-</pre>
-<p>then the following code is generated in <code>ScriptC_<em>script_name</em>.java</code>:</p>
- <pre>
- private final static int mExportVarIdx_unsignedInteger = 9;
- private long mExportVar_unsignedInteger;
- public void set_unsignedInteger(long v) {
- mExportVar_unsignedInteger = v;
- setVar(mExportVarIdx_unsignedInteger, v);
- }
-
- public long get_unsignedInteger() {
- return mExportVar_unsignedInteger;
- }
-</pre>
-
- <p class="note"><strong>Note:</strong> The mExportVarIdx_unsignedInteger variable represents the
- index of the <code>unsignedInteger</code>'s in an array of statically allocated primitives. You do
- not need to work with or be aware of this index.</p>
-
- <p>For a <code>struct</code>, the Android build tools generate a class named
- <code><project_root>/gen/com/example/renderscript/ScriptField_struct_name</code>. This
- class represents an array of the <code>struct</code> and allows you to allocate memory for a
- specified number of <code>struct</code>s. This class defines:</p>
-
- <ul>
- <li>Overloaded constructors that allow you to allocate memory. The
- <code>ScriptField_<em>struct_name</em>(RenderScript rs, int count)</code> constructor allows
- you to define the number of structures that you want to allocate memory for with the
- <code>count</code> parameter. The <code>ScriptField_<em>struct_name</em>(RenderScript rs, int
- count, int usages)</code> constructor defines an extra parameter, <code>usages</code>, that
- lets you specify the memory space of this memory allocation. There are four memory space
- possibilities:
-
- <ul>
- <li>{@link android.renderscript.Allocation#USAGE_SCRIPT}: Allocates in the script memory
- space. This is the default memory space if you do not specify a memory space.</li>
-
- <li>{@link android.renderscript.Allocation#USAGE_GRAPHICS_TEXTURE}: Allocates in the
- texture memory space of the GPU.</li>
-
- <li>{@link android.renderscript.Allocation#USAGE_GRAPHICS_VERTEX}: Allocates in the vertex
- memory space of the GPU.</li>
-
- <li>{@link android.renderscript.Allocation#USAGE_GRAPHICS_CONSTANTS}: Allocates in the
- constants memory space of the GPU that is used by the various program objects.</li>
- </ul>
-
- <p>You can specify one or all of these memory spaces by OR'ing them together. Doing so notifies
- the RenderScript runtime that you intend on accessing the data in the specified memory spaces. The following
- example allocates memory for a custom data type in both the script and vertex memory spaces:</p>
+ <h3 id="struct">Structs</h3>
+ <p>Structs are reflected into their own classes, located in
+ <code><project_root>/gen/com/example/renderscript/ScriptField_struct_name</code>. This
+ class represents an array of the <code>struct</code> and allows you to allocate memory for a
+ specified number of <code>struct</code>s. For example, if you declare the following struct:</p>
<pre>
-ScriptField_Point touchPoints = new ScriptField_Point(glRenderer, 2,
-Allocation.USAGE_SCRIPT | Allocation.USAGE_GRAPHICS_VERTEX);
+typedef struct Point {
+float2 point;
+} Point_t;
</pre>
- <p>If you modify the memory in one memory space and want to push the updates to the rest of
- the memory spaces, call <code>rsgAllocationSyncAll()</code> in your RenderScript code to
- synchronize the memory.</p>
- </li>
-
- <li>A static nested class, <code>Item</code>, allows you to create an instance of the
- <code>struct</code>, in the form of an object. This is useful if it makes more sense to work
- with the <code>struct</code> in your Android code. When you are done manipulating the object,
- you can push the object to the allocated memory by calling <code>set(Item i, int index, boolean
- copyNow)</code> and setting the <code>Item</code> to the desired position in the array. The
- native RenderScript code automatically has access to the newly written memory.
-
- <li>Accessor methods to get and set the values of each field in a struct. Each of these
- accessor methods have an <code>index</code> parameter to specify the <code>struct</code> in the
- array that you want to read or write to. Each setter method also has a <code>copyNow</code>
- parameter that specifies whether or not to immediately sync this memory to the native
- RenderScript layer. To sync any memory that has not been synced, call <code>copyAll()</code>.</li>
-
- <li>The createElement() method creates an object that describes the memory layout of the struct.</li>
-
- <li>resize() works much like a <code>realloc</code>, allowing you to expand previously
- allocated memory, maintaining the current values that were previously set.</li>
-
- <li>copyAll() synchronizes memory that was set on the framework level to the native level. When you call
- a set accessor method on a member, there is an optional <code>copyNow</code> boolean parameter that you can specify. Specifying
- <code>true</code> synchronizes the memory when you call the method. If you specify false, you can call <code>copyAll()</code>
- once, and it synchronizes memory for the all the properties that are not synchronized.</li>
- </ul>
-
- <p>The following example shows the reflected class, <code>ScriptField_Point.java</code> that is
- generated from the Point <code>struct</code>.</p>
- <pre>
-package com.example.renderscript;
+<p>then the following code is generated in <code>ScriptField_Point.java</code>:
+<pre>
+package com.example.android.rs.hellocompute;
import android.renderscript.*;
import android.content.res.Resources;
-
+ /**
+ * @hide
+ */
public class ScriptField_Point extends android.renderscript.Script.FieldBase {
- static public class Item {
- public static final int sizeof = 8;
- Float2 point;
+ static public class Item {
+ public static final int sizeof = 12;
+
+ Float2 position;
+ float size;
Item() {
- point = new Float2();
+ position = new Float2();
}
-
}
private Item mItemArray[];
private FieldPacker mIOBuffer;
public static Element createElement(RenderScript rs) {
Element.Builder eb = new Element.Builder(rs);
- eb.add(Element.F32_2(rs), "point");
+ eb.add(Element.F32_2(rs), "position");
+ eb.add(Element.F32(rs), "size");
return eb.create();
}
@@ -573,9 +362,11 @@
}
private void copyToArray(Item i, int index) {
- if (mIOBuffer == null) mIOBuffer = new FieldPacker(Item.sizeof * getType().getX()/* count */);
+ if (mIOBuffer == null) mIOBuffer = new FieldPacker(Item.sizeof * getType().getX()/* count
+ */);
mIOBuffer.reset(index * Item.sizeof);
- mIOBuffer.addF32(i.point);
+ mIOBuffer.addF32(i.position);
+ mIOBuffer.addF32(i.size);
}
public void set(Item i, int index, boolean copyNow) {
@@ -585,7 +376,6 @@
copyToArray(i, index);
mAllocation.setFromFieldPacker(index, mIOBuffer);
}
-
}
public Item get(int index) {
@@ -593,24 +383,42 @@
return mItemArray[index];
}
- public void set_point(int index, Float2 v, boolean copyNow) {
- if (mIOBuffer == null) mIOBuffer = new FieldPacker(Item.sizeof * getType().getX()/* count */)fnati;
+ public void set_position(int index, Float2 v, boolean copyNow) {
+ if (mIOBuffer == null) mIOBuffer = new FieldPacker(Item.sizeof * getType().getX()/* count */);
if (mItemArray == null) mItemArray = new Item[getType().getX() /* count */];
if (mItemArray[index] == null) mItemArray[index] = new Item();
- mItemArray[index].point = v;
- if (copyNow) {
+ mItemArray[index].position = v;
+ if (copyNow) {
mIOBuffer.reset(index * Item.sizeof);
mIOBuffer.addF32(v);
FieldPacker fp = new FieldPacker(8);
fp.addF32(v);
mAllocation.setFromFieldPacker(index, 0, fp);
}
-
}
- public Float2 get_point(int index) {
+ public void set_size(int index, float v, boolean copyNow) {
+ if (mIOBuffer == null) mIOBuffer = new FieldPacker(Item.sizeof * getType().getX()/* count */);
+ if (mItemArray == null) mItemArray = new Item[getType().getX() /* count */];
+ if (mItemArray[index] == null) mItemArray[index] = new Item();
+ mItemArray[index].size = v;
+ if (copyNow) {
+ mIOBuffer.reset(index * Item.sizeof + 8);
+ mIOBuffer.addF32(v);
+ FieldPacker fp = new FieldPacker(4);
+ fp.addF32(v);
+ mAllocation.setFromFieldPacker(index, 1, fp);
+ }
+ }
+
+ public Float2 get_position(int index) {
if (mItemArray == null) return null;
- return mItemArray[index].point;
+ return mItemArray[index].position;
+ }
+
+ public float get_size(int index) {
+ if (mItemArray == null) return 0;
+ return mItemArray[index].size;
}
public void copyAll() {
@@ -627,13 +435,361 @@
System.arraycopy(mItemArray, 0, ni, 0, copySize);
mItemArray = ni;
}
-
mAllocation.resize(newSize);
if (mIOBuffer != null) mIOBuffer = new FieldPacker(Item.sizeof * getType().getX()/* count */);
}
-
}
</pre>
-</body>
-</html>
+<p>The generated code is provided to you as a convenience to allocate memory for structs requested
+by the Renderscript runtime and to interact with <code>struct</code>s
+in memory. Each <code>struct</code>'s class defines the following methods and constructors:</p>
+
+ <ul>
+ <li>Overloaded constructors that allow you to allocate memory. The
+ <code>ScriptField_<em>struct_name</em>(RenderScript rs, int count)</code> constructor allows
+ you to define the number of structures that you want to allocate memory for with the
+ <code>count</code> parameter. The <code>ScriptField_<em>struct_name</em>(RenderScript rs, int
+ count, int usages)</code> constructor defines an extra parameter, <code>usages</code>, that
+ lets you specify the memory space of this memory allocation. There are four memory space
+ possibilities:
+
+ <ul>
+ <li>{@link android.renderscript.Allocation#USAGE_SCRIPT}: Allocates in the script memory
+ space. This is the default memory space if you do not specify a memory space.</li>
+
+ <li>{@link android.renderscript.Allocation#USAGE_GRAPHICS_TEXTURE}: Allocates in the
+ texture memory space of the GPU.</li>
+
+ <li>{@link android.renderscript.Allocation#USAGE_GRAPHICS_VERTEX}: Allocates in the vertex
+ memory space of the GPU.</li>
+
+ <li>{@link android.renderscript.Allocation#USAGE_GRAPHICS_CONSTANTS}: Allocates in the
+ constants memory space of the GPU that is used by the various program objects.</li>
+ </ul>
+
+ <p>You can specify multiple memory spaces by using the bitwise <code>OR</code> operator. Doing so
+ notifies the Renderscript runtime that you intend on accessing the data in the
+ specified memory spaces. The following example allocates memory for a custom data type
+ in both the script and vertex memory spaces:</p>
+ <pre>
+ ScriptField_Point touchPoints = new ScriptField_Point(glRenderer, 2,
+ Allocation.USAGE_SCRIPT | Allocation.USAGE_GRAPHICS_VERTEX);
+ </pre>
+
+ <p>If you modify the memory in one memory space and want to push the updates to the rest of
+ the memory spaces, call <code>rsgAllocationSyncAll()</code> in your Renderscript code to
+ synchronize the memory.</p>
+ </li>
+
+ <li>A static nested class, <code>Item</code>, allows you to create an instance of the
+ <code>struct</code>, in the form of an object. This nested class is useful if it makes more sense to work
+ with the <code>struct</code> in your Android code. When you are done manipulating the object,
+ you can push the object to the allocated memory by calling <code>set(Item i, int index,
+ boolean copyNow)</code> and setting the <code>Item</code> to the desired position in
+the array. The Renderscript runtime automatically has access to the newly written memory.
+
+ <li>Accessor methods to get and set the values of each field in a struct. Each of these
+ accessor methods have an <code>index</code> parameter to specify the <code>struct</code> in
+ the array that you want to read or write to. Each setter method also has a
+<code>copyNow</code> parameter that specifies whether or not to immediately sync this memory
+to the Renderscript runtime. To sync any memory that has not been synced, call
+ <code>copyAll()</code>.</li>
+
+ <li>The <code>createElement()</code> method creates a description of the struct in memory. This
+ description is used to allocate memory consisting of one or many elements.</li>
+
+ <li><code>resize()</code> works much like a <code>realloc()</code> in C, allowing you to
+expand previously allocated memory, maintaining the current values that were previously
+created.</li>
+
+ <li><code>copyAll()</code> synchronizes memory that was set on the framework level to the
+Renderscript runtime. When you call a set accessor method on a member, there is an optional
+<code>copyNow</code> boolean parameter that you can specify. Specifying
+ <code>true</code> synchronizes the memory when you call the method. If you specify false,
+ you can call <code>copyAll()</code> once, and it synchronizes memory for all the
+properties that are not yet synchronized.</li>
+ </ul>
+
+ <h2 id="mem-allocation">Memory Allocation APIs</h2>
+
+ <p>Applications that use Renderscript still run in the Android VM. The actual Renderscript code, however, runs natively and
+ needs access to the memory allocated in the Android VM. To accomplish this, you must
+ attach the memory that is allocated in the VM to the Renderscript runtime. This
+process, called binding, allows the Renderscript runtime to seamlessly work with memory that it
+requests but cannot explicitly allocate. The end result is essentially the same as if you had
+called <code>malloc</code> in C. The added benefit is that the Android VM can carry out garbage collection as well as
+share memory with the Renderscript runtime layer. Binding is only necessary for dynamically allocated memory. Statically
+allocated memory is automatically created for your Renderscript code at compile time. See <a href="#figure1">Figure 1</a>
+for more information on how memory allocation occurs.
+</p>
+
+ <p>To support this memory allocation system, there are a set of APIs that allow the Android VM to
+allocate memory and offer similar functionality to a <code>malloc</code> call. These classes
+essentially describe how memory should be allocated and also carry out the allocation. To better
+understand how these classes work, it is useful to think of them in relation to a simple
+<code>malloc</code> call that can look like this: </p>
+
+ <pre>array = (int *)malloc(sizeof(int)*10);</pre>
+
+ <p>The <code>malloc</code> call can be broken up into two parts: the size of the memory being allocated (<code>sizeof(int)</code>),
+ along with how many units of that memory should be allocated (10). The Android framework provides classes for these two parts as
+ well as a class to represent <code>malloc</code> itself.</p>
+
+ <p>The {@link android.renderscript.Element} class represents the (<code>sizeof(int)</code>) portion
+ of the <code>malloc</code> call and encapsulates one cell of a memory allocation, such as a single
+ float value or a struct. The {@link android.renderscript.Type} class encapsulates the {@link android.renderscript.Element}
+ and the amount of elements to allocate (10 in our example). You can think of a {@link android.renderscript.Type} as
+ an array of {@link android.renderscript.Element}s. The {@link android.renderscript.Allocation} class does the actual
+ memory allocation based on a given {@link android.renderscript.Type} and represents the actual allocated memory.</p>
+
+ <p>In most situations, you do not need to call these memory allocation APIs directly. The reflected layer
+ classes generate code to use these APIs automatically and all you need to do to allocate memory is call a
+ constructor that is declared in one of the reflected layer classes and then bind
+ the resulting memory {@link android.renderscript.Allocation} to the Renderscript.
+ There are some situations where you would want to use these classes directly to allocate memory on your
+ own, such as loading a bitmap from a resource or when you want to allocate memory for pointers to
+ primitive types. You can see how to do this in the
+ <a href="#allocating-mem">Allocating and binding memory to the Renderscript</a> section.
+ The following table describes the three memory management classes in more detail:</p>
+
+ <table id="mem-mgmt-table">
+ <tr>
+ <th>Android Object Type</th>
+
+ <th>Description</th>
+ </tr>
+
+ <tr>
+ <td>{@link android.renderscript.Element}</td>
+
+ <td>
+ <p>An element describes one cell of a memory allocation and can have two forms: basic or
+ complex.</p>
+
+ <p>A basic element contains a single component of data of any valid Renderscript data type.
+ Examples of basic element data types include a single <code>float</code> value, a <code>float4</code> vector, or a
+ single RGB-565 color.</p>
+
+ <p>Complex elements contain a list of basic elements and are created from
+ <code>struct</code>s that you declare in your Renderscript code. For instance an allocation
+ can contain multiple <code>struct</code>s arranged in order in memory. Each struct is considered as its
+ own element, rather than each data type within that struct.</p>
+ </td>
+ </tr>
+
+ <tr>
+ <td>{@link android.renderscript.Type}</td>
+
+ <td>
+ <p>A type is a memory allocation template and consists of an element and one or more
+ dimensions. It describes the layout of the memory (basically an array of {@link
+ android.renderscript.Element}s) but does not allocate the memory for the data that it
+ describes.</p>
+
+ <p>A type consists of five dimensions: X, Y, Z, LOD (level of detail), and Faces (of a cube
+ map). You can assign the X,Y,Z dimensions to any positive integer value within the
+ constraints of available memory. A single dimension allocation has an X dimension of
+ greater than zero while the Y and Z dimensions are zero to indicate not present. For
+ example, an allocation of x=10, y=1 is considered two dimensional and x=10, y=0 is
+ considered one dimensional. The LOD and Faces dimensions are booleans to indicate present
+ or not present.</p>
+ </td>
+ </tr>
+
+ <tr>
+ <td>{@link android.renderscript.Allocation}</td>
+
+ <td>
+ <p>An allocation provides the memory for applications based on a description of the memory
+ that is represented by a {@link android.renderscript.Type}. Allocated memory can exist in
+ many memory spaces concurrently. If memory is modified in one space, you must explicitly
+ synchronize the memory, so that it is updated in all the other spaces in which it exists.
+ </p>
+
+ <p>Allocation data is uploaded in one of two primary ways: type checked and type unchecked.
+ For simple arrays there are <code>copyFrom()</code> functions that take an array from the
+ Android system and copy it to the native layer memory store. The unchecked variants allow
+ the Android system to copy over arrays of structures because it does not support
+ structures. For example, if there is an allocation that is an array of n floats, the data
+ contained in a float[n] array or a <code>byte[n*4]</code> array can be copied.</p>
+ </td>
+ </tr>
+ </table>
+
+ <h2 id="memory">Working with Memory</h2>
+
+<p>Non-static, global variables that you declare in your Renderscript are allocated memory at compile time.
+You can work with these variables directly in your Renderscript code without having to allocate
+memory for them at the Android framework level. The Android framework layer also has access to these variables
+with the provided accessor methods that are generated in the reflected layer classes. If these variables are
+initialized at the Renderscript runtime layer, those values are used to initialize the corresponding
+values in the Android framework layer. If global variables are marked as const, then a <code>set</code> method is
+not generated.</p>
+
+
+<p class="note"><strong>Note:</strong> If you are using certain Renderscript structures that contain pointers, such as
+<code>rs_program_fragment</code> and <code>rs_allocation</code>, you have to obtain an object of the
+corresponding Android framework class first and then call the <code>set</code> method for that
+structure to bind the memory to the Renderscript runtime. You cannot directly manipulate these structures
+at the Renderscript runtime layer. Keep in mind that user-defined structures
+cannot contain pointers, so this restriction only applies to certain structures that are provided by Renderscript.
+</p>
+
+<p>Renderscript also has support for pointers, but you must explicitly allocate the memory in your
+Android framework code. When you declare a global pointer in your <code>.rs</code> file, you
+allocate memory through the appropriate reflected layer class and bind that memory to the native
+Renderscript layer. You can interact with this memory from the Android framework layer as well as
+the Renderscript layer, which offers you the flexibility to modify variables in the most
+appropriate layer.</p>
+
+
+
+ <h3 id="allocating-mem">Allocating and binding dynamic memory to the Renderscript</h3>
+
+ <p>To allocate dynamic memory, you need to call the constructor of a
+ {@link android.renderscript.Script.FieldBase} class, which is the most common way. An alternative is to create an
+ {@link android.renderscript.Allocation} manually, which is required for things such as primitive type pointers. You should
+ use a {@link android.renderscript.Script.FieldBase} class constructor whenever available for simplicity.
+ After obtaining a memory allocation, call the reflected <code>bind</code> method of the pointer to bind the allocated memory to the
+ Renderscript runtime.</p>
+ <p>The example below allocates memory for both a primitive type pointer,
+ <code>intPointer</code>, and a pointer to a struct, <code>touchPoints</code>. It also binds the memory to the
+ Renderscript:</p>
+ <pre>
+private RenderScriptGL glRenderer;
+private ScriptC_example script;
+private Resources resources;
+
+public void init(RenderScriptGL rs, Resources res) {
+ //get the rendering context and resources from the calling method
+ glRenderer = rs;
+ resources = res;
+
+ //allocate memory for the struct pointer, calling the constructor
+ ScriptField_Point touchPoints = new ScriptField_Point(glRenderer, 2);
+
+ //Create an element manually and allocate memory for the int pointer
+ intPointer = Allocation.createSized(glRenderer, Element.I32(glRenderer), 2);
+
+ //create an instance of the Renderscript, pointing it to the bytecode resource
+ mScript = new ScriptC_example(glRenderer, resources, R.raw.example);
+
+ //bind the struct and int pointers to the Renderscript
+ mScript.bind_touchPoints(touchPoints);
+ script.bind_intPointer(intPointer);
+
+ ...
+}
+</pre>
+
+ <h3>Reading and writing to memory</h3>
+ <p>You can read and write to statically and dynamically allocated memory both at the Renderscript runtime
+ and Android framework layer.</p>
+
+<p>Statically allocated memory comes with a one-way communication restriction
+at the Renderscript runtime level. When Renderscript code changes the value of a variable, it is not
+communicated back to the Android framework layer for efficiency purposes. The last value
+that is set from the Android framework is always returned during a call to a <code>get</code>
+method. However, when Android framework code modifies a variable, that change can be communicated to
+the Renderscript runtime automatically or synchronized at a later time. If you need to send data
+from the Renderscript runtime to the Android framework layer, you can use the <code>rsSendToClient()</code> function
+to overcome this limitation.
+</p>
+<p>When working with dynamically allocated memory, any changes at the Renderscript runtime layer are propagated
+back to the Android framework layer if you modified the memory allocation using its associated pointer.
+Modifying an object at the Android framework layer immediately propagates that change back to the Renderscript
+runtime layer.</p>
+
+ <h4>Reading and writing to global variables</h4>
+
+ <p>Reading and writing to global variables is a straightforward process. You can use the accessor methods
+ at the Android framework level or set them directly in the Renderscript code. Keep in mind that any
+ changes that you make in your Renderscript code are not propagated back to the Android framework layer.</p>
+
+ <p>For example, given the following struct declared in a file named <code>rsfile.rs</code>:</p>
+<pre>
+typedef struct Point {
+ int x;
+ int y;
+} Point_t;
+
+Point_t point;
+
+</pre>
+<p>You can assign values to the struct like this directly in <code>rsfile.rs</code>. These values are not
+propagated back to the Android framework level:</p>
+<pre>
+point.x = 1;
+point.y = 1;
+</pre>
+
+<p>You can assign values to the struct at the Android framework layer like this. These values are
+propagated back to the Renderscript runtime level:</p>
+<pre>
+ScriptC_rsfile mScript;
+
+...
+
+Item i = new ScriptField_Point.Item();
+i.x = 1;
+i.y = 1;
+mScript.set_point(i);
+</pre>
+
+<p>You can read the values in your Renderscript code like this:</p>
+
+<pre>
+rsDebug("Printing out a Point", point.x, point.y);
+</pre>
+
+<p>You can read the values in the Android framework layer with the following code. Keep in mind that this
+code only returns a value if one was set at the Android framework level. You will get a null pointer
+exception if you only set the value at the Renderscript runtime level:</p>
+
+<pre>
+Log.i("TAGNAME", "Printing out a Point: " + mScript.get_point().x + " " + mScript.get_point().y);
+System.out.println(point.get_x() + " " + point.get_y());
+</pre>
+
+<h4>Reading and writing global pointers</h4>
+
+<p>Assuming that memory has been allocated in the Android framework level and bound to the Renderscript runtime,
+you can read and write memory from the Android framework level by using the <code>get</code> and <code>set</code> methods for that pointer.
+In the Renderscript runtime layer, you can read and write to memory with pointers as normal and the changes are propagated
+back to the Android framework layer, unlike with statically allocated memory.</p>
+
+<p>For example, given the following pointer to a <code>struct</code> in a file named <code>rsfile.rs</code>:</p>
+<pre>
+typedef struct Point {
+ int x;
+ int y;
+} Point_t;
+
+Point_t *point;
+</pre>
+
+<p>Assuming you already allocated memory at the Android framework layer, you can access values in
+the <code>struct</code> as normal. Any changes you make to the struct via its pointer variable
+are automatically available to the Android framework layer:</p>
+
+<pre>
+point[index].x = 1;
+point[index].y = 1;
+</pre>
+
+<p>You can read and write values to the pointer at the Android framework layer as well:
+<pre>
+ScriptField_Point p = new ScriptField_Point(mRS, 1);
+ Item i = new ScriptField_Point.Item();
+ i.x=100;
+ i.y = 100;
+ p.set(i, 0, true);
+ mScript.bind_point(p);
+
+ points.get_x(0); //read x and y from index 0
+ points.get_x(0);
+</pre>
+
+<p>Once memory is already bound, you do not have to rebind the memory to the Renderscript
+runtime every time you make a change to a value.</p>
diff --git a/docs/html/guide/topics/ui/actionbar.jd b/docs/html/guide/topics/ui/actionbar.jd
index b83bde7..e59fa0f 100644
--- a/docs/html/guide/topics/ui/actionbar.jd
+++ b/docs/html/guide/topics/ui/actionbar.jd
@@ -113,9 +113,10 @@
href="{@docRoot}guide/topics/ui/menus.html#OptionsMenu">options menu</a> directly in the action bar,
as "action items." Action items can also provide an "action view," which provides an embedded
widget for even more immediate action behaviors. Menu items that are not promoted
-to an action item are available in the overflow menu, revealed by either the device MENU button
+to an action item are available in the overflow menu, revealed by either the device <em>Menu</em>
+button
(when available) or by an "overflow menu" button in the action bar (when the device does not
-include a MENU button).</p>
+include a <em>Menu</em> button).</p>
</li>
</ul>
@@ -125,6 +126,10 @@
landscape handset), showing the logo on the left, navigation tabs, and an action item on the
right (plus the overflow menu button).</p>
+<p class="note"><strong>Note:</strong> If you're looking for information about the contextual
+action bar for displaying contextual action items, see the <a
+href="{@docRoot}guide/topics/ui/menus.html#context-menu">Menu</a> guide.</p>
+
<div class="design-announce">
<p><strong>Action Bar Design</strong></p>
@@ -225,9 +230,10 @@
href="{@docRoot}guide/topics/ui/menus.html#OptionsMenu">options menu</a>. To do this, you can
declare that the menu item should appear in the action bar as an "action item." An action item can
include an icon and/or a text title. If a menu item does not appear as an action item, then the
-system places it in the overflow menu. The overflow menu is revealed either by the device MENU
+system places it in the overflow menu. The overflow menu is revealed either by the device
+<em>Menu</em>
button (if provided by the device) or an additional button in the action bar (if the device does not
-provide the MENU button).</p>
+provide the <em>Menu</em> button).</p>
<div class="figure" style="width:359px">
<img src="{@docRoot}images/ui/actionbar-item-withtext.png" height="57" alt="" />
@@ -1421,7 +1427,7 @@
</style>
<!-- style for the action bar tab text -->
- <style name="CustomTabTextStyle">
+ <style name="CustomTabTextStyle" parent="@android:style/TextAppearance.Holo">
<item name="android:textColor">#2456c2</item>
</style>
</resources>
@@ -1437,8 +1443,7 @@
manifest file like this:</p>
<pre>
-<application android:theme="@style/CustomActivityTheme"
- ... />
+<application android:theme="@style/CustomActivityTheme" ... />
</pre>
<p>For more information about using style and theme resources in your application, read <a
@@ -1457,7 +1462,7 @@
parent action bar style such as {@link android.R.style#Widget_Holo_ActionBar
Widget.Holo.ActionBar}.</p>
-<p>For example, if you want to change the action bar's background, you could use the following
+<p>For example, if you want to change the action bar's background, you can use the following
styles:</p>
<pre>
@@ -1465,14 +1470,15 @@
<resources>
<!-- the theme applied to the application or activity -->
<style name="CustomActivityTheme" parent="@android:style/Theme.Holo">
- <item name="android:actionBarTabTextStyle">@style/customTabTextStyle</item>
+ <item name="android:actionBarStyle">@style/MyActionBar</item>
<!-- other activity and action bar styles here -->
</style>
- <!-- style for the action bar, simply to change the background -->
- <style parent="@android:style/Widget.Holo.ActionBar">
+ <!-- style for the action bar backgrounds -->
+ <style name="MyActionBar" parent="@android:style/Widget.Holo.ActionBar">
<item name="android:background">@drawable/ab_background</item>
- <item name="android:backgroundSplit">@drawable/ab_background</item>
+ <item name="android:backgroundStacked">@drawable/ab_background</item>
+ <item name="android:backgroundSplit">@drawable/ab_split_background</item>
</style>
</resources>
</pre>
diff --git a/docs/html/guide/topics/ui/how-android-draws.jd b/docs/html/guide/topics/ui/how-android-draws.jd
index 3a57afa..6a8cd86 100644
--- a/docs/html/guide/topics/ui/how-android-draws.jd
+++ b/docs/html/guide/topics/ui/how-android-draws.jd
@@ -62,7 +62,7 @@
<p>
The measure pass uses two classes to communicate dimensions. The
- {@link android.view.View.MeasureSpec} class is used by Views to tell their parents how they
+ {@link android.view.ViewGroup.LayoutParams} class is used by Views to tell their parents how they
want to be measured and positioned. The base LayoutParams class just
describes how big the View wants to be for both width and height. For each
dimension, it can specify one of:</p>
diff --git a/docs/html/guide/topics/ui/menus.jd b/docs/html/guide/topics/ui/menus.jd
index 7b5b3dc..a2313b3 100644
--- a/docs/html/guide/topics/ui/menus.jd
+++ b/docs/html/guide/topics/ui/menus.jd
@@ -6,77 +6,129 @@
<div id="qv-wrapper">
<div id="qv">
<h2>In this document</h2>
- <ol>
- <li><a href="#xml">Creating a Menu Resource</a></li>
- <li><a href="#Inflating">Inflating a Menu Resource</a>
- <li><a href="#options-menu">Creating an Options Menu</a>
- <ol>
- <li><a href="#ChangingTheMenu">Changing menu items at runtime</a></li>
- </ol>
- </li>
- <li><a href="#context-menu">Creating a Context Menu</a></li>
- <li><a href="#submenu">Creating a Submenu</a></li>
- <li><a href="#features">Other Menu Features</a>
- <ol>
- <li><a href="#groups">Menu groups</a></li>
- <li><a href="#checkable">Checkable menu items</a></li>
- <li><a href="#shortcuts">Shortcut keys</a></li>
- <li><a href="#intents">Dynamically adding menu intents</a></li>
- </ol>
- </li>
- </ol>
+<ol>
+ <li><a href="#xml">Defining a Menu in XML</a></li>
+ <li><a href="#options-menu">Creating an Options Menu</a>
+ <ol>
+ <li><a href="#RespondingOptionsMenu">Handling click events</a></li>
+ <li><a href="#ChangingTheMenu">Changing menu items at runtime</a></li>
+ </ol>
+ </li>
+ <li><a href="#context-menu">Creating Contextual Menus</a>
+ <ol>
+ <li><a href="#FloatingContextMenu">Creating a floating context menu</a></li>
+ <li><a href="#CAB">Using the contextual action bar</a></li>
+ </ol>
+ </li>
+ <li><a href="#PopupMenu">Creating a Popup Menu</a>
+ <ol>
+ <li><a href="#PopupEvents">Handling click events</a></li>
+ </ol>
+ </li>
+ <li><a href="#groups">Creating Menu Groups</a>
+ <ol>
+ <li><a href="#checkable">Using checkable menu items</a></li>
+ </ol>
+ </li>
+ <li><a href="#intents">Adding Menu Items Based on an Intent</a>
+ <ol>
+ <li><a href="#AllowingToAdd">Allowing your activity to be added to other menus</a></li>
+ </ol>
+ </li>
+</ol>
<h2>Key classes</h2>
<ol>
<li>{@link android.view.Menu}</li>
<li>{@link android.view.MenuItem}</li>
<li>{@link android.view.ContextMenu}</li>
- <li>{@link android.view.SubMenu}</li>
+ <li>{@link android.view.ActionMode}</li>
</ol>
<h2>See also</h2>
<ol>
<li><a href="{@docRoot}guide/topics/ui/actionbar.html">Action Bar</a></li>
<li><a href="{@docRoot}guide/topics/resources/menu-resource.html">Menu Resource</a></li>
+ <li><a
+href="http://android-developers.blogspot.com/2012/01/say-goodbye-to-menu-button.html">Say
+Goodbye to the Menu Button</a></li>
</ol>
</div>
</div>
-<p>Menus are an important part of an activity's user interface, which provide users a familiar
-way to perform actions. Android offers a simple framework for you to add standard
-menus to your application.</p>
+<p>Menus are a common user interface component in many types of applications. To provide a familiar
+and consistent user experience, you should use the {@link android.view.Menu} APIs to present user
+actions and other options in your activities.</p>
-<p>There are three types of application menus:</p>
+<p>Beginning with Android 3.0 (API level 11), Android-powered devices are no longer required to
+provide a dedicated <em>Menu</em> button. With this change, Android apps should migrate away from a
+dependence on the traditional 6-item menu panel and instead provide an action bar to present common
+user actions.</p>
+
+<p>Although the design and user experience for some menu items have changed, the semantics to define
+a set of actions and options is still based on the {@link android.view.Menu} APIs. This
+guide shows how to create the three fundamental types of menus or action presentations on all
+versions of Android:</p>
+
<dl>
- <dt><strong>Options Menu</strong></dt>
- <dd>The primary collection of menu items for an activity, which appears when the user touches
-the MENU button. When your application is running on Android 3.0 or later, you can provide
-quick access to select menu items by placing them directly in the <a
-href="{@docRoot}guide/topics/ui/actionbar.html">Action Bar</a>, as "action items."</dd>
- <dt><strong>Context Menu</strong></dt>
- <dd>A floating list of menu items that appears when the user touches and holds a view
-that's registered to provide a context menu.
+ <dt><strong>Options menu and action bar</strong></dt>
+ <dd>The <a href="#options-menu">options menu</a> is the primary collection of menu items for an
+activity. It's where you should place actions that have a global impact on the app, such as
+"Search," "Compose email," and "Settings."
+ <p>If you're developing for Android 2.3 or lower, users can
+reveal the options menu panel by pressing the <em>Menu</em> button.</p>
+ <p>On Android 3.0 and higher, items from the options menu are presented by the <a
+href="{@docRoot}guide/topics/ui/actionbar.html">action bar</a> as a combination of on-screen action
+items and overflow options. Beginning with Android 3.0, the <em>Menu</em> button is deprecated (some
+devices
+don't have one), so you should migrate toward using the action bar to provide access to actions and
+other options.</p>
+ <p>See the section about <a href="#options-menu">Creating an Options Menu</a>.</p>
+ </dd>
+
+ <dt><strong>Context menu and contextual action mode</strong></dt>
+
+ <dd>A context menu is a <a href="#FloatingContextMenu">floating menu</a> that appears when the
+user performs a long-click on an element. It provides actions that affect the selected content or
+context frame.
+ <p>When developing for Android 3.0 and higher, you should instead use the <a
+href="#CAB">contextual action mode</a> to enable actions on selected content. This mode displays
+action items that affect the selected content in a bar at the top of the screen and allows the user
+to select multiple items.</p>
+ <p>See the section about <a href="#context-menu">Creating Contextual Menus</a>.</p>
</dd>
- <dt><strong>Submenu</strong></dt>
- <dd>A floating list of menu items that appears when the user touches a menu item that contains
-a nested menu.</dd>
+
+ <dt><strong>Popup menu</strong></dt>
+ <dd>A popup menu displays a list of items in a vertical list that's anchored to the view that
+invoked the menu. It's good for providing an overflow of actions that relate to specific content or
+to provide options for a second part of a command. Actions in a popup menu should
+<strong>not</strong> directly affect the corresponding content—that's what contextual actions
+are for. Rather, the popup menu is for extended actions that relate to regions of content in your
+activity.
+ <p>See the section about <a href="#PopupMenu">Creating a Popup Menu</a>.</p>
+</dd>
</dl>
-<p>This document shows you how to create each type of menu, using XML to define the content of
-the menu and callback methods in your activity to respond when the user selects an item.</p>
+<h2 id="xml">Defining a Menu in XML</h2>
-<h2 id="xml">Creating a Menu Resource</h2>
+<p>For all menu types, Android provides a standard XML format to define menu items.
+Instead of building a menu in your activity's code, you should define a menu and all its items in an
+XML <a href="{@docRoot}guide/topics/resources/menu-resource.html">menu resource</a>. You can then
+inflate the menu resource (load it as a {@link android.view.Menu} object) in your activity or
+fragment.</p>
-<p>Instead of instantiating a {@link android.view.Menu} in your application code, you should
-define a menu and all its items in an XML <a
-href="{@docRoot}guide/topics/resources/menu-resource.html">menu resource</a>, then inflate the menu
-resource (load it as a programmable object) in your application code. Using a menu resource to
-define your menu is a good practice because it separates the content for the menu from your
-application code. It's also easier to visualize the structure and content of a menu in XML.</p>
+<p>Using a menu resource is a good practice for a few reasons:</p>
+<ul>
+ <li>It's easier to visualize the menu structure in XML.</li>
+ <li>It separates the content for the menu from your application's behavioral code.</li>
+ <li>It allows you to create alternative menu configurations for different platform versions,
+screen sizes, and other configurations by leveraging the <a
+href="{@docRoot}guide/topics/resources/index.html">app resources</a> framework.</li>
+</ul>
-<p>To create a menu resource, create an XML file inside your project's <code>res/menu/</code>
+<p>To define the menu, create an XML file inside your project's <code>res/menu/</code>
directory and build the menu with the following elements:</p>
<dl>
<dt><code><menu></code></dt>
@@ -90,8 +142,8 @@
<dt><code><group></code></dt>
<dd>An optional, invisible container for {@code <item>} elements. It allows you to
-categorize menu items so they share properties such as active state and visibility. See the
-section about <a href="#groups">Menu groups</a>.</dd>
+categorize menu items so they share properties such as active state and visibility. For more
+information, see the section about <a href="#groups">Creating Menu Groups</a>.</dd>
</dl>
@@ -101,14 +153,17 @@
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<item android:id="@+id/new_game"
android:icon="@drawable/ic_new_game"
- android:title="@string/new_game" />
+ android:title="@string/new_game"
+ android:showAsAction="ifRoom"/>
<item android:id="@+id/help"
android:icon="@drawable/ic_help"
android:title="@string/help" />
</menu>
</pre>
-<p>This example defines a menu with two items. Each item includes the attributes:</p>
+<p>The <code><item></code> element supports several attributes you can use to define an item's
+appearance and behavior. The items in the above menu include the following attributes:</p>
+
<dl>
<dt>{@code android:id}</dt>
<dd>A resource ID that's unique to the item, which allows the application can recognize the item
@@ -117,312 +172,24 @@
<dd>A reference to a drawable to use as the item's icon.</dd>
<dt>{@code android:title}</dt>
<dd>A reference to a string to use as the item's title.</dd>
+ <dt>{@code android:showAsAction}</dt>
+ <dd>Specifies when and how this item should appear as an action item in the <a
+href="{@docRoot}guide/topics/ui/actionbar.html">action bar</a>.</dd>
</dl>
-<p>There are many more attributes you can include in an {@code <item>}, including some that
- specify how the item may appear in the <a
-href="{@docRoot}guide/topics/ui/actionbar.html">Action Bar</a>. For more information about the XML
-syntax and attributes for a menu resource, see the <a
-href="{@docRoot}guide/topics/resources/menu-resource.html">Menu Resource</a> reference.</p>
+<p>These are the most important attributes you should use, but there are many more available.
+For information about all the supported attributes, see the <a
+href="{@docRoot}guide/topics/resources/menu-resource.html">Menu Resource</a> document.</p>
-
-
-<h2 id="Inflating">Inflating a Menu Resource</h2>
-
-<p>From your application code, you can inflate a menu resource (convert the XML resource into a
-programmable object) using
-{@link android.view.MenuInflater#inflate(int,Menu) MenuInflater.inflate()}. For
-example, the following code inflates the <code>game_menu.xml</code> file defined above, during the
-{@link android.app.Activity#onCreateOptionsMenu(Menu) onCreateOptionsMenu()} callback method, to
-use the menu as the activity's Options Menu:</p>
-
-<pre>
-@Override
-public boolean onCreateOptionsMenu(Menu menu) {
- MenuInflater inflater = getMenuInflater();
- inflater.inflate(R.menu.game_menu, menu);
- return true;
-}
-</pre>
-
-<p>The {@link android.app.Activity#getMenuInflater()} method returns a {@link
-android.view.MenuInflater} for the activity. With this object, you can call {@link
-android.view.MenuInflater#inflate(int,Menu) inflate()}, which inflates a menu resource into a
-{@link android.view.Menu} object. In this example, the menu resource defined by
-<code>game_menu.xml</code>
-is inflated into the {@link android.view.Menu} that was passed into {@link
-android.app.Activity#onCreateOptionsMenu(Menu) onCreateOptionsMenu()}. (This callback method for
-the Options Menu is discussed more in the next section.)</p>
-
-
-
-<h2 id="options-menu">Creating an Options Menu</h2>
-
-<div class="figure" style="width:200px">
- <img src="{@docRoot}images/options_menu.png" height="333" alt="" />
- <p class="img-caption"><strong>Figure 1.</strong> Screenshot of the Options Menu in the
-Browser.</p>
-</div>
-
-<p>The Options Menu is where you should include basic activity actions and necessary navigation
-items (for example, a button to open the application settings). Items in the Options Menu are
-accessible in two distinct ways: the MENU button or in the <a
-href="{@docRoot}guide/topics/ui/actionbar.html">Action Bar</a> (on devices running Android 3.0
-or higher).</p>
-
-<p>When running on a device with Android 2.3 and lower, the Options Menu appears at the bottom of
-the screen, as shown in figure 1. When opened, the first visible portion of the Options Menu is
-the icon menu. It holds the first six menu items. If you add more than six items to the
-Options Menu, Android places the sixth item and those after it into the overflow menu, which the
-user can open by touching the "More" menu item.</p>
-
-<p>On Android 3.0 and higher, items from the Options Menu is placed in the Action Bar, which appears
-at the top of the activity in place of the traditional title bar. By default all items from the
-Options Menu are placed in the overflow menu, which the user can open by touching the menu icon
-on the right side of the Action Bar. However, you can place select menu items directly in the
-Action Bar as "action items," for instant access, as shown in figure 2.</p>
-
-<p>When the Android system creates the Options Menu for the first time, it calls your
-activity's {@link android.app.Activity#onCreateOptionsMenu(Menu)
-onCreateOptionsMenu()} method. Override this method in your activity
-and populate the {@link android.view.Menu} that is passed into the method,
-{@link android.view.Menu} by inflating a menu resource as described above in <a
-href="#Inflating">Inflating a Menu Resource</a>. For example:</p>
-
-<pre>
-@Override
-public boolean onCreateOptionsMenu(Menu menu) {
- MenuInflater inflater = getMenuInflater();
- inflater.inflate(R.menu.game_menu, menu);
- return true;
-}
-</pre>
-
-<div class="figure" style="width:450px">
-<img src="{@docRoot}images/ui/actionbar.png" alt="" />
-<p class="img-caption"><strong>Figure 2.</strong> Action bar from the <a
-href="{@docRoot}resources/samples/HoneycombGallery/index.html">Honeycomb Gallery</a> app, including
-navigation tabs and a camera action item (plus the overflow menu button).</p>
-</div>
-
-<p>You can also populate the menu in code, using {@link android.view.Menu#add(int,int,int,int)
-add()} to add items to the {@link android.view.Menu}.</p>
-
-<p class="note"><strong>Note:</strong> On Android 2.3 and lower, the system calls {@link
-android.app.Activity#onCreateOptionsMenu(Menu) onCreateOptionsMenu()} to create the Options Menu
-when the user opens it for the first time, but on Android 3.0 and greater, the system creates it as
-soon as the activity is created, in order to populate the Action Bar.</p>
-
-
-<h3 id="RespondingOptionsMenu">Responding to user action</h3>
-
-<p>When the user selects a menu item from the Options Menu (including action items in the
-Action Bar), the system calls your activity's
-{@link android.app.Activity#onOptionsItemSelected(MenuItem) onOptionsItemSelected()}
-method. This method passes the
-{@link android.view.MenuItem} that the user selected. You can identify the menu item by calling
-{@link android.view.MenuItem#getItemId()}, which returns the unique ID for the menu
-item (defined by the {@code android:id} attribute in the menu resource or with an integer
-given to the {@link android.view.Menu#add(int,int,int,int) add()} method). You can match this ID
-against known menu items and perform the appropriate action. For example:</p>
-
-<pre>
-@Override
-public boolean onOptionsItemSelected(MenuItem item) {
- // Handle item selection
- switch (item.getItemId()) {
- case R.id.new_game:
- newGame();
- return true;
- case R.id.help:
- showHelp();
- return true;
- default:
- return super.onOptionsItemSelected(item);
- }
-}
-</pre>
-
-<p>In this example, {@link android.view.MenuItem#getItemId()} queries the ID for the selected menu
-item and the switch statement compares the ID against the resource IDs that were assigned to menu
-items in the XML resource. When a switch case successfully handles the menu item, it
-returns {@code true} to indicate that the item selection was handled. Otherwise, the default
-statement passes the menu item to the super class, in
-case it can handle the item selected. (If you've directly extended the {@link android.app.Activity}
-class, then the super class returns {@code false}, but it's a good practice to
-pass unhandled menu items to the super class instead of directly returning {@code false}.)</p>
-
-<p>Additionally, Android 3.0 adds the ability for you to define the on-click behavior for a menu
-item in the <a href="{@docRoot}guide/topics/resources/menu-resource.html">menu resource</a> XML,
-using the {@code android:onClick} attribute. So you don't need to implement {@link
-android.app.Activity#onOptionsItemSelected(MenuItem) onOptionsItemSelected()}. Using the {@code
-android:onClick} attribute, you can specify a method to call when the user selects the menu item.
-Your activity must then implement the method specified in the {@code android:onClick} attribute so
-that it accepts a single {@link android.view.MenuItem} parameter—when the system calls this
-method, it passes the menu item selected.</p>
-
-<p class="note"><strong>Tip:</strong> If your application contains multiple activities and
-some of them provide the same Options Menu, consider creating
-an activity that implements nothing except the {@link android.app.Activity#onCreateOptionsMenu(Menu)
-onCreateOptionsMenu()} and {@link android.app.Activity#onOptionsItemSelected(MenuItem)
-onOptionsItemSelected()} methods. Then extend this class for each activity that should share the
-same Options Menu. This way, you have to manage only one set of code for handling menu
-actions and each descendant class inherits the menu behaviors.<br/><br/>
-If you want to add menu items to one of your descendant activities,
-override {@link android.app.Activity#onCreateOptionsMenu(Menu)
-onCreateOptionsMenu()} in that activity. Call {@code super.onCreateOptionsMenu(menu)} so the
-original menu items are created, then add new menu items with {@link
-android.view.Menu#add(int,int,int,int) menu.add()}. You can also override the super class's
-behavior for individual menu items.</p>
-
-
-<h3 id="ChangingTheMenu">Changing menu items at runtime</h3>
-
-<p>Once the activity is created, the {@link android.app.Activity#onCreateOptionsMenu(Menu)
-onCreateOptionsMenu()} method is
-called only once, as described above. The system keeps and re-uses the {@link
-android.view.Menu} you define in this method until your activity is destroyed. If you want to change
-the Options Menu any time after it's first created, you must override the
-{@link android.app.Activity#onPrepareOptionsMenu(Menu) onPrepareOptionsMenu()} method. This passes
-you the {@link android.view.Menu} object as it currently exists. This is useful if you'd like to
-remove, add, disable, or enable menu items depending on the current state of your application.</p>
-
-<p>On Android 2.3 and lower, the system calls {@link android.app.Activity#onPrepareOptionsMenu(Menu)
-onPrepareOptionsMenu()} each time the user opens the Options Menu.</p>
-
-<p>On Android 3.0 and higher, you must call {@link android.app.Activity#invalidateOptionsMenu
-invalidateOptionsMenu()} when you want to update the menu, because the menu is always open. The
-system will then call {@link android.app.Activity#onPrepareOptionsMenu(Menu) onPrepareOptionsMenu()}
-so you can update the menu items.</p>
-
-<p class="note"><strong>Note:</strong>
-You should never change items in the Options Menu based on the {@link android.view.View} currently
-in focus. When in touch mode (when the user is not using a trackball or d-pad), views
-cannot take focus, so you should never use focus as the basis for modifying
-items in the Options Menu. If you want to provide menu items that are context-sensitive to a {@link
-android.view.View}, use a <a href="#context-menu">Context Menu</a>.</p>
-
-<p>If you're developing for Android 3.0 or higher, be sure to also read the <a
-href="{@docRoot}guide/topics/ui/actionbar.html">Action Bar</a> developer guide.</p>
-
-
-
-
-<h2 id="context-menu">Creating a Context Menu</h2>
-
-<p>A context menu is conceptually similar to the menu displayed when the user performs a
-"right-click" on a PC. You should use a context menu to provide the user access to
-actions that pertain to a specific item in the user interface. On Android, a context menu is
-displayed when the user performs a "long press" (press and hold) on an item.</p>
-
-<p>You can create a context menu for any View, though context menus are most often used for items in
-a {@link android.widget.ListView}. When the user performs a long-press on an item in a ListView and
-the list is registered to provide a context menu, the list item signals to the user that a context
-menu is available by animating its background color—it transitions from
-orange to white before opening the context menu. (The Contacts application demonstrates this
-feature.)</p>
-
-<div class="sidebox-wrapper">
-<div class="sidebox">
-<h3>Register a ListView</h3>
-<p>If your activity uses a {@link android.widget.ListView} and
-you want all list items to provide a context menu, register all items for a context
-menu by passing the {@link android.widget.ListView} to {@link
-android.app.Activity#registerForContextMenu(View) registerForContextMenu()}. For
-example, if you're using a {@link android.app.ListActivity}, register all list items like this:</p>
-<p><code>registerForContextMenu({@link android.app.ListActivity#getListView()});</code></p>
-</div>
-</div>
-
-<p>In order for a View to provide a context menu, you must "register" the view for a context
-menu. Call {@link android.app.Activity#registerForContextMenu(View) registerForContextMenu()} and
-pass it the {@link android.view.View} you want to give a context menu. When this View then
-receives a long-press, it displays a context menu.</p>
-
-<p>To define the context menu's appearance and behavior, override your activity's context menu
-callback methods, {@link android.app.Activity#onCreateContextMenu(ContextMenu,View,ContextMenuInfo)
-onCreateContextMenu()} and
-{@link android.app.Activity#onContextItemSelected(MenuItem) onContextItemSelected()}.</p>
-
-<p>For example, here's an {@link
-android.app.Activity#onCreateContextMenu(ContextMenu,View,ContextMenuInfo)
-onCreateContextMenu()} that uses the {@code context_menu.xml} menu resource:</p>
-<pre>
-@Override
-public void onCreateContextMenu(ContextMenu menu, View v,
- ContextMenuInfo menuInfo) {
- super.onCreateContextMenu(menu, v, menuInfo);
- MenuInflater inflater = getMenuInflater();
- inflater.inflate(R.menu.context_menu, menu);
-}
-</pre>
-
-<p>{@link android.view.MenuInflater} is used to inflate the context menu from a <a
-href="{@docRoot}guide/topics/resources/menu-resource.html">menu resource</a>. (You can also use
-{@link android.view.Menu#add(int,int,int,int) add()} to add menu items.) The callback method
-parameters include the {@link android.view.View}
-that the user selected and a {@link android.view.ContextMenu.ContextMenuInfo} object that provides
-additional information about the item selected. You might use these parameters to determine
-which context menu should be created, but in this example, all context menus for the activity are
-the same.</p>
-
-<p>Then when the user selects an item from the context menu, the system calls {@link
-android.app.Activity#onContextItemSelected(MenuItem) onContextItemSelected()}. Here is an example
-of how you can handle selected items:</p>
-
-<pre>
-@Override
-public boolean onContextItemSelected(MenuItem item) {
- AdapterContextMenuInfo info = (AdapterContextMenuInfo) item.getMenuInfo();
- switch (item.getItemId()) {
- case R.id.edit:
- editNote(info.id);
- return true;
- case R.id.delete:
- deleteNote(info.id);
- return true;
- default:
- return super.onContextItemSelected(item);
- }
-}
-</pre>
-
-<p>The structure of this code is similar to the example for <a href="#options-menu">Creating an
-Options Menu</a>, in which {@link android.view.MenuItem#getItemId()} queries the ID for the selected
-menu item and a switch statement matches the item to the IDs that are defined in the menu resource.
-And like the options menu example, the default statement calls the super class in case it
-can handle menu items not handled here, if necessary.</p>
-
-<p>In this example, the selected item is an item from a {@link android.widget.ListView}. To
-perform an action on the selected item, the application needs to know the list
-ID for the selected item (it's position in the ListView). To get the ID, the application calls
-{@link android.view.MenuItem#getMenuInfo()}, which returns a {@link
-android.widget.AdapterView.AdapterContextMenuInfo} object that includes the list ID for the
-selected item in the {@link android.widget.AdapterView.AdapterContextMenuInfo#id id} field. The
-local methods <code>editNote()</code> and <code>deleteNote()</code> methods accept this list ID to
-perform an action on the data specified by the list ID.</p>
-
-<p class="note"><strong>Note:</strong> Items in a context menu do not support icons or shortcut
-keys.</p>
-
-
-
-<h2 id="submenu">Creating Submenus</h2>
-
-<p>A submenu is a menu that the user can open by selecting an item in another menu. You can add a
-submenu to any menu (except a submenu). Submenus are useful when your application has a lot of
-functions that can be organized into topics, like items in a PC application's menu bar (File, Edit,
-View, etc.).</p>
-
-<p>When creating your <a href="{@docRoot}guide/topics/resources/menu-resource.html">menu
-resource</a>, you can create a submenu by adding a {@code <menu>} element as the child of an
-{@code <item>}. For example:</p>
+<p>You can add a submenu to an item in any menu (except a submenu) by adding a {@code <menu>}
+element as the child of an {@code <item>}. Submenus are useful when your application has a lot
+of functions that can be organized into topics, like items in a PC application's menu bar (File,
+Edit, View, etc.). For example:</p>
<pre>
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<item android:id="@+id/file"
- android:icon="@drawable/file"
android:title="@string/file" >
<!-- "file" submenu -->
<menu>
@@ -435,23 +202,625 @@
</menu>
</pre>
-<p>When the user selects an item from a submenu, the parent menu's respective on-item-selected
-callback method receives the event. For instance, if the above menu is applied as an Options Menu,
-then the {@link android.app.Activity#onOptionsItemSelected(MenuItem) onOptionsItemSelected()} method
-is called when a submenu item is selected.</p>
-
-<p>You can also use {@link android.view.Menu#addSubMenu(int,int,int,int) addSubMenu()} to
-dynamically add a {@link android.view.SubMenu} to an existing {@link android.view.Menu}. This
-returns the new {@link android.view.SubMenu} object, to which you can add
-submenu items, using {@link android.view.Menu#add(int,int,int,int) add()}</p>
+<p>To use the menu in your activity, you need to inflate the menu resource (convert the XML
+resource into a programmable object) using {@link android.view.MenuInflater#inflate(int,Menu)
+MenuInflater.inflate()}. In the following sections, you'll see how to inflate a menu for each
+menu type.</p>
-<h2 id="features">Other Menu Features</h2>
+<h2 id="options-menu">Creating an Options Menu</h2>
-<p>Here are some other features that you can apply to most menu items.</p>
+<div class="figure" style="width:200px;margin:0">
+ <img src="{@docRoot}images/options_menu.png" height="333" alt="" />
+ <p class="img-caption"><strong>Figure 1.</strong> Options menu in the
+Browser, on Android 2.3.</p>
+</div>
-<h3 id="groups">Menu groups</h3>
+<p>The options menu is where you should include actions and other options that are relevant to the
+current activity context, such as "Search," "Compose email," and "Settings."</p>
+
+<p>Where the items in your options menu appear on the screen depends on the version for which you've
+developed your application:</p>
+
+<ul>
+ <li>If you've developed your application for <strong>Android 2.3.x (API level 10) or
+lower</strong>, the contents of your options menu appear at the bottom of the screen when the user
+presses the <em>Menu</em> button, as shown in figure 1. When opened, the first visible portion is
+the icon
+menu, which holds up to six menu items. If your menu includes more than six items, Android places
+the sixth item and the rest into the overflow menu, which the user can open by selecting
+<em>More</em>.</li>
+
+ <li>If you've developed your application for <strong>Android 3.0 (API level 11) and
+higher</strong>, items from the options menu are available in the <a
+href="{@docRoot}guide/topics/ui/actionbar.html">action bar</a>. By default, the system
+places all items in the action overflow, which the user can reveal with the action overflow icon on
+the right side of the action bar (or by pressing the device <em>Menu</em> button, if available). To
+enable
+quick access to important actions, you can promote a few items to appear in the action bar by adding
+{@code android:showAsAction="ifRoom"} to the corresponding {@code <item>} elements (see figure
+2). <p>For more information about action items and other action bar behaviors, see the <a
+href="{@docRoot}guide/topics/ui/actionbar.html">Action Bar</a> guide. </p>
+<p class="note"><strong>Note:</strong> Even if you're <em>not</em> developing for Android 3.0 or
+higher, you can build your own action bar layout for a similar effect. For an example of how you can
+support older versions of Android with an action bar, see the <a
+href="{@docRoot}resources/samples/ActionBarCompat/index.html">Action Bar Compatibility</a>
+sample.</p>
+</li>
+</ul>
+
+<img src="{@docRoot}images/ui/actionbar.png" alt="" />
+<p class="img-caption"><strong>Figure 2.</strong> Action bar from the <a
+href="{@docRoot}resources/samples/HoneycombGallery/index.html">Honeycomb Gallery</a> app, showing
+navigation tabs and a camera action item (plus the action overflow button).</p>
+
+<p>You can declare items for the options menu from either your {@link android.app.Activity}
+subclass or a {@link android.app.Fragment} subclass. If both your activity and fragment(s)
+declare items for the options menu, they are combined in the UI. The activity's items appear
+first, followed by those of each fragment in the order in which each fragment is added to the
+activity. If necessary, you can re-order the menu items with the {@code android:orderInCategory}
+attribute in each {@code <item>} you need to move.</p>
+
+<p>To specify the options menu for an activity, override {@link
+android.app.Activity#onCreateOptionsMenu(Menu) onCreateOptionsMenu()} (fragments provide their
+own {@link android.app.Fragment#onCreateOptionsMenu onCreateOptionsMenu()} callback). In this
+method, you can inflate your menu resource (<a href="#xml">defined in XML</a>) into the {@link
+android.view.Menu} provided in the callback. For example:</p>
+
+<pre>
+@Override
+public boolean onCreateOptionsMenu(Menu menu) {
+ MenuInflater inflater = {@link android.app.Activity#getMenuInflater()};
+ inflater.inflate(R.menu.game_menu, menu);
+ return true;
+}
+</pre>
+
+<p>You can also add menu items using {@link android.view.Menu#add(int,int,int,int)
+add()} and retrieve items with {@link android.view.Menu#findItem findItem()} to revise their
+properties with {@link android.view.MenuItem} APIs.</p>
+
+<p>If you've developed your application for Android 2.3.x and lower, the system calls {@link
+android.app.Activity#onCreateOptionsMenu(Menu) onCreateOptionsMenu()} to create the options menu
+when the user opens the menu for the first time. If you've developed for Android 3.0 and higher, the
+system calls {@link android.app.Activity#onCreateOptionsMenu(Menu) onCreateOptionsMenu()} when
+starting the activity, in order to show items to the action bar.</p>
+
+
+
+<h3 id="RespondingOptionsMenu">Handling click events</h3>
+
+<p>When the user selects an item from the options menu (including action items in the action bar),
+the system calls your activity's {@link android.app.Activity#onOptionsItemSelected(MenuItem)
+onOptionsItemSelected()} method. This method passes the {@link android.view.MenuItem} selected. You
+can identify the item by calling {@link android.view.MenuItem#getItemId()}, which returns the unique
+ID for the menu item (defined by the {@code android:id} attribute in the menu resource or with an
+integer given to the {@link android.view.Menu#add(int,int,int,int) add()} method). You can match
+this ID against known menu items to perform the appropriate action. For example:</p>
+
+<pre>
+@Override
+public boolean onOptionsItemSelected(MenuItem item) {
+ // Handle item selection
+ switch (item.getItemId()) {
+ case R.id.new_game:
+ newGame();
+ return true;
+ case R.id.help:
+ showHelp();
+ return true;
+ default:
+ return super.onOptionsItemSelected(item);
+ }
+}
+</pre>
+
+<p>When you successfully handle a menu item, return {@code true}. If you don't handle the menu
+item, you should call the superclass implementation of {@link
+android.app.Activity#onOptionsItemSelected(MenuItem) onOptionsItemSelected()} (the default
+implementation returns false).</p>
+
+<p>If your activity includes fragments, the system first calls {@link
+android.app.Activity#onOptionsItemSelected(MenuItem) onOptionsItemSelected()} for the activity then
+for each fragment (in the order each fragment was added) until one returns
+{@code true} or all fragments have been called.</p>
+
+<p class="note"><strong>Tip:</strong> Android 3.0 adds the ability for you to define the on-click
+behavior for a menu item in XML, using the {@code android:onClick} attribute. The value for the
+attribute must be the name of a method defined by the activity using the menu. The method
+must be public and accept a single {@link android.view.MenuItem} parameter—when the system
+calls this method, it passes the menu item selected. For more information and an example, see the <a
+href="{@docRoot}guide/topics/resources/menu-resource.html">Menu Resource</a> document.</p>
+
+<p class="note"><strong>Tip:</strong> If your application contains multiple activities and
+some of them provide the same options menu, consider creating
+an activity that implements nothing except the {@link android.app.Activity#onCreateOptionsMenu(Menu)
+onCreateOptionsMenu()} and {@link android.app.Activity#onOptionsItemSelected(MenuItem)
+onOptionsItemSelected()} methods. Then extend this class for each activity that should share the
+same options menu. This way, you can manage one set of code for handling menu
+actions and each descendant class inherits the menu behaviors.
+If you want to add menu items to one of the descendant activities,
+override {@link android.app.Activity#onCreateOptionsMenu(Menu)
+onCreateOptionsMenu()} in that activity. Call {@code super.onCreateOptionsMenu(menu)} so the
+original menu items are created, then add new menu items with {@link
+android.view.Menu#add(int,int,int,int) menu.add()}. You can also override the super class's
+behavior for individual menu items.</p>
+
+
+<h3 id="ChangingTheMenu">Changing menu items at runtime</h3>
+
+<p>After the system calls {@link android.app.Activity#onCreateOptionsMenu(Menu)
+onCreateOptionsMenu()}, it retains an instance of the {@link android.view.Menu} you populate and
+will not call {@link android.app.Activity#onCreateOptionsMenu(Menu) onCreateOptionsMenu()}
+again unless the menu is invalidated for some reason. However, you should use {@link
+android.app.Activity#onCreateOptionsMenu(Menu) onCreateOptionsMenu()} only to create the initial
+menu state and not to make changes during the activity lifecycle.</p>
+
+<p>If you want to modify the options menu based on
+events that occur during the activity lifecycle, you can do so in
+the {@link android.app.Activity#onPrepareOptionsMenu(Menu) onPrepareOptionsMenu()} method. This
+method passes you the {@link android.view.Menu} object as it currently exists so you can modify it,
+such as add, remove, or disable items. (Fragments also provide an {@link
+android.app.Fragment#onPrepareOptionsMenu onPrepareOptionsMenu()} callback.)</p>
+
+<p>On Android 2.3.x and lower, the system calls {@link
+android.app.Activity#onPrepareOptionsMenu(Menu)
+onPrepareOptionsMenu()} each time the user opens the options menu (presses the <em>Menu</em>
+button).</p>
+
+<p>On Android 3.0 and higher, the options menu is considered to always be open when menu items are
+presented in the action bar. When an event occurs and you want to perform a menu update, you must
+call {@link android.app.Activity#invalidateOptionsMenu invalidateOptionsMenu()} to request that the
+system call {@link android.app.Activity#onPrepareOptionsMenu(Menu) onPrepareOptionsMenu()}.</p>
+
+<p class="note"><strong>Note:</strong>
+You should never change items in the options menu based on the {@link android.view.View} currently
+in focus. When in touch mode (when the user is not using a trackball or d-pad), views
+cannot take focus, so you should never use focus as the basis for modifying
+items in the options menu. If you want to provide menu items that are context-sensitive to a {@link
+android.view.View}, use a <a href="#context-menu">Context Menu</a>.</p>
+
+
+
+
+<h2 id="context-menu">Creating Contextual Menus</h2>
+
+<div class="figure" style="width:420px;margin-top:-1em">
+ <img src="{@docRoot}images/ui/menu-context.png" alt="" />
+ <p class="img-caption"><strong>Figure 3.</strong> Screenshots of a floating context menu (left)
+and the contextual action bar (right).</p>
+</div>
+
+<p>A contextual menu offers actions that affect a specific item or context frame in the UI. You
+can provide a context menu for any view, but they are most often used for items in a {@link
+android.widget.ListView}, {@link android.widget.GridView}, or other view collections in which
+the user can perform direct actions on each item.</p>
+
+<p>There are two ways to provide contextual actions:</p>
+<ul>
+ <li>In a <a href="#FloatingContextMenu">floating context menu</a>. A menu appears as a
+floating list of menu items (similar to a dialog) when the user performs a long-click (press and
+hold) on a view that declares support for a context menu. Users can perform a contextual
+action on one item at a time.</li>
+
+ <li>In the <a href="#CAB">contextual action mode</a>. This mode is a system implementation of
+{@link android.view.ActionMode} that displays a <em>contextual action bar</em> at the top of the
+screen with action items that affect the selected item(s). When this mode is active, users
+can perform an action on multiple items at once (if your app allows it).</li>
+</ul>
+
+<p class="note"><strong>Note:</strong> The contextual action mode is available on Android 3.0 (API
+level 11) and higher and is the preferred technique for displaying contextual actions when
+available. If your app supports versions lower than 3.0 then you should fall back to a floating
+context menu on those devices.</p>
+
+
+<h3 id="FloatingContextMenu">Creating a floating context menu</h3>
+
+<p>To provide a floating context menu:</p>
+<ol>
+ <li>Register the {@link android.view.View} to which the context menu should be associated by
+calling {@link android.app.Activity#registerForContextMenu(View) registerForContextMenu()} and pass
+it the {@link android.view.View}.
+ <p>If your activity uses a {@link android.widget.ListView} or {@link android.widget.GridView} and
+you want each item to provide the same context menu, register all items for a context menu by
+passing the {@link android.widget.ListView} or {@link android.widget.GridView} to {@link
+android.app.Activity#registerForContextMenu(View) registerForContextMenu()}.</p>
+</li>
+
+ <li>Implement the {@link
+android.view.View.OnCreateContextMenuListener#onCreateContextMenu onCreateContextMenu()} method
+in your {@link android.app.Activity} or {@link android.app.Fragment}.
+ <p>When the registered view receives a long-click event, the system calls your {@link
+android.view.View.OnCreateContextMenuListener#onCreateContextMenu onCreateContextMenu()}
+method. This is where you define the menu items, usually by inflating a menu resource. For
+example:</p>
+<pre>
+@Override
+public void onCreateContextMenu(ContextMenu menu, View v,
+ ContextMenuInfo menuInfo) {
+ super.onCreateContextMenu(menu, v, menuInfo);
+ MenuInflater inflater = getMenuInflater();
+ inflater.inflate(R.menu.context_menu, menu);
+}
+</pre>
+
+<p>{@link android.view.MenuInflater} allows you to inflate the context menu from a <a
+href="{@docRoot}guide/topics/resources/menu-resource.html">menu resource</a>. The callback method
+parameters include the {@link android.view.View}
+that the user selected and a {@link android.view.ContextMenu.ContextMenuInfo} object that provides
+additional information about the item selected. If your activity has several views that each provide
+a different context menu, you might use these parameters to determine which context menu to
+inflate.</p>
+</li>
+
+<li>Implement {@link android.app.Activity#onContextItemSelected(MenuItem)
+onContextItemSelected()}.
+ <p>When the user selects a menu item, the system calls this method so you can perform the
+appropriate action. For example:</p>
+
+<pre>
+@Override
+public boolean onContextItemSelected(MenuItem item) {
+ AdapterContextMenuInfo info = (AdapterContextMenuInfo) item.getMenuInfo();
+ switch (item.getItemId()) {
+ case R.id.edit:
+ editNote(info.id);
+ return true;
+ case R.id.delete:
+ deleteNote(info.id);
+ return true;
+ default:
+ return super.onContextItemSelected(item);
+ }
+}
+</pre>
+
+<p>The {@link android.view.MenuItem#getItemId()} method queries the ID for
+the selected menu item, which you should assign to each menu item in XML using the {@code
+android:id} attribute, as shown in the section about <a href="#xml">Defining a Menu in
+XML</a>.</p>
+
+<p>When you successfully handle a menu item, return {@code true}. If you don't handle the menu item,
+you should pass the menu item to the superclass implementation. If your activity includes fragments,
+the activity receives this callback first. By calling the superclass when unhandled, the system
+passes the event to the respective callback method in each fragment, one at a time (in the order
+each fragment was added) until {@code true} or {@code false} is returned. (The default
+implementation for {@link android.app.Activity} and {@code android.app.Fragment} return {@code
+false}, so you should always call the superclass when unhandled.)</p>
+</li>
+</ol>
+
+
+<h3 id="CAB">Using the contextual action mode</h3>
+
+<p>The contextual action mode is a system implementation of {@link android.view.ActionMode} that
+focuses user interaction toward performing contextual actions. When a
+user enables this mode by selecting an item, a <em>contextual action bar</em> appears at the top of
+the screen to present actions the user can perform on the currently selected item(s). While this
+mode is enabled, the user can select multiple items (if you allow it), deselect items, and continue
+to navigate within the activity (as much as you're willing to allow). The action mode is disabled
+and the contextual action bar disappears when the user deselects all items, presses the BACK button,
+or selects the <em>Done</em> action on the left side of the bar.</p>
+
+<p class="note"><strong>Note:</strong> The contextual action bar is not necessarily
+associated with the <a href="{@docRoot}guide/topics/ui/actionbar.html">action bar</a>. They operate
+independently, even though the contextual action bar visually overtakes the action bar
+position.</p>
+
+<p>If you're developing for Android 3.0 (API level 11) or higher, you
+should usually use the contextual action mode to present contextual actions, instead of the <a
+href="#FloatingContextMenu">floating context menu</a>.</p>
+
+<p>For views that provide contextual actions, you should usually invoke the contextual action mode
+upon one of two events (or both):</p>
+<ul>
+ <li>The user performs a long-click on the view.</li>
+ <li>The user selects a checkbox or similar UI component within the view.</li>
+</ul>
+
+<p>How your application invokes the contextual action mode and defines the behavior for each
+action depends on your design. There are basically two designs:</p>
+<ul>
+ <li>For contextual actions on individual, arbitrary views.</li>
+ <li>For batch contextual actions on groups of items in a {@link
+android.widget.ListView} or {@link android.widget.GridView} (allowing the user to select multiple
+items and perform an action on them all).</li>
+</ul>
+
+<p>The following sections describe the setup required for each scenario.</p>
+
+
+<h4 id="CABforViews">Enabling the contextual action mode for individual views</h4>
+
+<p>If you want to invoke the contextual action mode only when the user selects specific
+views, you should:</p>
+<ol>
+ <li>Implement the {@link android.view.ActionMode.Callback} interface. In its callback methods, you
+can specify the actions for the contextual action bar, respond to click events on action items, and
+handle other lifecycle events for the action mode.</li>
+ <li>Call {@link android.app.Activity#startActionMode startActionMode()} when you want to show the
+bar (such as when the user long-clicks the view).</li>
+</ol>
+
+<p>For example:</p>
+
+<ol>
+ <li>Implement the {@link android.view.ActionMode.Callback ActionMode.Callback} interface:
+<pre>
+private ActionMode.Callback mActionModeCallback = new ActionMode.Callback() {
+
+ // Called when the action mode is created; startActionMode() was called
+ @Override
+ public boolean onCreateActionMode(ActionMode mode, Menu menu) {
+ // Inflate a menu resource providing context menu items
+ MenuInflater inflater = mode.getMenuInflater();
+ inflater.inflate(R.menu.context_menu, menu);
+ return true;
+ }
+
+ // Called each time the action mode is shown. Always called after onCreateActionMode, but
+ // may be called multiple times if the mode is invalidated.
+ @Override
+ public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
+ return false; // Return false if nothing is done
+ }
+
+ // Called when the user selects a contextual menu item
+ @Override
+ public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
+ switch (item.getItemId()) {
+ case R.id.menu_share:
+ shareCurrentItem();
+ mode.finish(); // Action picked, so close the CAB
+ return true;
+ default:
+ return false;
+ }
+ }
+
+ // Called when the user exits the action mode
+ @Override
+ public void onDestroyActionMode(ActionMode mode) {
+ mActionMode = null;
+ }
+};
+</pre>
+
+<p>Notice that these event callbacks are almost exactly the same as the callbacks for the <a
+href="#options-menu">options menu</a>, except each of these also pass the {@link
+android.view.ActionMode} object associated with the event. You can use {@link
+android.view.ActionMode} APIs to make various changes to the CAB, such as revise the title and
+subtitle with {@link android.view.ActionMode#setTitle setTitle()} and {@link
+android.view.ActionMode#setSubtitle setSubtitle()} (useful to indicate how many items are
+selected).</p>
+
+<p>Also notice that the above sample sets the {@code mActionMode} variable null when the
+action mode is destroyed. In the next step, you'll see how it's initialized and how saving
+the member variable in your activity or fragment can be useful.</p>
+</li>
+
+ <li>Call {@link android.app.Activity#startActionMode startActionMode()} to enable the contextual
+action mode when appropriate, such as in response to a long-click on a {@link
+android.view.View}:</p>
+
+<pre>
+someView.setOnLongClickListener(new View.OnLongClickListener() {
+ // Called when the user long-clicks on someView
+ public boolean onLongClick(View view) {
+ if (mActionMode != null) {
+ return false;
+ }
+
+ // Start the CAB using the ActionMode.Callback defined above
+ mActionMode = getActivity().startActionMode(mActionModeCallback);
+ view.setSelected(true);
+ return true;
+ }
+});
+</pre>
+
+<p>When you call {@link android.app.Activity#startActionMode startActionMode()}, the system returns
+the {@link android.view.ActionMode} created. By saving this in a member variable, you can
+make changes to the contextual action bar in response to other events. In the above sample, the
+{@link android.view.ActionMode} is used to ensure that the {@link android.view.ActionMode} instance
+is not recreated if it's already active, by checking whether the member is null before starting the
+action mode.</p>
+</li>
+</ol>
+
+
+
+<h4 id="CABforListView">Enabling batch contextual actions in a ListView or GridView</h4>
+
+<p>If you have a collection of items in a {@link android.widget.ListView} or {@link
+android.widget.GridView} (or another extension of {@link android.widget.AbsListView}) and want to
+allow users to perform batch actions, you should:</p>
+
+<ul>
+ <li>Implement the {@link android.widget.AbsListView.MultiChoiceModeListener} interface and set it
+for the view group with {@link android.widget.AbsListView#setMultiChoiceModeListener
+setMultiChoiceModeListener()}. In the listener's callback methods, you can specify the actions
+for the contextual action bar, respond to click events on action items, and handle other callbacks
+inherited from the {@link android.view.ActionMode.Callback} interface.</li>
+
+ <li>Call {@link android.widget.AbsListView#setChoiceMode setChoiceMode()} with the {@link
+android.widget.AbsListView#CHOICE_MODE_MULTIPLE_MODAL} argument.</li>
+</ul>
+
+<p>For example:</p>
+
+<pre>
+ListView listView = getListView();
+listView.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE_MODAL);
+listView.setMultiChoiceModeListener(new MultiChoiceModeListener() {
+
+ @Override
+ public void onItemCheckedStateChanged(ActionMode mode, int position,
+ long id, boolean checked) {
+ // Here you can do something when items are selected/de-selected,
+ // such as update the title in the CAB
+ }
+
+ @Override
+ public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
+ // Respond to clicks on the actions in the CAB
+ switch (item.getItemId()) {
+ case R.id.menu_delete:
+ deleteSelectedItems();
+ mode.finish(); // Action picked, so close the CAB
+ return true;
+ default:
+ return false;
+ }
+ }
+
+ @Override
+ public boolean onCreateActionMode(ActionMode mode, Menu menu) {
+ // Inflate the menu for the CAB
+ MenuInflater inflater = mode.getMenuInflater();
+ inflater.inflate(R.menu.context, menu);
+ return true;
+ }
+
+ @Override
+ public void onDestroyActionMode(ActionMode mode) {
+ // Here you can make any necessary updates to the activity when
+ // the CAB is removed. By default, selected items are deselected/unchecked.
+ }
+
+ @Override
+ public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
+ // Here you can perform updates to the CAB due to
+ // an {@link android.view.ActionMode#invalidate} request
+ return false;
+ }
+});
+</pre>
+
+<p>That's it. Now when the user selects an item with a long-click, the system calls the {@link
+android.widget.AbsListView.MultiChoiceModeListener#onCreateActionMode onCreateActionMode()}
+method and displays the contextual action bar with the specified actions. While the contextual
+action bar is visible, users can select additional items.</p>
+
+<p>In some cases in which the contextual actions provide common action items, you might
+want to add a checkbox or a similar UI element that allows users to select items, because they
+might not discover the long-click behavior. When a user selects the checkbox, you
+can invoke the contextual action mode by setting the respective list item to the checked
+state with {@link android.widget.AbsListView#setItemChecked setItemChecked()}.</p>
+
+
+
+
+<h2 id="PopupMenu">Creating a Popup Menu</h2>
+
+<div class="figure" style="width:220px">
+<img src="{@docRoot}images/ui/popupmenu.png" alt="" />
+<p><strong>Figure 4.</strong> A popup menu in the Gmail app, anchored to the overflow
+button at the top-right.</p>
+</div>
+
+<p>A {@link android.widget.PopupMenu} is a modal menu anchored to a {@link android.view.View}.
+It appears below the anchor view if there is room, or above the view otherwise. It's useful for:</p>
+<ul>
+ <li>Providing an overflow-style menu for actions that <em>relate to</em> specific content (such as
+Gmail's email headers, shown in figure 4).
+ <p class="note"><strong>Note:</strong> This is not the same as a context menu, which is
+generally for actions that <em>affect</em> selected content. For actions that affect selected
+content, use the <a href="#CAB">contextual action mode</a> or <a
+href="#FloatingContextMenu">floating context menu</a>.</p></li>
+ <li>Providing a second part of a command sentence (such as a button marked "Add"
+that produces a popup menu with different "Add" options).</li>
+ <li>Providing a drop-down similar to {@link android.widget.Spinner} that does not retain
+a persistent selection.</li>
+</ul>
+
+
+<p class="note"><strong>Note:</strong> {@link android.widget.PopupMenu} is available with API
+level 11 and higher.</p>
+
+<p>If you <a href="#xml">define your menu in XML</a>, here's how you can show the popup menu:</p>
+<ol>
+ <li>Instantate a {@link android.widget.PopupMenu} with its constructor, which takes the
+current application {@link android.content.Context} and the {@link android.view.View} to which the
+menu should be anchored.</li>
+ <li>Use {@link android.view.MenuInflater} to inflate your menu resource into the {@link
+android.view.Menu} object returned by {@link
+android.widget.PopupMenu#getMenu() PopupMenu.getMenu()}. On API level 14 and above, you can use
+{@link android.widget.PopupMenu#inflate PopupMenu.inflate()} instead.</li>
+ <li>Call {@link android.widget.PopupMenu#show() PopupMenu.show()}.</li>
+</ol>
+
+<p>For example, here's a button with the {@link android.R.attr#onClick android:onClick} attribute
+that shows a popup menu:</p>
+
+<pre>
+<ImageButton
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:src="@drawable/ic_overflow_holo_dark"
+ android:contentDescription="@string/descr_overflow_button"
+ android:onClick="showPopup" />
+</pre>
+
+<p>The activity can then show the popup menu like this:</p>
+
+<pre>
+public void showPopup(View v) {
+ PopupMenu popup = new PopupMenu(this, v);
+ MenuInflater inflater = popup.getMenuInflater();
+ inflater.inflate(R.menu.actions, popup.getMenu());
+ popup.show();
+}
+</pre>
+
+<p>In API level 14 and higher, you can combine the two lines that inflate the menu with {@link
+android.widget.PopupMenu#inflate PopupMenu.inflate()}.</p>
+
+<p>The menu is dismissed when the user selects an item or touches outside the menu
+area. You can listen for the dismiss event using {@link
+android.widget.PopupMenu.OnDismissListener}.</p>
+
+<h3 id="PopupEvents">Handling click events</h3>
+
+<p>To perform an
+action when the user selects a menu item, you must implement the {@link
+android.widget.PopupMenu.OnMenuItemClickListener} interface and register it with your {@link
+android.widget.PopupMenu} by calling {@link android.widget.PopupMenu#setOnMenuItemClickListener
+setOnMenuItemclickListener()}. When the user selects an item, the system calls the {@link
+android.widget.PopupMenu.OnMenuItemClickListener#onMenuItemClick onMenuItemClick()} callback in
+your interface.</p>
+
+<p>For example:</p>
+
+<pre>
+public void showMenu(View v) {
+ PopupMenu popup = new PopupMenu(this, v);
+
+ // This activity implements OnMenuItemClickListener
+ popup.setOnMenuItemClickListener(this);
+ popup.inflate(R.menu.actions);
+ popup.show();
+}
+
+@Override
+public boolean onMenuItemClick(MenuItem item) {
+ switch (item.getItemId()) {
+ case R.id.archive:
+ archive(item);
+ return true;
+ case R.id.delete:
+ delete(item);
+ return true;
+ default:
+ return false;
+ }
+}
+</pre>
+
+
+<h2 id="groups">Creating Menu Groups</h2>
<p>A menu group is a collection of menu items that share certain traits. With a group, you
can:</p>
@@ -473,38 +842,41 @@
<pre>
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
- <item android:id="@+id/item1"
- android:icon="@drawable/item1"
- android:title="@string/item1" />
+ <item android:id="@+id/menu_save"
+ android:icon="@drawable/menu_save"
+ android:title="@string/menu_save" />
<!-- menu group -->
- <group android:id="@+id/group1">
- <item android:id="@+id/groupItem1"
- android:title="@string/groupItem1" />
- <item android:id="@+id/groupItem2"
- android:title="@string/groupItem2" />
+ <group android:id="@+id/group_delete">
+ <item android:id="@+id/menu_archive"
+ android:title="@string/menu_archive" />
+ <item android:id="@+id/menu_delete"
+ android:title="@string/menu_delete" />
</group>
</menu>
</pre>
-<p>The items that are in the group appear the same as the first item that is not in a
-group—all three items in the menu are siblings. However, you can modify the traits of the two
-items in the group by referencing the group ID and using the methods listed above.</p>
+<p>The items that are in the group appear at the same level as the first item—all three items
+in the menu are siblings. However, you can modify the traits of the two
+items in the group by referencing the group ID and using the methods listed above. The system
+will also never separate grouped items. For example, if you declare {@code
+android:showAsAction="ifRoom"} for each item, they will either both appear in the action
+bar or both appear in the action overflow.</p>
-<h3 id="checkable">Checkable menu items</h3>
+<h3 id="checkable">Using checkable menu items</h3>
<div class="figure" style="width:200px">
<img src="{@docRoot}images/radio_buttons.png" height="333" alt="" />
- <p class="img-caption"><strong>Figure 3.</strong> Screenshot of a submenu with checkable
+ <p class="img-caption"><strong>Figure 5.</strong> Screenshot of a submenu with checkable
items.</p>
</div>
<p>A menu can be useful as an interface for turning options on and off, using a checkbox for
stand-alone options, or radio buttons for groups of
-mutually exclusive options. Figure 2 shows a submenu with items that are checkable with radio
+mutually exclusive options. Figure 5 shows a submenu with items that are checkable with radio
buttons.</p>
-<p class="note"><strong>Note:</strong> Menu items in the Icon Menu (from the Options Menu) cannot
+<p class="note"><strong>Note:</strong> Menu items in the Icon Menu (from the options menu) cannot
display a checkbox or radio button. If you choose to make items in the Icon Menu checkable,
you must manually indicate the checked state by swapping the icon and/or text
each time the state changes.</p>
@@ -550,15 +922,15 @@
<pre>
@Override
public boolean onOptionsItemSelected(MenuItem item) {
- switch (item.getItemId()) {
- case R.id.vibrate:
- case R.id.dont_vibrate:
- if (item.isChecked()) item.setChecked(false);
- else item.setChecked(true);
- return true;
- default:
- return super.onOptionsItemSelected(item);
- }
+ switch (item.getItemId()) {
+ case R.id.vibrate:
+ case R.id.dont_vibrate:
+ if (item.isChecked()) item.setChecked(false);
+ else item.setChecked(true);
+ return true;
+ default:
+ return super.onOptionsItemSelected(item);
+ }
}
</pre>
@@ -575,30 +947,8 @@
href="{@docRoot}guide/topics/data/data-storage.html#pref">Shared Preferences</a>.</p>
-<h3 id="shortcuts">Shortcut keys</h3>
-<p>To facilitate quick access to items in the Options Menu when the user's device has a hardware
-keyboard, you can add quick-access shortcut keys using letters and/or numbers, with the
-{@code android:alphabeticShortcut} and {@code android:numericShortcut} attributes in the {@code
-<item>} element. You can also use the methods {@link
-android.view.MenuItem#setAlphabeticShortcut(char)} and {@link
-android.view.MenuItem#setNumericShortcut(char)}. Shortcut keys are <em>not</em>
-case sensitive.</p>
-
-<p>For example, if you apply the "s" character as an alphabetic shortcut to a "save" menu item, then
-when the menu is open (or while the user holds the MENU button) and the user presses the "s" key,
-the "save" menu item is selected.</p>
-
-<p>This shortcut key is displayed as a tip in the menu item, below the menu item name
-(except for items in the Icon Menu, which are displayed only if the user holds the MENU
-button).</p>
-
-<p class="note"><strong>Note:</strong> Shortcut keys for menu items only work on devices with a
-hardware keyboard. Shortcuts cannot be added to items in a Context Menu.</p>
-
-
-
-<h3 id="intents">Dynamically adding menu intents</h3>
+<h2 id="intents">Adding Menu Items Based on an Intent</h2>
<p>Sometimes you'll want a menu item to launch an activity using an {@link android.content.Intent}
(whether it's an activity in your application or another application). When you know the intent you
@@ -671,7 +1021,7 @@
argument.</p>
-<h4>Allowing your activity to be added to other menus</h4>
+<h3 id="AllowingToAdd">Allowing your activity to be added to other menus</h3>
<p>You can also offer the services of your activity to other applications, so your
application can be included in the menu of others (reverse the roles described above).</p>
@@ -681,7 +1031,7 @@
and/or {@link android.content.Intent#CATEGORY_SELECTED_ALTERNATIVE} values for the intent filter
category. For example:</p>
<pre>
-<intent-filter label="Resize Image">
+<intent-filter label="@string/resize_image">
...
<category android:name="android.intent.category.ALTERNATIVE" />
<category android:name="android.intent.category.SELECTED_ALTERNATIVE" />
diff --git a/docs/html/guide/topics/ui/notifiers/notifications.jd b/docs/html/guide/topics/ui/notifiers/notifications.jd
index 33b0fec..bef9671 100644
--- a/docs/html/guide/topics/ui/notifiers/notifications.jd
+++ b/docs/html/guide/topics/ui/notifiers/notifications.jd
@@ -245,31 +245,27 @@
activity like this can cause it to be mixed with your normal application back stack
in undesired ways. To make it behave correctly, in the manifest declaration
for the activity the attributes
-<code>android:launchMode="singleInstance"</code> and
+<code>android:launchMode="singleTask"</code>,
+<code>android:taskAffinity=""</code> and
<code>android:excludeFromRecents="true"</code>
must be set. The full activity declaration for this sample is:</p>
{@sample development/samples/ApiDemos/AndroidManifest.xml interstitial_affinity}
-<p>Because of the use of <code>singleInstance</code>, you must be careful about launching
-any other activities from this one. These activities will be launched
-in their own task, and care must be taken to make sure this interacts
-well with the current state of your application's task. This is essentially
+<p>You must be careful when launching other activities from this initial activity,
+because this is not a top-level part of the application, does not appear in
+recents, and needs to be relaunched at any point from the notification with new data
+to show. This best approach is to make sure any activity launched from it is
+launched in its own task. When doing this care must be taken to make sure this
+new task interacts well with the current state of your exiting application's
+task. This is essentially
the same as switching to the main application as described for the Email style
notification shown before. Given the <code>makeMessageIntentStack()</code>
-method previously shown, handling a click here would look something like this:</p>
+method previously shown, handling a click then would look something like this:</p>
{@sample development/samples/ApiDemos/src/com/example/android/apis/app/IncomingMessageInterstitial.java
app_launch}
-<p>If you don't want to use the <code>singleInstance</code> launch mode for
-this activity, an alternative approach is to use <code>android:taskAffinity=""</code>.
-This tells Android that the activity should not be treated as part of the
-main application flow, so it will not get mixed together with that. All of the
-other issues discussed here do still apply, though this would allow you to start
-additional activities that are part of this notification task instead of switching
-to and replacing the main application task.</p>
-
<h2 id="ManageYourNotifications">Managing your Notifications</h2>
<p>The {@link android.app.NotificationManager} is a system service that manages all
diff --git a/docs/html/guide/topics/wireless/wifip2p.jd b/docs/html/guide/topics/wireless/wifip2p.jd
new file mode 100644
index 0000000..4dd3d26
--- /dev/null
+++ b/docs/html/guide/topics/wireless/wifip2p.jd
@@ -0,0 +1,611 @@
+page.title=Wi-Fi Direct
+
+@jd:body
+
+ <div id="qv-wrapper">
+ <div id="qv">
+ <h2>In this document</h2>
+
+ <ol>
+ <li><a href="#api">API Overview</a></li>
+ <li><a href="#creating-br">Creating a Broadcast Receiver for Wi-Fi Direct Intents</a></li>
+
+ <li>
+ <a href="#creating-app">Creating a Wi-Fi Direct Application</a>
+
+ <ol>
+ <li><a href="#setup">Initial setup</a></li>
+
+ <li><a href="#discovering">Discovering peers</a></li>
+
+ <li><a href="#connecting">Connecting to peers</a></li>
+
+ <li><a href="#transferring">Transferring data</a></li>
+ </ol>
+ </li>
+ </ol>
+ <h2>Related Samples</h2>
+ <ol>
+ <li><a href="{@docRoot}resources/samples/WiFiDirectDemo/index.html">Wi-Fi Direct Demo</a></li>
+ </ol>
+ </div>
+ </div>
+
+ <p>Wi-Fi Direct allows Android 4.0 (API level 14) or later devices with the appropriate hardware
+ to connect directly to each other via Wi-Fi without an intermediate access point.
+ Using these APIs, you can discover and connect to other devices when each device supports Wi-Fi Direct,
+ then communicate over a speedy connection across distances much longer than a Bluetooth connection.
+ This is useful for applications that share data among users, such as a multiplayer game or
+ a photo sharing application.</p>
+
+ <p>The Wi-Fi Direct APIs consist of the following main parts:</p>
+
+ <ul>
+ <li>Methods that allow you to discover, request, and connect to peers are defined
+ in the {@link android.net.wifi.p2p.WifiP2pManager} class.</li>
+
+ <li>Listeners that allow you to be notified of the success or failure of {@link
+ android.net.wifi.p2p.WifiP2pManager} method calls. When calling {@link
+ android.net.wifi.p2p.WifiP2pManager} methods, each method can receive a specific listener
+ passed in as a parameter.</li>
+
+ <li>Intents that notify you of specific events detected by the Wi-Fi Direct framework,
+ such as a dropped connection or a newly discovered peer.</li>
+ </ul>
+
+ <p>You often use these three main components of the APIs together. For example, you can
+ provide a {@link android.net.wifi.p2p.WifiP2pManager.ActionListener} to a call to {@link
+ android.net.wifi.p2p.WifiP2pManager#discoverPeers discoverPeers()}, so that you can be
+ notified with the {@link android.net.wifi.p2p.WifiP2pManager.ActionListener#onSuccess
+ ActionListener.onSuccess()} and {@link android.net.wifi.p2p.WifiP2pManager.ActionListener#onFailure
+ ActionListener.onFailure()}
+ methods. A {@link android.net.wifi.p2p.WifiP2pManager#WIFI_P2P_PEERS_CHANGED_ACTION} intent is
+ also broadcast if the {@link android.net.wifi.p2p.WifiP2pManager#discoverPeers discoverPeers()}
+ method discovers that the peers list has changed.</p>
+
+ <h2 id="api">API Overview</h2>
+
+<p>The {@link android.net.wifi.p2p.WifiP2pManager} class provides methods to allow you to interact with
+ the Wi-Fi hardware on your device to do things like discover and connect to peers. The following actions
+ are available:</p>
+
+<p class="table-caption"><strong>Table 1.</strong>Wi-Fi Direct Methods</p>
+
+ <table>
+ <tr>
+ <th>Method</th>
+ <th>Description</th>
+ </tr>
+
+ <tr>
+ <td>{@link android.net.wifi.p2p.WifiP2pManager#initialize initialize()}</td>
+ <td>Registers the application with the Wi-Fi framework. This must be called before calling any other Wi-Fi Direct method.</td>
+ </tr>
+
+ <tr>
+ <td>{@link android.net.wifi.p2p.WifiP2pManager#connect connect()}</td>
+ <td>Starts a peer-to-peer connection with a device with the specified configuration.</td>
+ </tr>
+
+ <tr>
+ <td>{@link android.net.wifi.p2p.WifiP2pManager#cancelConnect cancelConnect()}</td>
+ <td>Cancels any ongoing peer-to-peer group negotiation.</td>
+ </tr>
+
+ <tr>
+ <td>{@link android.net.wifi.p2p.WifiP2pManager#requestConnectionInfo requestConnectInfo()}</td>
+ <td>Requests a device's connection information.</td>
+ </tr>
+
+ <tr>
+ <td>{@link android.net.wifi.p2p.WifiP2pManager#createGroup createGroup()}</td>
+ <td>Creates a peer-to-peer group with the current device as the group owner.</td>
+ </tr>
+
+ <tr>
+ <td>{@link android.net.wifi.p2p.WifiP2pManager#removeGroup removeGroup()}</td>
+ <td>Removes the current peer-to-peer group.</td>
+ </tr>
+
+ <tr>
+ <td>{@link android.net.wifi.p2p.WifiP2pManager#requestGroupInfo requestGroupInfo()}</td>
+ <td>Requests peer-to-peer group information.</td>
+ </tr>
+
+ <tr>
+ <td>{@link android.net.wifi.p2p.WifiP2pManager.PeerListListener#discoverPeers discoverPeers()}</td>
+ <td>Initiates peer discovery </td>
+ </tr>
+
+ <tr>
+ <td>{@link android.net.wifi.p2p.WifiP2pManager#requestPeers requestPeers()}</td>
+ <td>Requests the current list of discovered peers.</td>
+ </tr>
+ </table>
+
+
+ <p>{@link android.net.wifi.p2p.WifiP2pManager} methods let you pass in a listener,
+ so that the Wi-Fi Direct framework can notify your
+ activity of the status of a call. The available listener interfaces and the
+ corresponding {@link android.net.wifi.p2p.WifiP2pManager} method calls that use the listeners
+ are described in the following table:</p>
+
+ <p class="table-caption"><strong>Table 2.</strong> Wi-Fi Direct Listeners</p>
+
+ <table>
+ <tr>
+ <th>Listener interface</th>
+ <th>Associated actions</th>
+ </tr>
+ <tr>
+ <td>{@link android.net.wifi.p2p.WifiP2pManager.ActionListener}</td>
+ <td>{@link android.net.wifi.p2p.WifiP2pManager#connect connect()}, {@link
+ android.net.wifi.p2p.WifiP2pManager#cancelConnect cancelConnect()}, {@link
+ android.net.wifi.p2p.WifiP2pManager#createGroup createGroup()}, {@link
+ android.net.wifi.p2p.WifiP2pManager#removeGroup removeGroup()}, and {@link
+ android.net.wifi.p2p.WifiP2pManager.PeerListListener#discoverPeers discoverPeers()}</td>
+ </tr>
+
+ <tr>
+ <td>{@link android.net.wifi.p2p.WifiP2pManager.ChannelListener}</td>
+ <td>{@link android.net.wifi.p2p.WifiP2pManager#initialize initialize()}</td>
+ </tr>
+
+ <tr>
+ <td>{@link android.net.wifi.p2p.WifiP2pManager.ConnectionInfoListener}</td>
+ <td>{@link android.net.wifi.p2p.WifiP2pManager#requestConnectionInfo requestConnectInfo()}</td>
+ </tr>
+
+ <tr>
+ <td>{@link android.net.wifi.p2p.WifiP2pManager.GroupInfoListener}</td>
+ <td>{@link android.net.wifi.p2p.WifiP2pManager#requestGroupInfo requestGroupInfo()}</td>
+ </tr>
+
+ <tr>
+ <td>{@link android.net.wifi.p2p.WifiP2pManager.PeerListListener}</td>
+ <td>{@link android.net.wifi.p2p.WifiP2pManager#requestPeers requestPeers()}</td>
+ </tr>
+ </table>
+
+<p>The Wi-Fi Direct APIs define intents that are broadcast when certain Wi-Fi Direct events happen,
+ such as when a new peer is discovered or when a device's Wi-Fi state changes. You can register
+ to receive these intents in your application by <a href="#creating-br">creating a broadcast
+ receiver</a> that handles these intents:</p>
+
+<p class="table-caption"><strong>Table 3.</strong> Wi-Fi Direct Intents</p>
+
+ <table>
+ <tr>
+ <th>Intent</th>
+ <th>Description</th>
+ </tr>
+ <tr>
+ <td>{@link android.net.wifi.p2p.WifiP2pManager#WIFI_P2P_CONNECTION_CHANGED_ACTION}</td>
+ <td>Broadcast when the state of the device's Wi-Fi connection changes.</td>
+ </tr>
+ <tr>
+ <td>{@link android.net.wifi.p2p.WifiP2pManager#WIFI_P2P_PEERS_CHANGED_ACTION}</td>
+ <td>Broadcast when you call {@link
+ android.net.wifi.p2p.WifiP2pManager.PeerListListener#discoverPeers discoverPeers()}. You
+ usually want to call {@link android.net.wifi.p2p.WifiP2pManager.PeerListListener#requestPeers
+ requestPeers()} to get an updated list of peers if you handle this intent in your
+ application.</td>
+ </tr>
+ <tr>
+ <td>{@link android.net.wifi.p2p.WifiP2pManager#WIFI_P2P_STATE_CHANGED_ACTION}</td>
+ <td>Broadcast when Wi-Fi Direct is enabled or disabled on the device.</td>
+ </tr>
+ <tr>
+ <td>{@link android.net.wifi.p2p.WifiP2pManager#WIFI_P2P_THIS_DEVICE_CHANGED_ACTION}</td>
+ <td>Broadcast when a device's details have changed, such as the device's name.</td>
+ </tr>
+ </table>
+
+
+
+ <h2 id="creating-br">Creating a Broadcast Receiver for Wi-Fi Direct Intents</h2>
+
+ <p>A broadcast receiver allows you to receive intents broadcast by the Android system,
+ so that your application can respond to events that you are interested in. The basic steps
+ for creating a broadcast receiver to handle Wi-Fi Direct intents are as follows:</p>
+
+ <ol>
+ <li>Create a class that extends the {@link android.content.BroadcastReceiver} class. For the
+ class' constructor, you most likely want to have parameters for the {@link
+ android.net.wifi.p2p.WifiP2pManager}, {@link android.net.wifi.p2p.WifiP2pManager.Channel}, and
+ the activity that this broadcast receiver will be registered in. This allows the broadcast
+ receiver to send updates to the activity as well as have access to the Wi-Fi hardware and a
+ communication channel if needed.</li>
+
+ <li>In the broadcast receiver, check for the intents that you are interested in
+ <code>{@link android.content.BroadcastReceiver#onReceive onReceive()}</code>.
+ Carry out any necessary actions depending on the intent that is
+ received. For example, if the broadcast receiver receives a {@link
+ android.net.wifi.p2p.WifiP2pManager#WIFI_P2P_PEERS_CHANGED_ACTION} intent, you can call the
+ {@link android.net.wifi.p2p.WifiP2pManager#requestPeers requestPeers()} method to get a list of
+ the currently discovered peers.</li>
+ </ol>
+
+ <p>The following code shows you how to create a typical broadcast receiver. The broadcast
+ receiver takes a {@link android.net.wifi.p2p.WifiP2pManager} object and an activity as
+ arguments and uses these two classes to appropriately carry out the needed actions when the
+ broadcast receiver receives an intent:</p>
+
+<pre>
+/**
+ * A BroadcastReceiver that notifies of important Wi-Fi p2p events.
+ */
+public class WiFiDirectBroadcastReceiver extends BroadcastReceiver {
+
+ private WifiP2pManager manager;
+ private Channel channel;
+ private MyWiFiActivity activity;
+
+ public WiFiDirectBroadcastReceiver(WifiP2pManager manager, Channel channel,
+ MyWifiActivity activity) {
+ super();
+ this.manager = manager;
+ this.channel = channel;
+ this.activity = activity;
+ }
+
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ String action = intent.getAction();
+
+ if (WifiP2pManager.WIFI_P2P_STATE_CHANGED_ACTION.equals(action)) {
+ // Check to see if Wi-Fi is enabled and notify appropriate activity
+ } else if (WifiP2pManager.WIFI_P2P_PEERS_CHANGED_ACTION.equals(action)) {
+ // Call WifiP2pManager.requestPeers() to get a list of current peers
+ } else if (WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION.equals(action)) {
+ // Respond to new connection or disconnections
+ } else if (WifiP2pManager.WIFI_P2P_THIS_DEVICE_CHANGED_ACTION.equals(action)) {
+ // Respond to this device's wifi state changing
+ }
+ }
+}
+</pre>
+
+ <h2 id="creating-app">Creating a Wi-Fi Direct Application</h2>
+
+ <p>Creating a Wi-Fi Direct application involves creating and registering a
+ broadcast receiver for your application, discovering peers, connecting to a peer, and
+ transferring data to a peer. The following sections describe how to do this.</p>
+
+ <h3 id="setup">Initial setup</h3>
+ <p>Before using the Wi-Fi Direct APIs, you must ensure that your application can access
+ the hardware and that the device supports the Wi-Fi Direct protocol. If Wi-Fi Direct is supported,
+ you can obtain an instance of {@link android.net.wifi.p2p.WifiP2pManager}, create and register
+ your broadcast receiver, and begin using the Wi-Fi Direct APIs.</p>
+ <ol>
+ <li>
+ <p>Request permission to use the Wi-Fi hardware on the device and also declare
+ your application to have the correct minimum SDK version in the Android manifest:</p>
+ <pre>
+<uses-sdk android:minSdkVersion="14" />
+<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
+<uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
+<uses-permission android:name="android.permission.CHANGE_NETWORK_STATE" />
+<uses-permission android:name="android.permission.INTERNET" />
+<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
+</pre>
+ </li>
+
+ <li>Check to see if Wi-Fi Direct is on and supported. A good place to check this is in your
+ broadcast receiver when it receives the {@link
+ android.net.wifi.p2p.WifiP2pManager#WIFI_P2P_STATE_CHANGED_ACTION} intent. Notify your
+ activity of the Wi-Fi Direct state and react accordingly:
+<pre>
+@Override
+public void onReceive(Context context, Intent intent) {
+ ...
+ String action = intent.getAction();
+ if (WifiP2pManager.WIFI_P2P_STATE_CHANGED_ACTION.equals(action)) {
+ int state = intent.getIntExtra(WifiP2pManager.EXTRA_WIFI_STATE, -1);
+ if (state == WifiP2pManager.WIFI_P2P_STATE_ENABLED) {
+ // Wifi Direct is enabled
+ } else {
+ // Wi-Fi Direct is not enabled
+ }
+ }
+ ...
+}
+</pre>
+ </li>
+
+ <li>In your activity's {@link android.app.Activity#onCreate onCreate()} method, obtain an instance of {@link
+ android.net.wifi.p2p.WifiP2pManager} and register your application with the Wi-Fi Direct
+ framework by calling {@link android.net.wifi.p2p.WifiP2pManager#initialize initialize()}. This
+ method returns a {@link android.net.wifi.p2p.WifiP2pManager.Channel}, which is used to connect
+ your application to the Wi-Fi Direct framework. You should also create an instance of your
+ broadcast receiver with the {@link
+ android.net.wifi.p2p.WifiP2pManager} and {@link android.net.wifi.p2p.WifiP2pManager.Channel}
+ objects along with a reference to your activity. This allows your broadcast receiver to notify
+ your activity of interesting events and update it accordingly. It also lets you manipulate the device's
+ Wi-Fi state if necessary:
+<pre>
+WifiP2pManager mManager;
+Channel mChannel;
+BroadcastReceiver mReceiver;
+...
+@Override
+protected void onCreate(Bundle savedInstanceState){
+ ...
+ mManager = (WifiP2pManager) getSystemService(Context.WIFI_P2P_SERVICE);
+ mChannel = mManager.initialize(this, getMainLooper(), null);
+ Receiver = new WiFiDirectBroadcastReceiver(manager, channel, this);
+ ...
+}
+</pre>
+ </li>
+
+ <li>Create an intent filter and add the same intents that your
+ broadcast receiver checks for:
+ <pre>
+IntentFilter mIntentFilter;
+...
+@Override
+protected void onCreate(Bundle savedInstanceState){
+ ...
+ mIntentFilter = new IntentFilter();
+ mIntentFilter.addAction(WifiP2pManager.WIFI_P2P_STATE_CHANGED_ACTION);
+ mIntentFilter.addAction(WifiP2pManager.WIFI_P2P_PEERS_CHANGED_ACTION);
+ mIntentFilter.addAction(WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION);
+ mIntentFilter.addAction(WifiP2pManager.WIFI_P2P_THIS_DEVICE_CHANGED_ACTION);
+ ...
+}
+</pre>
+ </li>
+
+ <li>Register the broadcast receiver in the {@link android.app.Activity#onResume()} method
+ of your activity and unregister it in the {@link android.app.Activity#onPause()} method of your activity:
+ <pre>
+/* register the broadcast receiver with the intent values to be matched */
+@Override
+protected void onResume() {
+ super.onResume();
+ registerReceiver(receiver, intentFilter);
+}
+/* unregister the broadcast receiver */
+@Override
+protected void onPause() {
+ super.onPause();
+ unregisterReceiver(receiver);
+}
+</pre>
+
+ <p>When you have obtained a {@link android.net.wifi.p2p.WifiP2pManager.Channel} and
+ set up a broadcast receiver, your application can make Wi-Fi Direct method calls and receive
+ Wi-Fi Direct intents.</p>
+ </li>
+
+ <p>You can now implement your application and use the Wi-Fi Direct features by calling the
+ methods in {@link android.net.wifi.p2p.WifiP2pManager}. The next sections describe how to do common actions
+ such as discovering and connecting to peers.</p>
+ </ol>
+
+ <h3 id="discovering">Discovering peers</h3>
+
+ <p>To discover peers that are available to connect to, call {@link
+ android.net.wifi.p2p.WifiP2pManager#discoverPeers discoverPeers()} to detect
+ available peers that are in range. The call to this function is asynchronous and a success or
+ failure is communicated to your application with {@link
+ android.net.wifi.p2p.WifiP2pManager.ActionListener#onSuccess onSuccess()} and {@link
+ android.net.wifi.p2p.WifiP2pManager.ActionListener#onFailure onFailure()} if you created a
+ {@link android.net.wifi.p2p.WifiP2pManager.ActionListener}. The
+ {@link android.net.wifi.p2p.WifiP2pManager.ActionListener#onSuccess onSuccess()} method only notifies you
+ that the discovery process succeeded and does not provide any information about the actual peers
+ that it discovered, if any:</p>
+ <pre>
+manager.discoverPeers(channel, new WifiP2pManager.ActionListener() {
+ @Override
+ public void onSuccess() {
+ ...
+ }
+
+ @Override
+ public void onFailure(int reasonCode) {
+ ...
+ }
+});
+
+</pre>
+
+<p>If the discovery process succeeds and detects peers, the system broadcasts the {@link
+ android.net.wifi.p2p.WifiP2pManager#WIFI_P2P_PEERS_CHANGED_ACTION} intent, which you can listen
+ for in a broadcast receiver to obtain a list of peers. When your application receives the {@link
+ android.net.wifi.p2p.WifiP2pManager#WIFI_P2P_PEERS_CHANGED_ACTION} intent, you can request a
+ list of the discovered peers with {@link
+ android.net.wifi.p2p.WifiP2pManager#requestPeers requestPeers()}. The following code shows how to set this up:</p>
+ <pre>
+PeerListListener myPeerListListener;
+...
+if (WifiP2pManager.WIFI_P2P_PEERS_CHANGED_ACTION.equals(action)) {
+
+ // request available peers from the wifi p2p manager. This is an
+ // asynchronous call and the calling activity is notified with a
+ // callback on PeerListListener.onPeersAvailable()
+ if (manager != null) {
+ manager.requestPeers(channel, myPeerListListener);
+ }
+}
+</pre>
+
+ <p>The {@link android.net.wifi.p2p.WifiP2pManager#requestPeers requestPeers()} method is also
+ asynchronous and can notify your activity when a list of peers is available with {@link
+ android.net.wifi.p2p.WifiP2pManager.PeerListListener#onPeersAvailable onPeersAvailable()}, which is defined in the
+ the {@link android.net.wifi.p2p.WifiP2pManager.PeerListListener} interface. The {@link
+ android.net.wifi.p2p.WifiP2pManager.PeerListListener#onPeersAvailable onPeersAvailable()} method
+ provides you with an {@link android.net.wifi.p2p.WifiP2pDeviceList}, which you can iterate
+ through to find the peer that you want to connect to.</p>
+
+ <h3 id="connecting">Connecting to peers</h3>
+
+ <p>When you have figured out the device that you want to connect to after obtaining a list of
+ possible peers, call the {@link android.net.wifi.p2p.WifiP2pManager#connect connect()} method to
+ connect to the device. This method call requires a {@link android.net.wifi.p2p.WifiP2pConfig}
+ object that contains the information of the device to connect to.
+ You can be notified of a connection success or failure through the {@link
+ android.net.wifi.p2p.WifiP2pManager.ActionListener}. The following code
+ shows you how to create a connection to a desired device:</p>
+ <pre>
+//obtain a peer from the WifiP2pDeviceList
+WifiP2pDevice device;
+WifiP2pConfig config = new WifiP2pConfig();
+config.deviceAddress = device.deviceAddress;
+manager.connect(channel, config, new ActionListener() {
+
+ @Override
+ public void onSuccess() {
+ //success logic
+ }
+
+ @Override
+ public void onFailure(int reason) {
+ //failure logic
+ }
+});
+
+</pre>
+
+
+ <h3 id="transferring">Transferring data</h3>
+ <p>Once a connection is established, you can transfer data between the devices with
+ sockets. The basic steps of transferring data are as follows:</p>
+
+ <ol>
+ <li>Create a {@link java.net.ServerSocket}. This socket waits for a connection from a client on a specified
+ port and blocks until it happens, so do this in a background thread.</li>
+
+ <li>Create a client {@link java.net.Socket}. The client uses the IP address and port of
+ the server socket to connect to the server device.</li>
+
+ <li>Send data from the client to the server. When the client
+ socket successfully connects to the server socket, you can send data from the client to the server
+ with byte streams. </li>
+
+ <li>The server socket waits for a client connection (with the {@link java.net.ServerSocket#accept()} method). This
+ call blocks until a client connects, so call this is another thread. When a connection happens, the server device can receive
+ the data from the client. Carry out any actions with this data, such as saving it to a file
+ or presenting it to the user.</li>
+ </ol>
+
+ <p>The following example, modified from the <a href=
+ "{@docRoot}resources/samples/WifiDirectDemo/index.html">Wi-Fi Direct Demo</a> sample, shows you how
+ to create this client-server socket communication and transfer JPEG images from a client
+ to a server with a service. For a complete working example, compile and run the <a href=
+ "{@docRoot}resources/samples/WifiDirectDemo/index.html">Wi-Fi Direct Demo</a> sample.</p>
+<pre>
+public static class FileServerAsyncTask extends AsyncTask<Void, Void, String> {
+
+ private Context context;
+ private TextView statusText;
+
+ public FileServerAsyncTask(Context context, View statusText) {
+ this.context = context;
+ this.statusText = (TextView) statusText;
+ }
+
+ @Override
+ protected String doInBackground(Void... params) {
+ try {
+
+ /**
+ * Create a server socket and wait for client connections. This
+ * call blocks until a connection is accepted from a client
+ */
+ ServerSocket serverSocket = new ServerSocket(8888);
+ Socket client = serverSocket.accept();
+
+ /**
+ * If this code is reached, a client has connected and transferred data
+ * Save the input stream from the client as a JPEG file
+ */
+ final File f = new File(Environment.getExternalStorageDirectory() + "/"
+ + context.getPackageName() + "/wifip2pshared-" + System.currentTimeMillis()
+ + ".jpg");
+
+ File dirs = new File(f.getParent());
+ if (!dirs.exists())
+ dirs.mkdirs();
+ f.createNewFile();
+ InputStream inputstream = client.getInputStream();
+ copyFile(inputstream, new FileOutputStream(f));
+ serverSocket.close();
+ return f.getAbsolutePath();
+ } catch (IOException e) {
+ Log.e(WiFiDirectActivity.TAG, e.getMessage());
+ return null;
+ }
+ }
+
+ /**
+ * Start activity that can handle the JPEG image
+ */
+ @Override
+ protected void onPostExecute(String result) {
+ if (result != null) {
+ statusText.setText("File copied - " + result);
+ Intent intent = new Intent();
+ intent.setAction(android.content.Intent.ACTION_VIEW);
+ intent.setDataAndType(Uri.parse("file://" + result), "image/*");
+ context.startActivity(intent);
+ }
+ }
+}
+</pre>
+
+ <p>On the client, connect to the server socket with a client socket and transfer data. This example
+ transfers a JPEG file on the client device's file system.</p>
+
+<pre>
+Context context = this.getApplicationContext();
+String host;
+int port;
+int len;
+Socket socket = new Socket();
+byte buf[] = new byte[1024];
+...
+try {
+ /**
+ * Create a client socket with the host,
+ * port, and timeout information.
+ */
+ socket.bind(null);
+ socket.connect((new InetSocketAddress(host, port)), 500);
+
+ /**
+ * Create a byte stream from a JPEG file and pipe it to the output stream
+ * of the socket. This data will be retrieved by the server device.
+ */
+ OutputStream outputStream = socket.getOutputStream();
+ ContentResolver cr = context.getContentResolver();
+ InputStream inputStream = null;
+ inputStream = cr.openInputStream(Uri.parse("path/to/picture.jpg"));
+ while ((len = inputStream.read(buf)) != -1) {
+ outputStream.write(buf, 0, len);
+ }
+ outputStream.close();
+ inputStream.close();
+} catch (FileNotFoundException e) {
+ //catch logic
+} catch (IOException e) {
+ //catch logic
+}
+
+/**
+ * Clean up any open sockets when done
+ * transferring or if an exception occurred.
+ */
+finally {
+ if (socket != null) {
+ if (socket.isConnected()) {
+ try {
+ socket.close();
+ } catch (IOException e) {
+ //catch logic
+ }
+ }
+ }
+}
+</pre>
diff --git a/docs/html/images/publishing/publishing_android_market.png b/docs/html/images/publishing/publishing_android_market.png
new file mode 100755
index 0000000..aa591ef
--- /dev/null
+++ b/docs/html/images/publishing/publishing_android_market.png
Binary files differ
diff --git a/docs/html/images/rs_compute.graffle b/docs/html/images/rs_compute.graffle
new file mode 100644
index 0000000..3fa8c67a
--- /dev/null
+++ b/docs/html/images/rs_compute.graffle
@@ -0,0 +1,2445 @@
+<?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.28.0.154505</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-09-19 10:15:24 -0700</string>
+ <key>Creator</key>
+ <string>Robert Ly</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>{{67.75, 299.343}, {157, 40.322}}</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>247</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.628571</string>
+ <key>g</key>
+ <string>0.768599</string>
+ <key>r</key>
+ <string>1</string>
+ </dict>
+ <key>FillType</key>
+ <integer>2</integer>
+ <key>GradientAngle</key>
+ <real>90</real>
+ <key>GradientColor</key>
+ <dict>
+ <key>b</key>
+ <string>0.236788</string>
+ <key>g</key>
+ <string>0.532236</string>
+ <key>r</key>
+ <string>0.990271</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.131021</string>
+ <key>g</key>
+ <string>0.363196</string>
+ <key>r</key>
+ <string>0.725948</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 Renderscript object}</string>
+ <key>VerticalPad</key>
+ <integer>0</integer>
+ </dict>
+ </dict>
+ <dict>
+ <key>Bounds</key>
+ <string>{{67.75, 231.343}, {157, 45.161}}</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>200</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.628571</string>
+ <key>g</key>
+ <string>0.768599</string>
+ <key>r</key>
+ <string>1</string>
+ </dict>
+ <key>FillType</key>
+ <integer>2</integer>
+ <key>GradientAngle</key>
+ <real>90</real>
+ <key>GradientColor</key>
+ <dict>
+ <key>b</key>
+ <string>0.236788</string>
+ <key>g</key>
+ <string>0.532236</string>
+ <key>r</key>
+ <string>0.990271</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.131021</string>
+ <key>g</key>
+ <string>0.363196</string>
+ <key>r</key>
+ <string>0.725948</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 Renderscript context}</string>
+ <key>VerticalPad</key>
+ <integer>0</integer>
+ </dict>
+ </dict>
+ <dict>
+ <key>Class</key>
+ <string>LineGraphic</string>
+ <key>FontInfo</key>
+ <dict>
+ <key>Font</key>
+ <string>DroidSans</string>
+ <key>Size</key>
+ <real>11</real>
+ </dict>
+ <key>Head</key>
+ <dict>
+ <key>ID</key>
+ <integer>247</integer>
+ <key>Info</key>
+ <integer>6</integer>
+ </dict>
+ <key>ID</key>
+ <integer>246</integer>
+ <key>OrthogonalBarAutomatic</key>
+ <false/>
+ <key>OrthogonalBarPoint</key>
+ <string>{0, 0}</string>
+ <key>OrthogonalBarPosition</key>
+ <real>40</real>
+ <key>Points</key>
+ <array>
+ <string>{146.25, 276.504}</string>
+ <string>{146.25, 299.343}</string>
+ </array>
+ <key>Style</key>
+ <dict>
+ <key>stroke</key>
+ <dict>
+ <key>Color</key>
+ <dict>
+ <key>a</key>
+ <string>0.7</string>
+ <key>b</key>
+ <string>0</string>
+ <key>g</key>
+ <string>0</string>
+ <key>r</key>
+ <string>0</string>
+ </dict>
+ <key>CornerRadius</key>
+ <real>4</real>
+ <key>HeadArrow</key>
+ <string>Ball</string>
+ <key>LineType</key>
+ <integer>2</integer>
+ <key>TailArrow</key>
+ <string>0</string>
+ </dict>
+ </dict>
+ <key>Tail</key>
+ <dict>
+ <key>ID</key>
+ <integer>200</integer>
+ <key>Info</key>
+ <integer>5</integer>
+ </dict>
+ </dict>
+ <dict>
+ <key>Class</key>
+ <string>LineGraphic</string>
+ <key>FontInfo</key>
+ <dict>
+ <key>Font</key>
+ <string>DroidSans</string>
+ <key>Size</key>
+ <real>11</real>
+ </dict>
+ <key>Head</key>
+ <dict>
+ <key>ID</key>
+ <integer>251</integer>
+ <key>Info</key>
+ <integer>8</integer>
+ </dict>
+ <key>ID</key>
+ <integer>256</integer>
+ <key>OrthogonalBarAutomatic</key>
+ <false/>
+ <key>OrthogonalBarPoint</key>
+ <string>{0, 0}</string>
+ <key>OrthogonalBarPosition</key>
+ <real>62</real>
+ <key>Points</key>
+ <array>
+ <string>{224.75, 319.504}</string>
+ <string>{339.25, 229.339}</string>
+ </array>
+ <key>Style</key>
+ <dict>
+ <key>stroke</key>
+ <dict>
+ <key>Color</key>
+ <dict>
+ <key>a</key>
+ <string>0.7</string>
+ <key>b</key>
+ <string>0</string>
+ <key>g</key>
+ <string>0</string>
+ <key>r</key>
+ <string>0</string>
+ </dict>
+ <key>CornerRadius</key>
+ <real>4</real>
+ <key>HeadArrow</key>
+ <string>Ball</string>
+ <key>LineType</key>
+ <integer>2</integer>
+ <key>TailArrow</key>
+ <string>0</string>
+ </dict>
+ </dict>
+ <key>Tail</key>
+ <dict>
+ <key>ID</key>
+ <integer>247</integer>
+ <key>Info</key>
+ <integer>7</integer>
+ </dict>
+ </dict>
+ <dict>
+ <key>Bounds</key>
+ <string>{{51.25, 186.67}, {190, 175.33}}</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>235</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 \
+Activity\
+\
+\
+\
+\
+\
+\
+\
+\
+\
+}</string>
+ <key>VerticalPad</key>
+ <integer>0</integer>
+ </dict>
+ </dict>
+ <dict>
+ <key>Bounds</key>
+ <string>{{26.5, 137.831}, {239.5, 238.669}}</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>233</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 \
+\
+\
+\
+Android Framework\
+\
+\
+\
+\
+\
+\
+\
+\
+\
+\
+\
+\
+\
+\
+\
+\
+}</string>
+ <key>VerticalPad</key>
+ <integer>0</integer>
+ </dict>
+ </dict>
+ <dict>
+ <key>Class</key>
+ <string>Group</string>
+ <key>Graphics</key>
+ <array>
+ <dict>
+ <key>Class</key>
+ <string>LineGraphic</string>
+ <key>FontInfo</key>
+ <dict>
+ <key>Font</key>
+ <string>DroidSans</string>
+ <key>Size</key>
+ <real>11</real>
+ </dict>
+ <key>Head</key>
+ <dict>
+ <key>ID</key>
+ <integer>250</integer>
+ </dict>
+ <key>ID</key>
+ <integer>249</integer>
+ <key>OrthogonalBarAutomatic</key>
+ <false/>
+ <key>OrthogonalBarPoint</key>
+ <string>{0, 0}</string>
+ <key>OrthogonalBarPosition</key>
+ <real>4.1290435791015625</real>
+ <key>Points</key>
+ <array>
+ <string>{434.25, 252.366}</string>
+ <string>{434.25, 281.285}</string>
+ </array>
+ <key>Style</key>
+ <dict>
+ <key>stroke</key>
+ <dict>
+ <key>Color</key>
+ <dict>
+ <key>a</key>
+ <string>0.7</string>
+ <key>b</key>
+ <string>0</string>
+ <key>g</key>
+ <string>0</string>
+ <key>r</key>
+ <string>0</string>
+ </dict>
+ <key>CornerRadius</key>
+ <real>4</real>
+ <key>HeadArrow</key>
+ <string>FilledArrow</string>
+ <key>LineType</key>
+ <integer>2</integer>
+ <key>TailArrow</key>
+ <string>0</string>
+ </dict>
+ </dict>
+ <key>Tail</key>
+ <dict>
+ <key>ID</key>
+ <integer>251</integer>
+ <key>Info</key>
+ <integer>5</integer>
+ </dict>
+ </dict>
+ <dict>
+ <key>Bounds</key>
+ <string>{{339.25, 281.285}, {190, 46.0537}}</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>250</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.274119</string>
+ <key>g</key>
+ <string>0.950739</string>
+ <key>r</key>
+ <string>0.787494</string>
+ </dict>
+ <key>FillType</key>
+ <integer>2</integer>
+ <key>GradientAngle</key>
+ <real>90</real>
+ <key>GradientColor</key>
+ <dict>
+ <key>b</key>
+ <string>0.223529</string>
+ <key>g</key>
+ <string>0.776471</string>
+ <key>r</key>
+ <string>0.643137</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.165602</string>
+ <key>g</key>
+ <string>0.586124</string>
+ <key>r</key>
+ <string>0.428309</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 Renderscript Compute Engine}</string>
+ <key>VerticalPad</key>
+ <integer>0</integer>
+ </dict>
+ </dict>
+ <dict>
+ <key>Bounds</key>
+ <string>{{339.25, 206.312}, {190, 46.0537}}</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>251</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 Compute Renderscript (.rs)}</string>
+ <key>VerticalPad</key>
+ <integer>0</integer>
+ </dict>
+ </dict>
+ <dict>
+ <key>Bounds</key>
+ <string>{{314.5, 168.835}, {239.5, 175.33}}</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>252</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 \
+\
+\
+Renderscript Runtime\
+\
+\
+\
+\
+\
+\
+\
+\
+\
+\
+\
+\
+}</string>
+ <key>VerticalPad</key>
+ <integer>0</integer>
+ </dict>
+ </dict>
+ </array>
+ <key>ID</key>
+ <integer>248</integer>
+ </dict>
+ </array>
+ <key>GridInfo</key>
+ <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-11-07 11:10:03 -0800</string>
+ <key>Modifier</key>
+ <string>Robert Ly</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>coded</string>
+ <string>BAtzdHJlYW10eXBlZIHoA4QBQISEhAdOU1ZhbHVlAISECE5TT2JqZWN0AIWEASqEhAx7X05TU2l6ZT1mZn2WgWQCgRgDhg==</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>
+ JVBERi0xLjMKJcTl8uXrp/Og0MTGCjUgMCBvYmoKPDwgL0xlbmd0aCA2IDAgUiAvRmls
+ dGVyIC9GbGF0ZURlY29kZSA+PgpzdHJlYW0KeAHFWstyHbkN3fMruJQWbjff3cuJM5OK
+ V0mkqllksphcy2M7ku2RNHn8fQ5AAOy+0pWlTWKVSw00CJLA4SHI1q/+z/5XP+OntOpb
+ Sv72yv/oP/vXb+6CP9z5wD93B/9qnoqn/xvD9/71n65uD1df73/7+drdfoSrWAK7i7n4
+ NK9TmOPiU4nTsrboDzf+9R9vgv/9F+43zt24NJ9SmpYC29zyNOPJddv4lG1a0UGI6nfY
+ yiBSKD4GGkPDIEKbYlK/6dhvWJrPhcZAtjVNLdqAsxqHuvRgVV/jhGnBNpd5mktWx+WB
+ bRy2aalsK4Go3ZZSQKNDbGueQi3uxhdMQSR/DSlOtdTVVKVkPCOqMUDJAuZZiz+wlNYw
+ Lan4a0fv0jpPoS1wqG7SsvB76kWfDzIGla8hIx45mYlLIWOQ5k7F3he176+7/JR0EFel
+ 9lFTX9TWpmRdawx28cEsP8hoR8QItfDC80mYe8yE1tDqtEH1gKtnuHb8vQo+pzzFAvTV
+ qTD0Lj4Ef/cBMD2xQIJ/i6XxqS+UNxdYGrmlOVV5WDM/xHVt7uINEmw9zbzMgO4+JUCK
+ U9FTrtIm5apCJl1olsmMqWngOclZQ9klw4YgJ2WGFjCAfPZnZymXd9uUi0qymMWdigq2
+ naz4kJHs3iFlXdZRa8ptSpZymTC80ZLQ6Y+Uq+bGXyA5ICqs/zssS5DUJszHCf3dpQ+R
+ F+8r/H6FtVNbawlP1V+Cln4I04wkXb73f/Vnfzknvov+7EofPp8jn1C8O3f7F7dqcacP
+ B32wVx+l8Vf5fe/5wY1+fpM32s29NrlRZxjJ3/zlW//9pWAyISdAbIl1qstClIGnoSDW
+ iG1aZ2KNboPfa7coEyCwDDmRC+IONnB5gSLlxD64SV7CtLYG0lGfeZm7jXRrMhLdR6Ya
+ h1TTWlzBJKoD3+/9miw9w4taiKbLY2zH761FiX066La7KFHma8PQoO1j2GllF1Z/w7th
+ SsvUwA6Yc6C4hBVTaaDy1ALvmA475re4pcwYVw3YVgG3iw/xFL04YrKH9IIdcgGZE8/E
+ OgPK05oKoHyKXXgeLs7gP1gZPFSxgYeqBB5xbthsSlR4RGzjcAG2UIMMRcWmTT44jdj1
+ pznGOuARsdWwjcDDZIWHM80GHqaTzJlflbVnS3YUjTu2OJZHiz4dDF5NdL4KDwuawEPj
+ wxTU4aGqZ3GQJp72lSMaagg101B+SEJvdOl/EXIwLvgqJKSscW801YnlaQLrRGZNbs9d
+ 57qXE5g/++lsksEJ2bkzc/PT+QnKykBLQ2lmmFTFBpOicgIwKrKw1ojKOm9kLEi4MEzm
+ eaHFtaUspHWe86Asl+fSbZSyVFZMerPYYNJ0ApcsfhVx1rMhzDTWQsZ2LGsLBzLm6Rgm
+ bb6KSZSZPWhKriJuMKkh21MW5hgoLg8oi4r8b1FWjhj5sgSpiNIpymKSfEhZaI4zAPBW
+ lhoicRdKVHDXyYpIFhc2m7hs8BFFscGHqBQfccF+Dp3iIy4o5+DC8JFiRh2IGt84K2FX
+ WNcyOMsl7G1sI/gw2fBhmg0+TCfZVb+KD+tZs+1NYy1kbMeytnA6HcOHzdfwoTFSzpKQ
+ bfChIXsWZ2nmabM64iycYbAH0nboXlQ4PeAdqbGEMNzZswsnf/YUN1I/7uw0N36vRdYv
+ Ql1aa6l+V2rNjk7H2GRf/wEn4l/utjWmlfJSbNr2daPniYgDXexbZbdxsWLzBDKvzQRl
+ fFdIOcvnbuqUS1p0G6lbrWcLigjmTqQAxZzLOEKRgvxh2SArpvjwsNF7OH2L/58em4bT
+ abQ+RJoF9eGjDVH6GArrI1ojTMPRoQlMjfJ0Jf5ZaTHHmoZ4DTHLmVZNIkpxVIk41NaM
+ 1yREbozSg8RUyCO1pOfWz6bmJhUc3fAu4R09oQ2ZdwGNun1xasfvzAlLZE9dmfD4I5vk
+ Ff+cjpBHNbFuM4XuHTuQzXA1GwkLrU8aJzxZoKj+Qy2FgcohNqKOrRREvZw5ydsh8xkg
+ N5zcU27C2/mlvP3CkywHOgAroHvNtImbTJsOGXQBkwoNB2ZKZ8ABgRtLpltCDiTTmEug
+ u4+RaTqkQ0Sm+3FdMs3qken+FnaUzuGEJXKvmea+xAp6rNC9Sc+qjZBGJVkcU9BMjxlK
+ pjFNCYtm2pvmaSI+SiWI2IGIcdc0o/i/POxOswB8bTjQvcIGt+fks+8+v7v98vGd/+H2
+ 55urf325/ce5v/zk7BRZ+NqjADa4JcEaxUGHzpBdxlSRpH6E7JqIsz2/z9O6UE5YdiUn
+ ao+I9vcJJ0U0VgFHAbpGMmd0apKe6BGbNI8Czzgr4uBAR0XKGbZz7i418aBipjbyCsvr
+ kaeDIy2lDs55cPA8NDJ86Qsu+vRoHNKGA9JHRhpMkTXHFscyZbnPxmJKyxnlKzbMhOsb
+ 3Gjg8Nivpdyz13OhChKQ5ZNjeXQ5q7OHZdgLT448fBewzdc2ICHyBhKikSwHXCnOgbLc
+ sx4WcFYzSIB21w0kKi4PeE0rvlKNBgk8GiTwvIUERM62S+pBkg/vBgk8D+146u85vTK4
+ AQlMV4ZvkJDpWYJFHpDwj1sAKQIia6GQEMXz1n1P+SNnRtxo15YWXF1hovvVjqur7/TU
+ aNWU3CW5s3/qKy147v+zPaH1kuMblU5EHd2wiQbsWXNmeCRiBFUAH7h7PlKkKReAXm0i
+ tjq2aDj0pOBMLuwTLNINIr4JoB5n3KgGF49xbbDA4S7jbBGx97ANblrh1JlMXvrdxN7i
+ uMWQqdrmZao+6OIqRVq4qgEWqUh7ooZCCxRoETwcUY5luqjBTS+85AJ2i+ggLgv2dtHA
+ 84Lqj4Jj7VCpxIBOaTx5WuY5wQrfDTI1w6LElbIqcMbA7oIgQrFptcI4UmzMt2pG/9pO
+ Rkl3weYcg6u4fd30PzTHsztwRJR0NhewXBwTfGUji7Q9M2RUsRQ6oCOmqsB3Cnxv2Cpw
+ 7cwKqimfinqg62qOOurHhvAh6gGfcxJtlhFlZCn41hRwZxfWdQHiTIMQcfy0HTZWXCnh
+ ew7ityL8K/a1jaZObcVXqoADO7WDJ9yxVoyR2nXvDLxAfLcZAWqdrrFxbtrFaWV0rOa9
+ a7YjsHYyvx53qrOxqQAtmB8olQkbBIElqgqsSFyIZr4HFpu+iNEElyqoYWBAi9rnFbsM
+ XGDpiAIFd14r1oEpqJgBWs1lRukBEyioU9xSdPEgo1L52uPYM9O27lRVsfqpgXhUkXvE
+ EPbyExKQK29l+OiLXdv0tGuL0T5itGWzxkLWb1DgBSyVC10ToEIt+NRX6S4FQHr2vo1D
+ 0dzwQa9v3PXRjVu96RriT6/8RanFsqKqQ5awHDEGun3Gx8wwn7pA6RMj5qFbapRzPSuq
+ 2EBBVT2xICYseVzSaKIjmIdcGBQiVcm8WAUKkSrqygws6JIFDgpmKOh6VyioPKCAM1mn
+ hJ4v86gi92jp1RHs3kqq9Z1CQYevUNDpOYOCzn8fMYMCs3ePoZzKH/3IZDX6SPPRZQnK
+ lBlWwNHDrfp/9ZXJKgG9SNaLjnFv/G8tDe63FcFgl0y7U2n4yqQLvSvA1YMKRKVcAUjt
+ 2AV7z5ZdXALd0YdaY5cEvq30ndpcJrAyf8vtkFJRISUy+MnyqiYdJeZRxd6jwkRHsHvr
+ dtJgIhm+Qirr9KxriZEyn0RsQErfb9klYSOiD/XMLli1MWK/OsEuzj4hK+wCVh5ooZNL
+ ewm54CPmSXI59UVJlgqqqi25YAfsig0SVCVIwCa8I5c083FukAtXHmDJgQQcQxP9acNA
+ Al+BUCXG5EI3pXwgkmirPJDA169kIulUjyqikOI/l9jLT0hGRDp8RYJNz5Cg899HzJBg
+ IXveQWBk+YhbsNemXPEnKf/Hi1illL/LXeon+S2flzaXuntm+S+c9lyDCmVuZHN0cmVh
+ bQplbmRvYmoKNiAwIG9iagoyOTIyCmVuZG9iagozIDAgb2JqCjw8IC9UeXBlIC9QYWdl
+ IC9QYXJlbnQgNCAwIFIgL1Jlc291cmNlcyA3IDAgUiAvQ29udGVudHMgNSAwIFIgL01l
+ ZGlhQm94IFswIDAgNTc2IDczM10KPj4KZW5kb2JqCjcgMCBvYmoKPDwgL1Byb2NTZXQg
+ WyAvUERGIC9UZXh0IC9JbWFnZUIgL0ltYWdlQyAvSW1hZ2VJIF0gL0NvbG9yU3BhY2Ug
+ PDwgL0NzMiAyMiAwIFIKL0NzMSA4IDAgUiA+PiAvRXh0R1N0YXRlIDw8IC9HczIgMzAg
+ MCBSIC9HczEgMzEgMCBSID4+IC9Gb250IDw8IC9GMS4wIDIzIDAgUgo+PiAvWE9iamVj
+ dCA8PCAvSW0xIDkgMCBSIC9JbTQgMTUgMCBSIC9JbTUgMTcgMCBSIC9JbTMgMTMgMCBS
+ IC9JbTIgMTEgMCBSCi9JbTYgMTkgMCBSID4+IC9TaGFkaW5nIDw8IC9TaDUgMjcgMCBS
+ IC9TaDYgMjggMCBSIC9TaDQgMjYgMCBSIC9TaDMgMjUgMCBSCi9TaDcgMjkgMCBSIC9T
+ aDIgMjQgMCBSIC9TaDEgMjEgMCBSID4+ID4+CmVuZG9iagoyNyAwIG9iago8PCAvQ29s
+ b3JTcGFjZSAzMiAwIFIgL1NoYWRpbmdUeXBlIDIgL0Nvb3JkcyBbIDk1LjUgLTg4LjE2
+ NSA5NS40OTk5OCA4OC4xNjUwNApdIC9Eb21haW4gWyAwIDEgXSAvRXh0ZW5kIFsgZmFs
+ c2UgZmFsc2UgXSAvRnVuY3Rpb24gMzMgMCBSID4+CmVuZG9iagoyOCAwIG9iago8PCAv
+ Q29sb3JTcGFjZSAzMiAwIFIgL1NoYWRpbmdUeXBlIDIgL0Nvb3JkcyBbIDc5IC0yMy4w
+ ODA1MSA3OSAyMy4wODA1NCBdCi9Eb21haW4gWyAwIDEgXSAvRXh0ZW5kIFsgZmFsc2Ug
+ ZmFsc2UgXSAvRnVuY3Rpb24gMzQgMCBSID4+CmVuZG9iagoyNiAwIG9iago8PCAvQ29s
+ b3JTcGFjZSAzMiAwIFIgL1NoYWRpbmdUeXBlIDIgL0Nvb3JkcyBbIDEyMC4yNSAtMTE5
+ LjgzNDcgMTIwLjI1IDExOS44MzQ4Cl0gL0RvbWFpbiBbIDAgMSBdIC9FeHRlbmQgWyBm
+ YWxzZSBmYWxzZSBdIC9GdW5jdGlvbiAzNSAwIFIgPj4KZW5kb2JqCjI1IDAgb2JqCjw8
+ IC9Db2xvclNwYWNlIDMyIDAgUiAvU2hhZGluZ1R5cGUgMiAvQ29vcmRzIFsgOTUuNSAt
+ MjMuNTI2ODUgOTUuNDk5OTggMjMuNTI2ODkKXSAvRG9tYWluIFsgMCAxIF0gL0V4dGVu
+ ZCBbIGZhbHNlIGZhbHNlIF0gL0Z1bmN0aW9uIDM2IDAgUiA+PgplbmRvYmoKMjkgMCBv
+ YmoKPDwgL0NvbG9yU3BhY2UgMzIgMCBSIC9TaGFkaW5nVHlwZSAyIC9Db29yZHMgWyA3
+ OSAtMjAuNjYxMDEgNzkgMjAuNjYxMDQgXQovRG9tYWluIFsgMCAxIF0gL0V4dGVuZCBb
+ IGZhbHNlIGZhbHNlIF0gL0Z1bmN0aW9uIDM3IDAgUiA+PgplbmRvYmoKMjQgMCBvYmoK
+ PDwgL0NvbG9yU3BhY2UgMzIgMCBSIC9TaGFkaW5nVHlwZSAyIC9Db29yZHMgWyA5NS41
+ IC0yMy41MjY4NSA5NS40OTk5OCAyMy41MjY4OQpdIC9Eb21haW4gWyAwIDEgXSAvRXh0
+ ZW5kIFsgZmFsc2UgZmFsc2UgXSAvRnVuY3Rpb24gMzggMCBSID4+CmVuZG9iagoyMSAw
+ IG9iago8PCAvQ29sb3JTcGFjZSAzMiAwIFIgL1NoYWRpbmdUeXBlIDIgL0Nvb3JkcyBb
+ IDEyMC4yNSAtODguMTY1IDEyMC4yNSA4OC4xNjUwNQpdIC9Eb21haW4gWyAwIDEgXSAv
+ RXh0ZW5kIFsgZmFsc2UgZmFsc2UgXSAvRnVuY3Rpb24gMzkgMCBSID4+CmVuZG9iago5
+ IDAgb2JqCjw8IC9MZW5ndGggMTAgMCBSIC9UeXBlIC9YT2JqZWN0IC9TdWJ0eXBlIC9J
+ bWFnZSAvV2lkdGggNTAyIC9IZWlnaHQgNDkwIC9JbnRlcnBvbGF0ZQp0cnVlIC9Db2xv
+ clNwYWNlIDQwIDAgUiAvSW50ZW50IC9QZXJjZXB0dWFsIC9TTWFzayA0MSAwIFIgL0Jp
+ dHNQZXJDb21wb25lbnQKOCAvRmlsdGVyIC9GbGF0ZURlY29kZSA+PgpzdHJlYW0KeAHt
+ 0DEBAAAAwqD1T20Hb4hAYcCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgw
+ YMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMG
+ DBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCA
+ AQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgw
+ YMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMG
+ DBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCA
+ AQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgw
+ YMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMG
+ DBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCA
+ AQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgw
+ YMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMG
+ DBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCA
+ AQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgw
+ YMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMG
+ DBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCA
+ AQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgw
+ YMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMG
+ DBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCA
+ AQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgw
+ YMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMG
+ DBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCA
+ AQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgw
+ YMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMG
+ DBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCA
+ AQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgw
+ YMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMG
+ DBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCA
+ AQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgw
+ YMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMG
+ DBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCA
+ AQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgw
+ YMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMG
+ DBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCA
+ AQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgw
+ YMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMG
+ DBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCA
+ AQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgw
+ YMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMG
+ DBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCA
+ AQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgw
+ YMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMG
+ DBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCA
+ AQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgw
+ YMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMG
+ DBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCA
+ AQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgw
+ YMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMG
+ DBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCA
+ AQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgw
+ YMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMG
+ DBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCA
+ AQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgw
+ YMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMG
+ DBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCA
+ AQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgw
+ YMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMG
+ DBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCA
+ AQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgw
+ YMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMG
+ DBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCA
+ AQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgw
+ YMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMG
+ DBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCA
+ AQMGDBgwYMCAAQMGDBgwYMCAgX9gQzkAAQplbmRzdHJlYW0KZW5kb2JqCjEwIDAgb2Jq
+ CjMyNDEKZW5kb2JqCjE1IDAgb2JqCjw8IC9MZW5ndGggMTYgMCBSIC9UeXBlIC9YT2Jq
+ ZWN0IC9TdWJ0eXBlIC9JbWFnZSAvV2lkdGggNDAyIC9IZWlnaHQgMzc0IC9JbnRlcnBv
+ bGF0ZQp0cnVlIC9Db2xvclNwYWNlIDQwIDAgUiAvSW50ZW50IC9QZXJjZXB0dWFsIC9T
+ TWFzayA0MyAwIFIgL0JpdHNQZXJDb21wb25lbnQKOCAvRmlsdGVyIC9GbGF0ZURlY29k
+ ZSA+PgpzdHJlYW0KeAHt0DEBAAAAwqD1T20Hb4hAYcCAAQMGDBgwYMCAAQMGDBgwYMCA
+ AQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgw
+ YMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMG
+ DBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCA
+ AQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgw
+ YMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMG
+ DBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCA
+ AQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgw
+ YMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMG
+ DBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCA
+ AQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgw
+ YMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMG
+ DBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCA
+ AQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgw
+ YMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMG
+ DBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCA
+ AQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgw
+ YMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMG
+ DBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCA
+ AQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgw
+ YMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMG
+ DBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCA
+ AQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgw
+ YMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMG
+ DBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCA
+ AQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgw
+ YMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMG
+ DBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCA
+ AQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgw
+ YMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMG
+ DBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCA
+ AQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgw
+ YMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMG
+ DBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCA
+ AQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgw
+ YMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMG
+ DBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCA
+ AQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgw
+ YMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMG
+ DBgwYMCAgX9g4j4AAQplbmRzdHJlYW0KZW5kb2JqCjE2IDAgb2JqCjE5OTAKZW5kb2Jq
+ CjE3IDAgb2JqCjw8IC9MZW5ndGggMTggMCBSIC9UeXBlIC9YT2JqZWN0IC9TdWJ0eXBl
+ IC9JbWFnZSAvV2lkdGggMzM2IC9IZWlnaHQgMTEyIC9JbnRlcnBvbGF0ZQp0cnVlIC9D
+ b2xvclNwYWNlIDQwIDAgUiAvSW50ZW50IC9QZXJjZXB0dWFsIC9TTWFzayA0NSAwIFIg
+ L0JpdHNQZXJDb21wb25lbnQKOCAvRmlsdGVyIC9GbGF0ZURlY29kZSA+PgpzdHJlYW0K
+ eAHt0DEBAAAAwqD1T20ND4hAYcCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMG
+ DBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCA
+ AQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgw
+ YMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMG
+ DBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCA
+ AQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgw
+ YMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMG
+ DBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCA
+ AQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgw
+ YMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQOP
+ AwO5DwABCmVuZHN0cmVhbQplbmRvYmoKMTggMCBvYmoKNTE2CmVuZG9iagoxMyAwIG9i
+ ago8PCAvTGVuZ3RoIDE0IDAgUiAvVHlwZSAvWE9iamVjdCAvU3VidHlwZSAvSW1hZ2Ug
+ L1dpZHRoIDUwMiAvSGVpZ2h0IDYzMCAvSW50ZXJwb2xhdGUKdHJ1ZSAvQ29sb3JTcGFj
+ ZSA0MCAwIFIgL0ludGVudCAvUGVyY2VwdHVhbCAvU01hc2sgNDcgMCBSIC9CaXRzUGVy
+ Q29tcG9uZW50CjggL0ZpbHRlciAvRmxhdGVEZWNvZGUgPj4Kc3RyZWFtCngB7dAxAQAA
+ AMKg9U9tCy+IQGHAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAED
+ BgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDA
+ gAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwY
+ MGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAED
+ BgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDA
+ gAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwY
+ MGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAED
+ BgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDA
+ gAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwY
+ MGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAED
+ BgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDA
+ gAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwY
+ MGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAED
+ BgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDA
+ gAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwY
+ MGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAED
+ BgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDA
+ gAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwY
+ MGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAED
+ BgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDA
+ gAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwY
+ MGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAED
+ BgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDA
+ gAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwY
+ MGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAED
+ BgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDA
+ gAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwY
+ MGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAED
+ BgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDA
+ gAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwY
+ MGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAED
+ BgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDA
+ gAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwY
+ MGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAED
+ BgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDA
+ gAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwY
+ MGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAED
+ BgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDA
+ gAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwY
+ MGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAED
+ BgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDA
+ gAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwY
+ MGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAED
+ BgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDA
+ gAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwY
+ MGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAED
+ BgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDA
+ gAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwY
+ MGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAED
+ BgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDA
+ gAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwY
+ MGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAED
+ BgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDA
+ gAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwY
+ MGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAED
+ BgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDA
+ gAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwY
+ MGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAED
+ BgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDA
+ gAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwY
+ MGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAED
+ BgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDA
+ gAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwY
+ MGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAED
+ BgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDA
+ gAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwY
+ MGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAED
+ BgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDA
+ gAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwY
+ MGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAED
+ BgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDA
+ gAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwY
+ MGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAED
+ BgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDA
+ gAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwY
+ MGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAED
+ BgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDA
+ gAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwY
+ MGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAED
+ BgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDA
+ gAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwY
+ MGDAgAEDBgwYMGDAgAED74EBev4AAQplbmRzdHJlYW0KZW5kb2JqCjE0IDAgb2JqCjQx
+ NjEKZW5kb2JqCjExIDAgb2JqCjw8IC9MZW5ndGggMTIgMCBSIC9UeXBlIC9YT2JqZWN0
+ IC9TdWJ0eXBlIC9JbWFnZSAvV2lkdGggNDAyIC9IZWlnaHQgMTE0IC9JbnRlcnBvbGF0
+ ZQp0cnVlIC9Db2xvclNwYWNlIDQwIDAgUiAvSW50ZW50IC9QZXJjZXB0dWFsIC9TTWFz
+ ayA0OSAwIFIgL0JpdHNQZXJDb21wb25lbnQKOCAvRmlsdGVyIC9GbGF0ZURlY29kZSA+
+ PgpzdHJlYW0KeAHt0AENAAAAwqD3T20PBxEoDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCA
+ AQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgw
+ YMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMG
+ DBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCA
+ AQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgw
+ YMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMG
+ DBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCA
+ AQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgw
+ YMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMG
+ DBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCA
+ AQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgw
+ YMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMG
+ DBgwYMCAAQMGDBgw8D8wGSoAAQplbmRzdHJlYW0KZW5kb2JqCjEyIDAgb2JqCjYyMgpl
+ bmRvYmoKMTkgMCBvYmoKPDwgL0xlbmd0aCAyMCAwIFIgL1R5cGUgL1hPYmplY3QgL1N1
+ YnR5cGUgL0ltYWdlIC9XaWR0aCAzMzYgL0hlaWdodCAxMDQgL0ludGVycG9sYXRlCnRy
+ dWUgL0NvbG9yU3BhY2UgNDAgMCBSIC9JbnRlbnQgL1BlcmNlcHR1YWwgL1NNYXNrIDUx
+ IDAgUiAvQml0c1BlckNvbXBvbmVudAo4IC9GaWx0ZXIgL0ZsYXRlRGVjb2RlID4+CnN0
+ cmVhbQp4Ae3QMQEAAADCoPVPbQlPiEBhwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBg
+ wIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYM
+ GDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIAB
+ AwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBg
+ wIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYM
+ GDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIAB
+ AwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBg
+ wIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYM
+ GDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIAB
+ AwYMGDBgwIABAwYMGDBgwIABAwb+AwOZjwABCmVuZHN0cmVhbQplbmRvYmoKMjAgMCBv
+ YmoKNDgxCmVuZG9iago0MSAwIG9iago8PCAvTGVuZ3RoIDQyIDAgUiAvVHlwZSAvWE9i
+ amVjdCAvU3VidHlwZSAvSW1hZ2UgL1dpZHRoIDUwMiAvSGVpZ2h0IDQ5MCAvQ29sb3JT
+ cGFjZQovRGV2aWNlR3JheSAvSW50ZXJwb2xhdGUgdHJ1ZSAvQml0c1BlckNvbXBvbmVu
+ dCA4IC9GaWx0ZXIgL0ZsYXRlRGVjb2RlID4+CnN0cmVhbQp4Ae3YWVeTZx9GcTKTEGYZ
+ DVpBi1WDVZGiAhWlMs+Q0O//Rd7Qd7Wrwauetmu776P2f3btHw/aDgz4LGABC1jAAhaw
+ gAUsYAELWMACFrCABSxgAQtYwAIWsIAFLGABC1jAAhawgAUsYAELWMACFrCABSxgAQtY
+ wAIWsIAFLGABC1jAAhawgAUsYAELWMACFrCABSxgAQtYwAIWsIAFLGABC1jAAhawgAUs
+ YAELWMACFrCABSxgAQtYwAIWsIAFLGABC1jAAhawgAUsYAELWMACFrCABSxgAQtYwAIW
+ sIAFLGABC/xHCxR8uALf/lErFEvlcsUHK1AulYqFf5IvlMrVwcbQUNOHKjDUqNcq5exe
+ KJZrjeGxyXtT0z5SgampexOjzXqlFD73Hvrg8MRM6+GjpaXHPlCBpcVHD+anxoaqgb1Y
+ ro9OLzx+9vL1m9XVtz5MgdXVN6/aTxfnJ5u1r9gL5cGRmUfPXr/b/Lj9yYcqsP3rxtrL
+ Hxcmh6rFO3+lK1abUz+8WNva2Ts4PPKRChweHux++vB6+f54vdz/R3uhVB9v/fT2193j
+ s4uLSx+pwMXF+enhzoefl2aG73zshcrQ1OKrzd2Ty+tOp+sjFeh0Olfnh5/Xn7fG66W+
+ X/HF6sjs8tqno4tO9+bm5ncfqEAPtHt9trf186N7jf5f8cXa6P3n77+cXN2iqw4y703p
+ iXYuDrdXH083K31/sJcGx1vtjd2za8lZ4rdrbj/2y+PPaz/2/mDvV69PLKxs7ffUeaNd
+ 9PtN9+p4Z3159mv1By+39s9VZ/6MdK9Ofnv3dG7kq2/9/+rM0d/9qm+rd777PswAf6n3
+ /d+5Un3ij29dddWZBb7HVX7rqv/5P+j8Dc/+WfBbZ/vmdarnLuyr6mzfvE713IV9VZ3t
+ m9epnruwr6qzffM61XMX9lV1tm9ep3ruwr6qzvbN61TPXdhX1dm+eZ3quQv7qjrbN69T
+ PXdhX1Vn++Z1qucu7KvqbN+8TvXchX1Vne2b16meu7CvqrN98zrVcxf2VXW2b16neu7C
+ vqrO9s3rVM9d2FfV2b55neq5C/uqOts3r1M9d2FfVWf75nWq5y7sq+ps37xO9dyFfVWd
+ 7ZvXqZ67sK+qs33zOtVzF/ZVdbZvXqd67sK+qs72zetUz13YV9XZvnmd6rkL+6o62zev
+ Uz13YV9VZ/vmdarnLuyr6mzfvE713IV9VZ3tm9epnruwr6qzffM61XMX9lV1tm9ep3ru
+ wr6qzvbN61TPXdhX1dm+eZ3quQv7qjrbN69TPXdhX1Vn++Z1qucu7KvqbN+8TvXchX1V
+ ne2b16meu7CvqrN98zrVcxf2VXW2b16neu7CvqrO9s3rVM9d2FfV2b55neq5C/uqOts3
+ r1M9d2FfVWf75nWq5y7sq+ps37xO9dyFfVWd7ZvXqZ67sK+qs33zOtVzF/ZVdbZvXqd6
+ 7sK+qs72zetUz13YV9XZvnmd6rkL+6o62zevUz13YV9VZ/vmdarnLuyr6mzfvE713IV9
+ VZ3tm9epnruwr6qzffM61XMX9lV1tm9ep3ruwr6qzvbN61TPXdhX1dm+eZ3quQv7qjrb
+ N69TPXdhX1Vn++Z1qucu7KvqbN+8TvXchX1Vne2b16meu7CvqrN98zrVcxf2VXW2b16n
+ eu7CvqrO9s3rVM9d2FfV2b55neq5C/uqOts3r1M9d2FfVWf75nWq5y7sq+ps37xO9dyF
+ fVWd7ZvXqZ67sK+qs33zOtVzF/ZVdbZvXqd67sK+qs72zetUz13YV9XZvnmd6rkL+6o6
+ 2zevUz13YV9VZ/vmdarnLuyr6mzfvE713IV9VZ3tm9epnruwr6qzffM61XMX9lV1tm9e
+ p3ruwr6qzvbN61TPXdhX1dm+eZ3quQv7qjrbN69TPXdhX1Vn++Z1qucu7KvqbN+8TvXc
+ hX1Vne2b16meu7CvqrN98zrVcxf2VXW2b16neu7CvqrO9s3rVM9d2FfV2b55neq5C/uq
+ Ots3r1M9d2FfVWf75nWq5y7sq+ps37xO9dyFfVWd7ZvXqZ67sK+qs33zOtVzF/ZVdbZv
+ Xqd67sK+qs72zetUz13YV9XZvnmd6rkL+6o62zevUz13YV9VZ/vmdarnLuyr6mzfvE71
+ 3IV9VZ3tm9epnruwr6qzffM61XMX9lV1tm9ep3ruwr6qzvbN61TPXdhX1dm+eZ3quQv7
+ qjrbN69TPXdhX1Vn++Z1qucu7KvqbN+8TvXchX1Vne2b16meu7CvqrN98zrVcxf2VXW2
+ b16neu7CvqrO9s3rVM9d2FfV2b55neq5C/uqOts3r1M9d2FfVWf75nWq5y7sq+ps37xO
+ 9dyFfVWd7ZvXqZ67sK+qs33zOtVzF/ZVdbZvXqd67sK+qs72zetUz13YV9XZvnmd6rkL
+ +6o62zevUz13YV9VZ/vmdarnLuyr6mzfvE713IV9VZ3tm9epnruwr6qzffM61XMX9lV1
+ tm9ep3ruwr6qzvbN61TPXdhX1dm+eZ3quQv7qjrbN69TPXdhX1Vn++Z1qucu7KvqbN+8
+ TvXchX1Vne2b16meu7CvqrN98zrVcxf2VXW2b16neu7CvqrO9s3rVM9d2FfV2b55neq5
+ C/uqOts3r1M9d2FfVWf75nWq5y7sq+ps37xO9dyFfVWd7ZvXqZ67sK+qs33zOtVzF/ZV
+ dbZvXqd67sK+qs72zetUz13YV9XZvnmd6rkL+6o62zevUz13YV9VZ/vmdarnLuyr6mzf
+ vE713IV9VZ3tm9epnruwr6qzffM61XMX9lV1tm9ep3ruwr6qzvbN61TPXdhX1dm+eZ3q
+ uQv7qjrbN69TPXdhX1Vn++Z1qucu7KvqbN+8TvXchX1Vne2b16meu7CvqrN98zrVcxf2
+ VXW2b16neu7CvqrO9s3rVM9d2FfV2b55neq5C/uqOts3r1M9d2FfVWf75nWq5y7sq+ps
+ 37xO9dyFfVWd7ZvXqZ67sK/fVr++Ya//Xtf9pV4Y+Nsr1ScerGztn6vO/Lm4VV9fnhup
+ 3lEfX1jZ3Du7vrnxa+fB33Qvj3d+WZ4dvqM+ON56sbF7et2VHYjeUz/6vPZkZrjS960X
+ a6PzP7377fhKdSR65+Lg45ulqaE76tXhmSer2wfn113dWe69X97dztXJl42VhxONct+3
+ Xig3Jh+23+8cnV9e376OD1LgVvPq8nT/49un86O10t/+Bt/7x1JtZO7J642dg+PTs947
+ 90EK9DBPT452t9fbP9wbqhT71YuVxkRr+dX7jztfdvf29n2YAnt7u18+b621l2ZHBkt9
+ v+AHBgqlanOy9aS9uv5hY3Nzy4cpsLm58X7t1bPFubH63U/9lr3WnJh7+Pjp8xft9ooP
+ U6DdfvFsebE1PdqoFO986r1f972vvTEyOT13v7XgIxVoteZnp8abvS/9a/Rb9kqt0RwZ
+ G/exCoyNjjTr1XJE77EXS+VqrTZY95EKDA7WqpV/Mv/j7/SFQrFY8rEKFIvFQvrl3v9f
+ cf6bBSxgAQtYwAIWsIAFLGABC1jAAhawgAUsYAELWMACFrCABSxgAQtYwAIWsIAFLGAB
+ C1jAAhawgAUsYAELWMACFrCABSxgAQtYwAIWsIAFLGABC1jAAhawgAUsYAELWMACFrCA
+ BSxgAQtYwAIWsIAFLGABC1jAAhawgAUsYAELWMACFrCABSxgAQtYwAIWsIAFLGABC1jA
+ AhawgAUsYAELWMACFrCABSxggX+lwP8AyqUofgplbmRzdHJlYW0KZW5kb2JqCjQyIDAg
+ b2JqCjI3OTgKZW5kb2JqCjQzIDAgb2JqCjw8IC9MZW5ndGggNDQgMCBSIC9UeXBlIC9Y
+ T2JqZWN0IC9TdWJ0eXBlIC9JbWFnZSAvV2lkdGggNDAyIC9IZWlnaHQgMzc0IC9Db2xv
+ clNwYWNlCi9EZXZpY2VHcmF5IC9JbnRlcnBvbGF0ZSB0cnVlIC9CaXRzUGVyQ29tcG9u
+ ZW50IDggL0ZpbHRlciAvRmxhdGVEZWNvZGUgPj4Kc3RyZWFtCngB7ZdZW5NXAAbJHgiL
+ LIJsClKRugRL61aWShURUBAhBP//H2nwqRa0zlX93ovOueHihQzPDOdL6OvzaEADGtCA
+ BjSgAQ0UY6BULlc8hRool0ul78UtlSu1eqPZ7ynSQLNRq1b+vUmpUmu2hkZGxzwFGhi9
+ Njw40KiW/6VJuVJvjYxPzczN3/QUZ2B+dnpybKi/9u01KVUag+MzC3fuPWi3Vz1FGWg/
+ vL+yND91baD29S0pVeqDE/PL7cfPNza3PMUZ2Fx/unZ/aWa0l+Tq+3u51hqfX1lb397Z
+ fbPnKc7Am9evtp62f5oeaX713Ko0R6aX1zZ3Dg6P3h97ijPw/ujd3p/PHy5eH7x6SUrV
+ 1vhCe33n7fFpp3PmKc5Ap3NytL/9ZGWmd0kuP7bK9aGpO4+394873e75+flHTzEGeq67
+ Z6dHuxvtW+MD1cufgMuNkZl7z3cOTy96WKSYHJ8oF0k+7L/4dan32LpcpNIcnXuwsXvU
+ 8YYUWONzkpO3L5/cmRq6WqR/dL69+eZ9xwtSdJGP592Td6+e3r0xVL9yR/rHbra39o57
+ RQr/jf73wO7p4c6zu9PD3xRZtUjmj+OiyPOV7xQ5y/xO/2/qlyKX/2uv9J5aF3fEIoE/
+ DosEpCPSIqgnMFokIB2RFkE9gdEiAemItAjqCYwWCUhHpEVQT2C0SEA6Ii2CegKjRQLS
+ EWkR1BMYLRKQjkiLoJ7AaJGAdERaBPUERosEpCPSIqgnMFokIB2RFkE9gdEiAemItAjq
+ CYwWCUhHpEVQT2C0SEA6Ii2CegKjRQLSEWkR1BMYLRKQjkiLoJ7AaJGAdERaBPUERosE
+ pCPSIqgnMFokIB2RFkE9gdEiAemItAjqCYwWCUhHpEVQT2C0SEA6Ii2CegKjRQLSEWkR
+ 1BMYLRKQjkiLoJ7AaJGAdERaBPUERosEpCPSIqgnMFokIB2RFkE9gdEiAemItAjqCYwW
+ CUhHpEVQT2C0SEA6Ii2CegKjRQLSEWkR1BMYLRKQjkiLoJ7AaJGAdERaBPUERosEpCPS
+ IqgnMFokIB2RFkE9gdEiAemItAjqCYwWCUhHpEVQT2C0SEA6Ii2CegKjRQLSEWkR1BMY
+ LRKQjkiLoJ7AaJGAdERaBPUERosEpCPSIqgnMFokIB2RFkE9gdEiAemItAjqCYwWCUhH
+ pEVQT2C0SEA6Ii2CegKjRQLSEWkR1BMYLRKQjkiLoJ7AaJGAdERaBPUERosEpCPSIqgn
+ MFokIB2RFkE9gdEiAemItAjqCYwWCUhHpEVQT2C0SEA6Ii2CegKjRQLSEWkR1BMYLRKQ
+ jkiLoJ7AaJGAdERaBPUERosEpCPSIqgnMFokIB2RFkE9gdEiAemItAjqCYwWCUhHpEVQ
+ T2C0SEA6Ii2CegKjRQLSEWkR1BMYLRKQjkiLoJ7AaJGAdERaBPUERosEpCPSIqgnMFok
+ IB2RFkE9gdEiAemItAjqCYwWCUhHpEVQT2C0SEA6Ii2CegKjRQLSEWkR1BMYLRKQjkiL
+ oJ7AaJGAdERaBPUERosEpCPSIqgnMFokIB2RFkE9gdEiAemItAjqCYwWCUhHpEVQT2C0
+ SEA6Ii2CegKjRQLSEWkR1BMYLRKQjkiLoJ7AaJGAdERaBPUERosEpCPSIqgnMFokIB2R
+ FkE9gdEiAemItAjqCYwWCUhHpEVQT2C0SEA6Ii2CegKjRQLSEWkR1BMYLRKQjkiLoJ7A
+ aJGAdERaBPUERosEpCPSIqgnMFokIB2RFkE9gdEiAemItAjqCYwWCUhHpEVQT2C0SEA6
+ Ii2CegKjRQLSEWkR1BMYLRKQjkiLoJ7AaJGAdERaBPUERosEpCPSIqgnMFokIB2RFkE9
+ gdEiAemItAjqCYwWCUhHpEVQT2C0SEA6Ii2CegKjRQLSEWkR1BMYLRKQjkiLoJ7AaJGA
+ dERaBPUERosEpCPSIqgnMFokIB2RFkE9gdEiAemItAjqCYwWCUhHpEVQT2C0SEA6Ii2C
+ egKjRQLSEWkR1BMYLRKQjkiLoJ7AaJGAdERaBPUERosEpCPSIqgnMFokIB2RFkE9gdEi
+ AemItAjqCYwWCUhHpEVQT2C0SEA6Ii2CegKjRQLSEWkR1BMYLRKQjkiLoJ7AaJGAdERa
+ BPUERosEpCPSIqgnMFokIB2RFkE9gdEiAemItAjqCYwWCUhHpEVQT2C0SEA6Ii2CegKj
+ RQLSEWkR1BMYLRKQjkiLoJ7AaJGAdERaBPUERosEpCPSIqgnMFokIB2RFkE9gdEiAemI
+ tAjqCYwWCUhHpEVQT2C0SEA6Ii2CegKjRQLSEWkR1BMYLRKQjkiLoJ7AaJGAdERaBPUE
+ RosEpCPSIqgnMFokIB2RFkE9gdEiAemItAjqCYwWCUhHpEVQT2C0SEA6Ii2CegKjRQLS
+ EWkR1BMYLRKQjkiLoJ7AaJGAdERaBPUERosEpCPSIqgnMFokIB2RFkE9gdEiAemItAjq
+ CYwWCUhHpEVQT2C0SEA6Ii2CegKjRQLSEWkR1BMYLRKQjkiLoJ7AaJGAdERaBPUERosE
+ pCPSIqgnMFokIB2RFkE9gdEiAemItAjqCYwWCUhHpEVQT2C0SEA6Ii2CegKjRQLSEWkR
+ 1BMYLRKQjkiLoJ7AaJGAdERaBPUERosEpCPSIqgnMFokIB2RFkE9gdEiAemItAjqCYwW
+ CUhHpEVQT2C0SEA6IrFIB3/U8YcY+FKk1PfPqfSP3Vzd2jvunP8Qpi9KBr5XZL69ufe+
+ c35uE7L3A7bz7um7V8/u3hiqX7kjzdG5hxu7Rxb5AcrxJXtXoHvy7uWT5amh2uUi5cbI
+ 7L3fXx+ednvf4S1Bh//t2NN99uFg+7efJgevFqkP31h+8ufBh7OLJP8t01cDA70b0u0c
+ vdl8tDA+UL18R0q11sTio43XhyedM0+hBjqnxwcvn96bu9as/PNJq6+vVOm/Nrvy2x+7
+ b4+OP3iKNHB8uP9qfXVpcqhevlykr1wfnLh1//Hmy939/QNPcQb2915v//7L8uxo/5WH
+ 1sUlaQxPLvy89mzjjxfbnuIMvNhaf9xenhtv1a5ekb6+crU5fH1u6eeHj9Z+9RRn4JfV
+ B3cXZ8Za9crl9/WL51epl2RwdHL25sLi7SVPQQZu3168NTc9MTLwbZBPSeoDQyNj4xPX
+ PYUZmJgYHx1uNWvf3JBP7/K9a1Jv9A+0PEUaGOhv1Crlrx9Znz92lcqVSrVarXkKMtCT
+ Xe3l+F6Pv7uUPEUa+Hwb/KoBDWhAAxrQgAY0UICBvwALpbhFCmVuZHN0cmVhbQplbmRv
+ YmoKNDQgMCBvYmoKMjQ0NwplbmRvYmoKNDUgMCBvYmoKPDwgL0xlbmd0aCA0NiAwIFIg
+ L1R5cGUgL1hPYmplY3QgL1N1YnR5cGUgL0ltYWdlIC9XaWR0aCAzMzYgL0hlaWdodCAx
+ MTIgL0NvbG9yU3BhY2UKL0RldmljZUdyYXkgL0ludGVycG9sYXRlIHRydWUgL0JpdHNQ
+ ZXJDb21wb25lbnQgOCAvRmlsdGVyIC9GbGF0ZURlY29kZSA+PgpzdHJlYW0KeAHt3V1T
+ GgcYBWB2F1i+PxMVAtHGIFRlMzH1AwVHGxC1ClJAzP//I91l2gyLcLonN51pznulHg4X
+ z7w7yo1vKKSRgAQkIAEJSOD/LWCYpqUhBEzTMNathGFakagdi2uCC8TsSNhaLWpYkVgy
+ nc0XNIEF8rlMKmGHzRWiphVNZoub5Ur1vSaoQPVdaaOQjkder6hh2alieae2f+g4nzTB
+ BJzmQWO3uplLRJY31LCiqTfVPee41e5caoIKdC5Ojw52y3kX1P9byYwki9XG0cV1r397
+ pwkqcHvTvTx1PpaysaUn3oplS3tHnd4fg+HTSBNU4Gn4ePd7q/nL25R/QY1wsrjjXPQe
+ RpPp9FkTVGA6HQ/vr08aZXdBFx94M5rerB1f34+ms9nLy8s3TRABV2r2PBn22852MRFe
+ /JvJtLPl/VZvMPE05RkEc/4aD/TP+6svu+4Dv+hpxfKVw3Z/ONV2Brb8B3T88PWktpn2
+ e8bzVadz+zTVcnKe315m48fuaX0rHfXtZ7zw3rm8G7me5Pv99C+fTQa9s3op88rzkzx/
+ ZDk8z1Zjjefzj7zjz9357rn4Cclyn3dvP+VJL4c8aTJYkCfkoUN50mSwIE/IQ4fypMlg
+ QZ6Qhw7lSZPBgjwhDx3KkyaDBXlCHjqUJ00GC/KEPHQoT5oMFuQJeehQnjQZLMgT8tCh
+ PGkyWJAn5KFDedJksCBPyEOH8qTJYEGekIcO5UmTwYI8IQ8dypMmgwV5Qh46lCdNBgvy
+ hDx0KE+aDBbkCXnoUJ40GSzIE/LQoTxpMliQJ+ShQ3nSZLAgT8hDh/KkyWBBnpCHDuVJ
+ k8GCPCEPHcqTJoMFeUIeOpQnTQYL8oQ8dChPmgwW5Al56FCeNBksyBPy0KE8aTJYkCfk
+ oUN50mSwIE/IQ4fypMlgQZ6Qhw7lSZPBgjwhDx3KkyaDBXlCHjqUJ00GC/KEPHQoT5oM
+ FuQJeehQnjQZLMgT8tChPGkyWJAn5KFDedJksCBPyEOH8qTJYAF6TvXv/CHeivC75+r7
+ CCsa+hES8DzP6lvL9xF0vwOhrc/W3O/QfZn1ZChxD/asui/j3T/6tdV7nN8/Qn1lPgHv
+ /tFofv8o6bvXM7/P9Zvuc/mw/vUb97iRe59rcOPe5yr473MZ4URxu3nefRiNpxpCYDIe
+ 3l0d18tZ23c/LmTZmVLtqN29fxw+aQILDAcP/euz5s6bpP++YciMJAqV+ufzq+5N/1YT
+ VKDf+9o5ae5uZZbvb3r3YYuVWvPL2UW7owkq0D4/+bz/oZSLL61nKOTdLy6Utj82Dg6b
+ mqACh/t7Hyob2df3iz3QaCJT2Ci9q1Q1AQUqlfLW23zK3c7FD5t/HzZ177/biVQml9cE
+ FshlM8l4dOX9d3dDTSscse1YXBNQIBazo5E1mvMtNQzTNC1NUAFXy1jxqC+eMtbXEpCA
+ BCQggf9A4C9bXHKRCmVuZHN0cmVhbQplbmRvYmoKNDYgMCBvYmoKMTA4OQplbmRvYmoK
+ NDcgMCBvYmoKPDwgL0xlbmd0aCA0OCAwIFIgL1R5cGUgL1hPYmplY3QgL1N1YnR5cGUg
+ L0ltYWdlIC9XaWR0aCA1MDIgL0hlaWdodCA2MzAgL0NvbG9yU3BhY2UKL0RldmljZUdy
+ YXkgL0ludGVycG9sYXRlIHRydWUgL0JpdHNQZXJDb21wb25lbnQgOCAvRmlsdGVyIC9G
+ bGF0ZURlY29kZSA+PgpzdHJlYW0KeAHt11lzlAUeRvF0OitZgICBgEQWDYuyCLILyC5b
+ IJAQ5vt/kek4o2VAjlUzVxzPe+PFX6vynF/eTjs21lOBClSgAhWoQAUqUIEKVKACFahA
+ BSpQgQpUoAIVqEAFKlCBClSgAhWoQAUqUIEKVKACFahABSpQgQpUoAIVqEAFKlCBClSg
+ AhWoQAUqUIEKVKACFahABSpQgQpUoAIVqEAFKlCBClSgAhWoQAUqUIEKVKACFahABSpQ
+ gQpUoAIVqEAFKlCBClSgAhWoQAUqUIEKVKACFahABSpQgQpUoAIVqEAFKlCBClSgAhWo
+ QAUqUIEKVKACFahABSpQgf+hwGAwGO+RFRihwq/CYHw4MTk1Nd2jKjA1NTkxHP8M/GB8
+ Ymp2bn5hcW+PqcDi4sL8nunJ4V+yD4aTs/P7Di4fXlk50iMqsLJy6KulvXPTE3/xug+G
+ U3v2LR898e3ps2fP9XgKnD17Zu3U6sqBhZmJ8U/+uo9Pzi0dOXnu0k/Xb97qURW4ee3K
+ +bXV5cWZiY8/5AcTs/uPfHfh+p37jx4/6TEVePz44S+3r3x/fHlh+uO/7cPphUOnLt58
+ 8PTFq/X11z2eAuvr6y+fP7579dzqgbnJ3S/7YGLP0uoPNx48f/12c/Rs9WgKjDjfbbx6
+ evfK2sri9O6/7IPJ+eVvr9x79mbz/fbo+dCjKbDj+f7dq8e3zq8uzU7s+j43Pr24cubG
+ o1fvdsT/1WMqMPr93d7aeHbv8smDc7u/z43P7Dv6/e2nr7e2MzeJ72zZ+dR6/+7lg6vf
+ Lc/v/sM+nN1/7PydX99s9abb0H9z33736tH1tUMLU7u+zg1nl1Yv3H22sdWr7lTfXH90
+ 4/ThxU/VL6YuFP/PpO3N9cc3z6x8Rv29dvc/e1jq/0T/P9R3/Q/7zt/1nU/43nXn70Tq
+ TldelTr3cV5Td7ryqtS5j/OautOVV6XOfZzX1J2uvCp17uO8pu505VWpcx/nNXWnK69K
+ nfs4r6k7XXlV6tzHeU3d6cqrUuc+zmvqTldelTr3cV5Td7ryqtS5j/OautOVV6XOfZzX
+ 1J2uvCp17uO8pu505VWpcx/nNXWnK69Knfs4r6k7XXlV6tzHeU3d6cqrUuc+zmvqTlde
+ lTr3cV5Td7ryqtS5j/OautOVV6XOfZzX1J2uvCp17uO8pu505VWpcx/nNXWnK69Knfs4
+ r6k7XXlV6tzHeU3d6cqrUuc+zmvqTldelTr3cV5Td7ryqtS5j/OautOVV6XOfZzX1J2u
+ vCp17uO8pu505VWpcx/nNXWnK69Knfs4r6k7XXlV6tzHeU3d6cqrUuc+zmvqTldelTr3
+ cV5Td7ryqtS5j/OautOVV6XOfZzX1J2uvCp17uO8pu505VWpcx/nNXWnK69Knfs4r6k7
+ XXlV6tzHeU3d6cqrUuc+zmvqTldelTr3cV5Td7ryqtS5j/OautOVV6XOfZzX1J2uvCp1
+ 7uO8pu505VWpcx/nNXWnK69Knfs4r6k7XXlV6tzHeU3d6cqrUuc+zmvqTldelTr3cV5T
+ d7ryqtS5j/OautOVV6XOfZzX1J2uvCp17uO8pu505VWpcx/nNXWnK69Knfs4r6k7XXlV
+ 6tzHeU3d6cqrUuc+zmvqTldelTr3cV5Td7ryqtS5j/OautOVV6XOfZzX1J2uvCp17uO8
+ pu505VWpcx/nNXWnK69Knfs4r6k7XXlV6tzHeU3d6cqrUuc+zmvqTldelTr3cV5Td7ry
+ qtS5j/OautOVV6XOfZzX1J2uvCp17uO8pu505VWpcx/nNXWnK69Knfs4r6k7XXlV6tzH
+ eU3d6cqrUuc+zmvqTldelTr3cV5Td7ryqtS5j/OautOVV6XOfZzX1J2uvCp17uO8pu50
+ 5VWpcx/nNXWnK69Knfs4r6k7XXlV6tzHeU3d6cqrUuc+zmvqTldelTr3cV5Td7ryqtS5
+ j/OautOVV6XOfZzX1J2uvCp17uO8pu505VWpcx/nNXWnK69Knfs4r6k7XXlV6tzHeU3d
+ 6cqrUuc+zmvqTldelTr3cV5Td7ryqtS5j/OautOVV6XOfZzX1J2uvCp17uO8pu505VWp
+ cx/nNXWnK69Knfs4r6k7XXlV6tzHeU3d6cqrUuc+zmvqTldelTr3cV5Td7ryqtS5j/Oa
+ utOVV6XOfZzX1J2uvCp17uO8pu505VWpcx/nNXWnK69Knfs4r6k7XXlV6tzHeU3d6cqr
+ Uuc+zmvqTldelTr3cV5Td7ryqtS5j/OautOVV6XOfZzX1J2uvCp17uO8pu505VWpcx/n
+ NXWnK69Knfs4r6k7XXlV6tzHeU3d6cqrUuc+zmvqTldelTr3cV5Td7ryqtS5j/OautOV
+ V6XOfZzX1J2uvCp17uO8pu505VWpcx/nNXWnK69Knfs4r6k7XXlV6tzHeU3d6cqrUuc+
+ zmvqTldelTr3cV5Td7ryqtS5j/OautOVV6XOfZzX1J2uvCp17uO8pu505VWpcx/nNXWn
+ K69Knfs4r6k7XXlV6tzHeU3d6cqrUuc+zmvqTldelTr3cV5Td7ryqtS5j/OautOVV6XO
+ fZzX1J2uvCp17uO8pu505VWpcx/nNXWnK69Knfs4r6k7XXlV6tzHeU3d6cqrUuc+zmvq
+ TldelTr3cV5Td7ryqtS5j/OautOVV6XOfZzX1J2uvCp17uO8pu505VWpcx/nNXWnK69K
+ nfs4r6k7XXlV6tzHeU3d6cqrUuc+zmvqTldelTr3cV5Td7ryqtS5j/OautOVV6XOfZzX
+ 1J2uvCp17uO8pu505VWpcx/nNXWnK69Knfs4r6k7XXlV6tzHeU3d6cqrUuc+zmvqTlde
+ lTr3cV5Td7ryqtS5j/OautOVV6XOfZzX1J2uvCp17uO8pu505VWpcx/nNXWnK69Knfs4
+ r6k7XXlV6tzHeU3d6cqrUuc+zmvqTldelTr3cV5Td7ryqtS5j/OautOVV6XOfZzX1J2u
+ vCp17uO8pu505VWpcx/nNXWnK69Knfs4r6k7XXlV6tzHeU3d6cqrUuc+zmvqTldelTr3
+ cV5Td7ryqtS5j/OautOVV6XOfZzX1J2uvCp17uO8pu505VWpcx/nNXWnK69Knfs4r6k7
+ XXlV6tzHeU3d6cqrUuc+zmvqTldelTr3cV5Td7ryqtS5j/OautOVV6XOfZzX1J2uvCp1
+ 7uO8pu505VWpcx/nNXWnK69Knfs4r6k7XXlV6tzHeU3d6cqrUuc+zmvqTldelTr3cV5T
+ d7ryqtS5j/OautOVV6XOfZzX1J2uvCp17uO8pu505VWpcx/nNXWnK69Knfs4r6k7XXlV
+ 6tzHeU3d6cqrUuc+zmvqTldelTr3cV5Td7ryqtS5j/OautOVV6XOfZzX1J2uvCp17uO8
+ pu505VWpcx/nNXWnK69Knfs4r6k7XXlV6tzHeU3d6cqrUuc+zmvqTldelTr3cV5Td7ry
+ qtS5j/OautOVV6XOfZzX1J2uvCp17uO8pu505VWpcx/nNXWnK69Knfs4r6k7XXlV6tzH
+ eU3d6cqrUuc+zmvqTldelTr3cV5Td7ryqtS5j/OautOVV6XOfZzX1J2uvCp17uO8pu50
+ 5VWpcx/nNXWnK69Knfs4r6k7XXlV6tzHeU3d6cqrUuc+zmvqTldelTr3cV5Td7ryqtS5
+ j/OautOVV6XOfZzX1J2uvCp17uO8pu505VWpcx/nNXWnK69Knfs4r6k7XXlV6tzHeU3d
+ 6cqrUuc+zmvqTldelTr3cV5Td7ryqtS5j/OautOVV6XOfZzX1J2uvIrVt/g/7vqFFvhD
+ fTD2p2c4u7R68e6zja0PX+isfmws8Fn1YxfuPHuz9eFD7tjvizx+2N589ejG6cMLU7vf
+ 9Zn9X5//+WnqXyTq3/zQozd5+92rh9fWDi1M7lIfn9579NytJ+ub26N/pbf9bzJ+YeeR
+ 6Pu3L+7/9O3y/EfqU4uH1649ePn2/Q77F7aqHxcLjN707a03v965dPzAnold7/pgcu7g
+ iUs/P1l/t/W+x1Zga3PjxcPr577eNzP80zf4sbHBcHbf0TNX7z19+XrjbY+swMb680e3
+ L51aXpga36U+Nj41f/Cb76/eefT0+YseV4Hnz57cv/Xj2tH9s7s/4Hde9unF5eNnL9/4
+ +d790fOgR1JghPnL3dvXLqx9fWDu41d9bGx8Ymbxq2Onzl748fKVHlWByxd/OH3iyNL8
+ 1HDXd7mdD/vBiH1+afno6vGTJ0/1iAqcPPHNsZWDe+f+Av039qk9C3uXDhz8qkdV4OCB
+ /YtzM5Ofvum/fbUbve5TM7N75npkBfbMTk8Oxz/5eP/9+/xgfDicmJiY7BEVGIGOyD9r
+ /l/7QY+swO8vdf+sQAUqUIEKVKACFahABSpQgQpUoAIVqEAFKlCBClSgAhWoQAUqUIEK
+ VKACFahABSpQgQpUoAIVqEAFKlCBClSgAhWoQAUqUIEKVKACFahABSpQgQpUoAIVqEAF
+ KlCBClSgAhWoQAUqUIEKVKACFahABSpQgQpUoAIVqEAFKlCBClSgAhWoQAUqUIEKVKAC
+ FahABSpQgQpUoAIVqEAFKlCBClSgAhWoQAUqUIEKVKACFahABSpQgQpUoAL/X4F/A+4p
+ 3x8KZW5kc3RyZWFtCmVuZG9iago0OCAwIG9iagozNDQ5CmVuZG9iago0OSAwIG9iago8
+ PCAvTGVuZ3RoIDUwIDAgUiAvVHlwZSAvWE9iamVjdCAvU3VidHlwZSAvSW1hZ2UgL1dp
+ ZHRoIDQwMiAvSGVpZ2h0IDExNCAvQ29sb3JTcGFjZQovRGV2aWNlR3JheSAvSW50ZXJw
+ b2xhdGUgdHJ1ZSAvQml0c1BlckNvbXBvbmVudCA4IC9GaWx0ZXIgL0ZsYXRlRGVjb2Rl
+ ID4+CnN0cmVhbQp4Ae2dW1PaXBSGyRkIBAELQgVrKQdFY0c/5SRaFTxQASkJof//jzRo
+ 2yEq64695pu+60Iv3oGXeR52tl6tUAgDAiAAAiAAAiAAAiAghoAkywpGKAFZlqRVciVZ
+ 0XQjHMGIJBA2NFV534mkaGEznkimMAIJJDesWNRQ5XecyIpuJtLZ/HahiBFHoPAxl0nF
+ I9rbYyIpRiyd/1TeP7DtI4woAvZhvVYqZDei2utTIil6bLNQsU9b590LjDgC3U7juF7K
+ J30lwftd1sx0oXbcuerf3T9gxBG4v+1dNOwvuUT41XNLCSdyleNu//to/DTBiCPwNB4+
+ XLcOdz/EgodEUs30J7vTf5w4rjvDiCPgutPx4OqslvcPyfJjS9bj2fLp1WDiet58Pv+J
+ EUPAZ+3NnPHdub2TjqrLfwHLRiK/3+qPnIUPGBGj47lloeTH4NtJyX9sLRtRwsntg/O7
+ sYsTItDGHyXTx5uzcjYeNBJJFuzu/ZOLAyLayM+5Nx32GtWtuB44I5FU0b54mPhGhH+i
+ f77Qc0b9ZjVnvTFyBCM8X46FkVZthZEZz2f6t1v/Gln+r13xn1qLMwIjDF8OGGGATlbC
+ CImHIYQRBuhkJYyQeBhCGGGATlbCCImHIYQRBuhkJYyQeBhCGGGATlbCCImHIYQRBuhk
+ JYyQeBhCGGGATlbCCImHIYQRBuhkJYyQeBhCGGGATlbCCImHIYQRBuhkJYyQeBhCGGGA
+ TlbCCImHIYQRBuhkJYyQeBhCGGGATlbCCImHIYQRBuhkJYyQeBhCGGGATlbCCImHIYQR
+ BuhkJYyQeBhCGGGATlbCCImHIYQRBuhkJYyQeBhCGGGATlbCCImHIYQRBuhkJYyQeBhC
+ GGGATlbCCImHIYQRBuhkJYyQeBhCGGGATlbCCImHIYQRBuhkJYyQeBhCGGGATlbCCImH
+ IYQRBuhkJYyQeBhCGGGATlbCCImHIYQRBuhkJYyQeBhCGGGATlbCCImHIYQRBuhkJYyQ
+ eBhCGGGATlbCCImHIYQRBuhkJYyQeBhCGGGATlbCCImHIYQRBuhkJYyQeBhCGGGATlbC
+ CImHIYQRBuhk5V8jr7e4vuwMJV+LcB0EVhp52au7jkq8J0HAXwfujHrN6tbrvbrJwuHL
+ 7mnixYjWQMA3stg9XckGd0/L4Y3teud5P/saSvGWKwn429fns+nj9Wk5EwvsZ5cNK7fX
+ 7A2nnod94CvxrSHwhXjuZHB5/HnTVJdvdkmLZb6cXD48ObOFE4woAp7nzabDfvuwmIqo
+ oaWR1GiqeNC8GYx/OI6LEUbAcaaT0d3FSSVnGcvLwEMhxbCypaP29f334WiMEUZgNBoO
+ bi/P6sW0GbhGQiFJjSQ/lo8a3ete/xYjjkD/5lvnv/puJm4oy9eIb0TWzFT+8/7X02a7
+ 3cEIItButxondnUnY4UD9/riQpEUPbqR2d4tV/f2McII7NUqpZ38pi8keIu8KNEi8eRm
+ ZiuXx4gjkMt+SCdMQ5WDz6znv7okWdUjZsyyEhhxBKx4LGpoytsT8tuJomq6gRFIQNc1
+ VXnvgDwb8X9IkowRSkCS3nle/dGB3yAAAiAAAiAAAv93Ar8AcG6kVAplbmRzdHJlYW0K
+ ZW5kb2JqCjUwIDAgb2JqCjEyMDIKZW5kb2JqCjUxIDAgb2JqCjw8IC9MZW5ndGggNTIg
+ MCBSIC9UeXBlIC9YT2JqZWN0IC9TdWJ0eXBlIC9JbWFnZSAvV2lkdGggMzM2IC9IZWln
+ aHQgMTA0IC9Db2xvclNwYWNlCi9EZXZpY2VHcmF5IC9JbnRlcnBvbGF0ZSB0cnVlIC9C
+ aXRzUGVyQ29tcG9uZW50IDggL0ZpbHRlciAvRmxhdGVEZWNvZGUgPj4Kc3RyZWFtCngB
+ 7d1ZV9pQFAVgkkAghEEGURAqlIpUJSqtI0OLiggoiBKg//+P9GJXESKcdY+Pus+Tstk8
+ fOtmOTyc63JhIAABCEAAAhD42AKKqmoYhoCqKsqqI6Gomkf3+gyMvIDP63Fry0UVzeMz
+ g+FIFCMtEFkLBfxet7pEVNV0MxzbSKUzXzCyApmtZCIaNDxvj6iieQOxVHZn78CyDjFy
+ AlZpv5jPbKz5Pc4Tqmh6IJ4pWCcX1VodIytQq5yV9/OpiABd/KmkesxYpliuNJqtuzZG
+ VuDu9qZ+Zn1Lhn2OJ17zhZOFcq3Z7fUfBxhZgcf+Q/vqopRbDyweUMVtxrJWpXk/GNr2
+ CCMrYNvP/U7jtJgSB3T+gVf14MbOSaMzsMfjyWTyByMjIKTGo2G/VbW2Y373/O9Mqjec
+ 2rto9oZTTXjKYL68Zwr61Pn9Iy8e+HlPzRdJH1RbfRunU9ryP+jz/fXpzkZw0dOIZKza
+ 3aONw8nz/DMZPz/cnO1uBvWF82lEv1j19kB4Mj/v0799POw1z3eToTeeh/B8z+GYel4U
+ V3iO3vOJn7sz85z/C0kTz/v0fMKTfTjgySYjC/AkedghPNlkZAGeJA87hCebjCzAk+Rh
+ h/Bkk5EFeJI87BCebDKyAE+Shx3Ck01GFuBJ8rBDeLLJyAI8SR52CE82GVmAJ8nDDuHJ
+ JiML8CR52CE82WRkAZ4kDzuEJ5uMLMCT5GGH8GSTkQV4kjzsEJ5sMrIAT5KHHcKTTUYW
+ 4EnysEN4ssnIAjxJHnYITzYZWYAnycMO4ckmIwvwJHnYITzZZGQBniQPO4Qnm4wswJPk
+ YYfwZJORBXiSPOwQnmwysgBPkocdwpNNRhbgSfKwQ3iyycgCPEkedghPNhlZgCfJww7h
+ ySYjC/AkedghPNlkZAGeJA87hCebjCzAk+Rhh/Bkk5EFeJI87BCebDKyAE+Shx3Ck01G
+ FkhPm6wiXCIw83Tu//y3r3JJAy9RAqs8xX7aNvbTUnJLs8l4+HBz/mY/rdifXJruT8a+
+ 36Vqq14UXGLf7/VpwbE/Wez33tq7/L/fe1UbrzsFhOfoqdv4+S2xuN9b1UObhdOr7tMI
+ C76dZsT34nSO7f5d7Sjr2D+veMx47qh623vG7QiydyO8vM8eDrpXZ3vptcX7ERTNWNsq
+ /qy37vuDJ4y0wGDQ69xUDvOJoD6/PtnlUsV1Pdv7J7XrVrvTxcgKdNq3jcvjwlbEWLhu
+ wuUS10mFEtnvx+fVX78bGFmBX/XKibWTjpmL18uIq1FUty+0ns5/Lx2Vyz8wcgLl48OD
+ 3VwyauqO64/EARWggUgilcnmvmJkBXLb6WQ87H/L+QKqG4FwNBaPr2PkBOLxWCRk+pZc
+ xze9DEkcUd1r+E2MvIDf8Ho052V8s5ulxI2mmhvDERCY8/9YmlG+fqFgpAVe1fAVBCAA
+ AQhAAAIfV+AvZD1MOQplbmRzdHJlYW0KZW5kb2JqCjUyIDAgb2JqCjEwODYKZW5kb2Jq
+ CjMwIDAgb2JqCjw8IC9UeXBlIC9FeHRHU3RhdGUgL2NhIDAuNyA+PgplbmRvYmoKMzEg
+ MCBvYmoKPDwgL1R5cGUgL0V4dEdTdGF0ZSAvQ0EgMC43ID4+CmVuZG9iago1MyAwIG9i
+ ago8PCAvTGVuZ3RoIDU0IDAgUiAvTiAxIC9BbHRlcm5hdGUgL0RldmljZUdyYXkgL0Zp
+ bHRlciAvRmxhdGVEZWNvZGUgPj4Kc3RyZWFtCngBhVJPSBRRHP7NNhKEiEGFeIh3CgmV
+ KaysoNp2dVmVbVuV0qIYZ9+6o7Mz05vZNcWTBF2iPHUPomN07NChm5eiwKxL1yCpIAg8
+ dej7zezqKIRveTvf+/39ft97RG2dpu87KUFUc0OVK6Wnbk5Ni4MfKUUd1E5YphX46WJx
+ jLHruZK/u9fWZ9LYst7HtXb79j21lWVgIeottrcQ+iGRZgAfmZ8oZYCzwB2Wr9g+ATxY
+ Dqwa8COiAw+auTDT0Zx0pbItkVPmoigqr2I7Sa77+bnGvou1iYP+XI9m1o69s+qq0UzU
+ tPdEobwPrkQZz19U9mw1FKcN45xIQxop8q7V3ytMxxGRKxBKBlI1ZLmfak6ddeB1GLtd
+ upPj+PYQpT7JYKiJtemymR2FfQB2KsvsEPAF6PGyYg/ngXth/1tRw5PAJ2E/ZId51q0f
+ 9heuU+B7hD014M4UrsXx2oofXi0BQ/dUI2iMc03E09c5c6SI7zHUGZj3RjmmCzF3lqoT
+ N4A7YR9ZqmYKsV37ruol7nsCd9PjO9GbOQtcoBxJcrEV2RTQPAlYFH2LsEkOPD7OHlXg
+ d6iYwBy5idzNKPce1REbZ6NSgVZ6jVfGT+O58cX4ZWwYz4B+rHbXe3z/6eMVdde2Pjz5
+ jXrcOa69nRtVYVZxZQvd/8cyhI/ZJzmmwdOhWVhr2HbkD5rMTLAMKMR/BT6X+pITVdzV
+ 7u24RRLMUD4sbCW6S1RuKdTqPYNKrBwr2AB2cJLELFocuFNrujl4d9giem35TVey64b+
+ +vZ6+9ryHm3KqCkoE82zRGaUsVuj5N142/1mkRGfODq+572KWsn+SUUQP4U5WiryFFX0
+ VlDWxG9nDn4btn5cP6Xn9UH9PAk9rZ/Rr+ijEb4MdEnPwnNRH6NJ8LBpIeISoIqDM9RO
+ VGONA+Ip8fK0W2SR/Q9AGf1mCmVuZHN0cmVhbQplbmRvYmoKNTQgMCBvYmoKNzA0CmVu
+ ZG9iagoyMiAwIG9iagpbIC9JQ0NCYXNlZCA1MyAwIFIgXQplbmRvYmoKNTUgMCBvYmoK
+ PDwgL0xlbmd0aCA1NiAwIFIgL04gMyAvQWx0ZXJuYXRlIC9EZXZpY2VSR0IgL0ZpbHRl
+ ciAvRmxhdGVEZWNvZGUgPj4Kc3RyZWFtCngB1VlnWBTNsu6ZTcCypCXnHEVylpwkSA6C
+ SFrSknMOSlKCIIiAgKCACCKCGAgCImACRIKAEQmiIKhgAgThDur3fec+55x/98+d55me
+ d6uqq2unerqn3gGAbdktONgfpgMgIDA81MpQh/eggyMv7gWgBDSAEYgBSjdSWLC2hYUp
+ +K/H9wkA7SrHJHd9/Vez/6yg9/AMIwEAWSBqd48wUgCCrwMA65CCQ8MBQK0j8uGo8GAE
+ ox8gmDEUCRDBL3ex92+8sovdf2EM+peNjZUuABhWACio3dxCvQEgCCJy3kiSN+KHoAcA
+ liHQgxwIAPEggjVIPm4eALAVIzZ7AgKCdnEfgkXd/8WP979gNzf3v326uXn/jX//F6Qn
+ MrAeOSzY3y3m14//yybAPwK5X78OBqSlDvQ3280NM3IueLjpmSBXTuTcDvb/lTPEBmL3
+ DLS1RmS7eE+gu5n5H6zhFWpghWCkL2QRHK6zi5F7BnkFh1vY/JEnxvromiGYGpEXeIbp
+ /+XnnK+b8W7OaBB5c2iElS2CBRHcHRZprY9gZEZBb2J9bOz/2Hz18NT7I4dhL7KB0W8b
+ mIEcbrQ7FiOSc36/IJPdGJCxYEVgAvyBJ4gAoUgbCCSBKdAFen9aSeAF3BBNJKILA37g
+ LYIDkB5BSJ8gBPP+sdP9N4nBr37eSL//7ZEXkBDbiL/H/D0aLzLmXz7JwAPBf8ndkDF2
+ dbvRhbmQk/8Z8y+LXX+/opGul16U3vorJrQwWhatgNZBq6M10CqAF82MZgeSaHm0Mlob
+ rYlWQ3QqwAC8QTx7/xXjrv+AZq/I4qAYVTsfRLv7393/0gK7X9bkv3//WwSAPLTcsvxX
+ BACEe0YjzwEAukHBMaFkb59wXm3kyfXcw2sUSNq7h1dWWkZmV/3/5thds34H+8Xq11oE
+ MT/+RxbQCIAyGZmPzv/I3E8C0C6JPPv1/8iEC5G1wReAAUFSRGjkb3/o3QsGUAFaZIay
+ AW4gAESR+ywLFIEa0AL6wBiYAxvgAJyR+eODzMFQEAXiwVGQDrLASXAalIAKUAVqQQNo
+ Bi2gA9wB98AAGAbj4AWYBvNgCayA72ATgiAcRICIEBvEAwlBEpAspAxpQPqQKWQFOUCu
+ kDcUCEVA8VAKlAXlQyXQeagOugq1QXegh9AI9AyagRahz9APGAVTw4wwFywMS8HKsDZs
+ AtvAh2FvOASOhVPhHLgYroQvwzfhO/AAPA5Pw0vwNxRA4VHMKD6UJEoZpYsyRzmivFCh
+ qERUJqoQVYm6gmpH3UeNoaZRy6gNNBZNRPOiJZF5uh9tiyahQ9CJ6Gx0CboWfRPdhx5D
+ z6BX0NsYAoYTI4FRxRhhDmK8MVGYdEwhpgZzA3MXM46Zx3zHYrHMWBGsEnY/1gHri43D
+ ZmPPYhux3dgR7Bz2Gw6HY8NJ4NRx5jg3XDguHXcGdxl3GzeKm8etU+ApeChkKQwoHCkC
+ KZIpCikuUXRRjFK8o9ikpKMUolSlNKf0oIyhzKWspmynfEw5T7lJRU8lQqVOZUPlS3WU
+ qpjqCtVdqpdUX/B4PD9eBW+JJ+OP4IvxTfgH+Bn8BjUDtTi1LrUTdQR1DvVF6m7qZ9Rf
+ CASCMEGL4EgIJ+QQ6gi9hCnCOg2RZi+NEY0HTRJNKc1NmlGaj7SUtEK02rTOtLG0hbTX
+ aB/TLtNR0gnT6dK50SXSldK10U3SfaMn0svQm9MH0GfTX6J/SL/AgGMQZtBn8GBIZahi
+ 6GWYI6KIAkRdIomYQqwm3iXOM2IZRRiNGH0ZsxgbGIcYV5gYmOSZ7JiimUqZOpmmmVHM
+ wsxGzP7MuczNzBPMP1i4WLRZPFkyWK6wjLKssXKwarF6smayNrKOs/5g42XTZ/Njy2Nr
+ YXvFjmYXZ7dkj2IvZ7/LvszByKHGQeLI5GjmeM4Jc4pzWnHGcVZxDnJ+4+LmMuQK5jrD
+ 1cu1zM3MrcXty13A3cW9yEPk0eAh8xTw3OZ5z8vEq83rz1vM28e7wsfJt58vgu883xDf
+ Jr8Ivy1/Mn8j/ysBKgFlAS+BAoEegRVBHsEDgvGC9YLPhSiFlIV8hIqE7gutCYsI2wsf
+ E24RXhBhFTESiRWpF3kpShDVFA0RrRR9IoYVUxbzEzsrNiwOiyuI+4iXij+WgCUUJcgS
+ ZyVG9mD2qOwJ3FO5Z1KSWlJbMlKyXnJmL/Ne073Je1v2fpQSlHKUypO6L7UtrSDtL10t
+ /UKGQcZYJlmmXeazrLgsSbZU9okcQc5ALkmuVW5VXkLeU75c/qkCUeGAwjGFHoWfikqK
+ oYpXFBeVBJVclcqUJpUZlS2Us5UfqGBUdFSSVDpUNlQVVcNVm1U/qUmq+aldUlvYJ7LP
+ c1/1vjl1fnU39fPq0xq8Gq4a5zSmNfk03TQrNWe1BLQ8tGq03mmLaftqX9b+qCOtE6pz
+ Q2dNV1U3QbdbD6VnqJepN6TPoG+rX6I/ZcBv4G1Qb7BiqGAYZ9i9H7PfZH/e/kkjLiOS
+ UZ3RirGScYJxnwm1ibVJicmsqbhpqGn7AfiA8YFTB16aCZkFmrWYA3Mj81PmryxELEIs
+ blliLS0sSy3fWslYxVvdtyZau1hfsv5uo2OTa/PCVtQ2wrbHjtbOya7Obs1ezz7ffvqg
+ 1MGEgwMO7A5kh1ZHnKOdY43jt0P6h04fmndScEp3mjgscjj68ENndmd/504XWhc3l2uu
+ GFd710uuW27mbpVu39yN3MvcV0i6pCLSkoeWR4HHoqe6Z77nOy91r3yvBW9171Peiz6a
+ PoU+y2Rdcgl51Xe/b4Xvmp+530W/HX97/8YAigDXgLZAhkC/wL4g7qDooJFgieD04OkQ
+ 1ZDTISuhJqE1YVDY4bDWcEbk5XAwQjQiLWImUiOyNHI9yi7qWjR9dGD0YIx4TEbMu1iD
+ 2Atx6DhSXE88X/zR+JkE7YTziVCie2JPkkBSatL8EcMjtUepjvodfZQsnZyf/DXFPqU9
+ lSv1SOpcmmFafTpNemj65DG1YxXH0cfJx4cy5DLOZGxnemT2Z0lnFWZtZZOy+0/InCg+
+ sZPjlTOUq5hbfhJ7MvDkRJ5mXm0+fX5s/typA6duFvAWZBZ8Pe1y+mGhfGFFEVVRRNF0
+ sWlx6xnBMyfPbJX4lIyX6pQ2lnGWZZStnfU4O1quVX6lgqsiq+LHOfK5p+cNz9+sFK4s
+ rMJWRVa9rbarvn9B+UJdDXtNVs3Pi4EXp2utavvqlOrqLnFeyq2H6yPqFy87XR5u0Gto
+ vSJ55Xwjc2NWE2iKaHp/1fXqRLNJc8815WtXrgtdL7tBvJF5E7oZc3OlxadlutWhdaTN
+ uK2nXa39xq29ty528HWUdjJ15nZRdaV27dyOvf2tO7h7+Y73nbkel54XvQd7n/RZ9g3d
+ Nbn74J7Bvd772vdvP1B/0PFQ9WFbv3J/y4DiwM1BhcEbjxQe3RhSHLr5WOlx67DKcPvI
+ vpGuUc3RO2N6Y/eeGD0ZGDcbH5mwnXg66TQ5/dTj6cIz/2erzyOfb7448hLzMvMV3avC
+ Kc6pytdirxunFac7Z/RmBmetZ1/MkeaW3oS92ZpPfUt4W/iO513dguxCx6LB4vD7Q+/n
+ l4KXNpfTP9B/KPso+vH6J61PgysHV+ZXQ1d3Pmd/Yfty8av8155vFt+mvgd831zLXGdb
+ r91Q3rj/w/7Hu82oLdxW8U+xn+3bJtsvdwJ2doLdQt1+vQugkBb28gLg80XkPcEBqR2G
+ AaCi+V1T/LJAyhUIsUGwHbQXWoLPopzRQuj3mG5sMS6YwopSn0oRL0W9lyBBo0xrQudK
+ H8FwmtjGOMNMzaLNGsrWwL7EKcbly93Es86nx39SYFZIRviYyCsxBfGTEsuS+nurpLZl
+ nGTb5dkVohXHleVUclSX9xmqn9P4oWWlfUFnQ89Ev8RgYb+8UZxxlyl0QMss1rzJYs6K
+ 3lrdxsM2ze6c/bWDtx16HbsPtTk1Hq5xLnM56ZrsFuLuTDL1UPLk9yJ4rXnP+PSTm31L
+ /JL9yQEWgQpBLEFrwWMh9aFJYebhPOGfIroic6KcoiWif8T0x5bEkeOVE7AJY4kVSf5H
+ dI4KJjOm0KbSpdGn0x0jHKfMQGfsZG5kfc5eOjGb8zx39ORAXk9+26krBVWnzxTmFKUU
+ x52JKUkuLS67cXa4fLZi+dzK+ZXKlapP1R8vfKhZurhQ+6Zu5tJc/WoD/RXdxsSmlquv
+ m9ev424Qb/K0iLcqtGm2G92y7nDvjO4qvn2ne6EH3UvsY7/Le0/8vtIDnYc6/aL9nwYy
+ B9kGzz/SfLQ81PA4dFhlBBp5NFo+FvJEf5xt/ONE72TRU59nis92nne/iH0p93L5VcNU
+ 2Ot909jp0ZmyWa85mbnNN/fmC956vlNdYFh4v9j1PnvJfplvefHD1Y+xn3RW8Cvjqw2f
+ y79c/7r23Wvt+YbWj4LN6Z9y2wU7O7/yLwA1wQ4oBtQDdDrGBMuEfYW7RpFN6U9li9ej
+ liOI0QjRitJJ0SswGBDtGAOZUpmrWPpYl9jpOTQ4yVwl3IM8O3zK/OECVwTfC0uI+IjW
+ ii1JSO4Jlbyxd0NaU+ao7H15vIKpYo7SiApR1UItZ1+/BlZTUytSu1bnhR5eX9XA3TBj
+ f73RgPGiKXyAxUzEXM5C1VLVSs5a0IbG5pvtc7tu++qDmQ6BjtaHlJw4nHYOzzr3udS4
+ prt5uGuROElrHiOe9V5p3s4+SmQ68oLvbb8i/8AA/UD2wA9Bt4NzQhxD+UMXw5rCoyJU
+ I35GdkUlRWvFoGMexJ6Is4gnxo8nFCUeQlbWlSO9RyuSU1ICUx3TDNPlj/Edpz6+ljGb
+ OZh1M/vcieM5obmHT5rmaeYrnNpbIHqav5CziKWY/gxVCbpkq/Rr2dLZ6fLJipFzw+fH
+ K19XLVWv16Au0tSy1Qlekq7fd9mgwfyKQ6NnU+TV7Obaa33Xp26stkCtdG187XK3DDoO
+ dQZ3pd8u7a6709BT3XuyL/yuzT3Z+/T3Vx88QdamioG0Qb9HlkPKj/mG8cPrI3Ojj8aa
+ nxSNJ0yQJk2eyj/jeo55vvziyctbr6qmTryOnw6e8ZsNmAt/kzCf/jbvXenChcWm9+1L
+ vcuPPrz4uL6islr9Recb/vvX9YUfo1uV2w5/8s8JnYBF4QFUAJoDPYBJxmpg13GdFMco
+ Hajk8DT4BeqHhGs05bQn6FLoYxkiiTGMMUwJzOksuaxn2RrZ+ziecn7kJvAI8urwufKn
+ CFQJ3hVaFKERlRGzFY+TqNjTJ7koRS+tJOMoGydXLn9bYUpxW5lDRUXVSo28L1E9T6NK
+ 86pWh/ZdnX7dQb0B/fsGtw2v7a80yjQONDEx5TX9euCeWZE52ULFEmc5YXXBOsxGy5ba
+ dtKu2j74oJoD1mHYseSQp9Nep++Hu5zTXcxcia6TbiXIOsFDmvY45+nqxeP12vucjyuZ
+ hzzle9bPwZ/oPxSQEagfBAXdCg4PEQl5Gno8TCnsXXhhhF7E58hzUWZRm9F1MXaxcGxj
+ 3KF4THxTwqFETGJTkvMRxiMjRwuTPVOUU2lS59M60wuO+R3XzmDJ+JB5J6sg2+uEUg5V
+ znRu68n8vNB861MKBWwF26ffFPYXNRafOhNZ4lCqWsaO7Jbj5TcqSs+dOJ9emVqVVn3s
+ wrGatIsJtQF1By/p16tdVm8wueLWGN9UfPV686Nr89c3b9K3CLfua7Ns976V2HG681JX
+ x+373f13Hvbc7b3T13m39d61+w0PLj6s6D8zkD+Y/Sh9KOVx2nDeSO3ow7HVca4Jo8nI
+ p5XPhp5vvBR8ZT2V+3p6hjzH+ubbO8xi4nLv6ql1wd38/+aWdvcErCIANQjvYXcEAEtE
+ U2sJgFABQnG0AWBBAMBGBcB+aQCmXwJQmejf+wcE0AgDR4dUnAJACqgjzMYhhEtIBPmg
+ BtwCI2ARqRfZIXnIHPKDjkEXoF5oFoZhAVgfqfSy4Eb4CfwDqef2o0JQJag+1CdkDhqi
+ I9BV6DEMCiOPVGQlmCEsCquCDcbWYmdxnLiDuALcKAU9hSXFKYpxSjZKF8oayo9UylQp
+ VMN4bnwgvpuakdqX+g6BgxBFGKdRpDlDs0PrTTtKp013jV6cvoZBhKGRqEYcZHRh/Mp0
+ glmceYAlmJWFtZcthJ2ffYLjBOd+LizXPe5MHkteTt4PfH38VQJZgrFCAcIeIi6izmKu
+ 4p4SAXtiJDP2lku1S0/KvJf9KPdG/olCr+JNpSvKl1TqVC+pNe1rVe/TGNOc19rQodUV
+ 0zPQ9zbIMry6/4UxzkTW1P5AqFmKea5FuWWL1QsbSlsNuyhkv/vsKH8o2umOM8HFybXO
+ bZnE5aHpae8V4H3cp5n8wU/JPyPgdZBi8MmQj8j+1hzJFBUe3R/LEuccX5uwk+RzZCbZ
+ LeV1mkP6+HGHjK2shZycvLMF7IXGxcElxWWt5UPnZiq/X6C5KFZnUh/d0N7E3Vx5Q6Kl
+ vG2nw6nr1h3e3sy7Gw98+sceyT/OGpl7cmBi6Jnri42pohnluddvUxc2l/iXtz9Wrwiu
+ Vnxh+1r5XWPt3Ubxps7W1Hbor/UDQjgHPCACLoSBVUL4HntARliFPHARdIEJ8AmiQjgC
+ HcgFSoTKoS5oGsm9MGwMB8OFcBf8FkWHUkV5ovJQt1Ef0JzoA0iFfhX9BsOGMcOkYTqR
+ 6lsa64/k/S1OCOeFq8UtUUhRRFB0UmIpLSjPUr6nUqXKonqNl8dn4d9Qa1Kfpf5JcCXc
+ pZGkKaLF0EbSLtGR6Kbp3enfM8QQaYmXGA0ZF5iymGWYn7Oks8qzvmUrZbfhoOMY5Szm
+ cueW4gE847wNfBn83gLGgjJCHMIUwpsiX0W/im1JEPYISGrsdZXKkG6TeS/HKW+hkKU4
+ qEyvYq96Rm1MHdIQ1jTQ8tI+rtOgO64PG8gaeu0/azRpwmxqd6DQbMyCxtLQKsm63WbN
+ TtE++mCnI+aQhVPF4c8uxq7Vbj9Jlsg69d5bzieBPODH5R8ScC+IKzgyZCxMPrwoYivK
+ JborljUuMP5eokBS5pH1ZN+UV2kW6b3HlTIasvizS3JYcivyVPM/FLQWFhUnl4SUuZQb
+ n5Ov5KmmubBz8XPd2/qnDQ8aO662Xbtz43HLq7alWxtdVN28Pap9B+/FPCjtbx8cHnox
+ /HR08EnHxOWnZ5/nvTw2lTQdMxv1Jvpt3EL0+8PLzB9qPrGskFerPo9/WfvG8l1uzWI9
+ bOPMj0dbuJ+W29V/8o8FBMCCPP0yQAfhl3xAAihAOKT7YBbsQFzQPugwkvvz0D3kLZMB
+ VoVJ8Am4FZ5HEVHaCHNThZpAUyLsYgT6Mnoew4M5hCnGTCCMiz22BDuFE8D54q7htimM
+ KYopFhDG5ATlHJLzAqoVvDm+iZpIHUM9SzAjdNJI01yg5aEto+Omq0Z4iz4GFyKM5Nue
+ Ccd0izmcRZplhfU6WwK7EQcrxzJnH9c57iQeEq8pnwq/uACfII8Qn7CYiKKokZiLeIxE
+ 0Z52yVkpBmljmXTZXnmMgqVigzJRJUl1dR9ZfUHTX+u7Troep367oYsR3rjDlGyGMc+y
+ BFZB1q9szex6kD2p9ZCKU7ezmcuMWzSJ1qPKS967m2ziO+lPClgNOhrCFNoYfiBiJepM
+ jHEcFN+aSEraPpqTwppamS55rDPDJnM9+0pO4EnxvLFTvgVfCiOKvp2JKtkqSy9nrKg5
+ r1Y5Vh1QQ3Wxtm7/pcXL2VfkG99cPX/N/4ZeC38bun2xY6Srs7uhp7Kv5F7Bg7z+3MHc
+ oazhhFHnJ9Lj3yabnwW8EHv5durCtNes+NzqfMe7tEW996vLxz98/mS0kr3a8vnVl+Wv
+ G9/mvj9cy1/ft/52I3Vj40fgj7nNg5u3txi3yFtdPxl/kn92bVNsW2wXb7/eEdkJ2mnZ
+ zX+Yl5zs7u4BIGodhH6c2tn5IgwALh+An3k7O5uVOzs/q5BiA/kG0u3/+3vFrjEW4dzL
+ bu2i/3T8D+gdk/4KZW5kc3RyZWFtCmVuZG9iago1NiAwIG9iago1OTUzCmVuZG9iago0
+ MCAwIG9iagpbIC9JQ0NCYXNlZCA1NSAwIFIgXQplbmRvYmoKNTcgMCBvYmoKPDwgL0xl
+ bmd0aCA1OCAwIFIgL04gMyAvQWx0ZXJuYXRlIC9EZXZpY2VSR0IgL0ZpbHRlciAvRmxh
+ dGVEZWNvZGUgPj4Kc3RyZWFtCngBhVTPaxNBFP42bqnQIghaaw6yeJAiSVmraEXUNv0R
+ YmsM2x+2RZBkM0nWbjbr7ia1pYjk4tEq3kXtoQf/gB568GQvSoVaRSjeqyhioRct8c1u
+ TLal6sDOfvPeN+99b3bfAA1y0jT1gATkDcdSohFpbHxCavyIAI6iCUE0JVXb7E4kBkGD
+ c/l759h6D4FbVsN7+3eyd62a0raaB4T9QOBHmtkqsO8XcQpZEgKIPN+hKcd0CN/j2PLs
+ jzlOeXjBtQ8rPcRZInxANS3Of024U80l00CDSDiU9XFSPpzXi5TXHQdpbmbGyBC9T5Cm
+ u8zuq2KhnE72DpC9nfR+TrPePsIhwgsZrT9GuI2e9YzVP+Jh4aTmxIY9HBg19PhgFbca
+ qfg1whRfEE0nolRx2S4N8Ziu/VbySoJwkDjKZGGAc1pIT9dMbvi6hwV9JtcTr+J3VlHh
+ eY8TZ97U3e9F2gKvMA4dDBoMmg1IUBBFBGGYsFBAhjwaMTSycj8jqwYbk3sydSRqu3Ri
+ RLFBezbcPbdRpN08/igicZRDtQiS/EH+Kq/JT+V5+ctcsNhW95Stm5q68uA7xeWZuRoe
+ 19PI43NNXnyV1HaTV0eWrHl6vJrsGj/sV5cx5oI1j8RzsPvxLV+VzJcpjBTF41Xz6kuE
+ dVoxN9+fbH87PeIuzy611nOtiYs3VpuXZ/1qSPvuqryT5lX5T1718fxnzcRj4ikxJnaK
+ 5yGJl8Uu8ZLYS6sL4mBtxwidlYYp0m2R+iTVYGCavPUvXT9beL1Gfwz1UZQZzNJUifd/
+ wipkNJ25Dm/6j9vH/Bfk94rnnygCL2zgyJm6bVNx7xChZaVuc64CF7/RffC2bmujfjj8
+ BFg8qxatUjWfILwBHHaHeh7oKZjTlpbNOVKHLJ+TuunKYlLMUNtDUlLXJddlSxazmVVi
+ 6XbYmdMdbhyhOUL3xKdKZZP6r/ERsP2wUvn5rFLZfk4a1oGX+m/AvP1FCmVuZHN0cmVh
+ bQplbmRvYmoKNTggMCBvYmoKNzM3CmVuZG9iagozMiAwIG9iagpbIC9JQ0NCYXNlZCA1
+ NyAwIFIgXQplbmRvYmoKNTkgMCBvYmoKPDwgL0xlbmd0aCA2MCAwIFIgL04gMyAvQWx0
+ ZXJuYXRlIC9EZXZpY2VSR0IgL0ZpbHRlciAvRmxhdGVEZWNvZGUgPj4Kc3RyZWFtCngB
+ hVTPaxNBFP42bqnQIghaaw6yeJAiSVmraEXUNv0RYmsM2x+2RZBkM0nWbjbr7ia1pYjk
+ 4tEq3kXtoQf/gB568GQvSoVaRSjeqyhioRct8c1uTLal6sDOfvPeN+99b3bfAA1y0jT1
+ gATkDcdSohFpbHxCavyIAI6iCUE0JVXb7E4kBkGDc/l759h6D4FbVsN7+3eyd62a0raa
+ B4T9QOBHmtkqsO8XcQpZEgKIPN+hKcd0CN/j2PLsjzlOeXjBtQ8rPcRZInxANS3Of024
+ U80l00CDSDiU9XFSPpzXi5TXHQdpbmbGyBC9T5Cmu8zuq2KhnE72DpC9nfR+TrPePsIh
+ wgsZrT9GuI2e9YzVP+Jh4aTmxIY9HBg19PhgFbcaqfg1whRfEE0nolRx2S4N8Ziu/Vby
+ SoJwkDjKZGGAc1pIT9dMbvi6hwV9JtcTr+J3VlHheY8TZ97U3e9F2gKvMA4dDBoMmg1I
+ UBBFBGGYsFBAhjwaMTSycj8jqwYbk3sydSRqu3RiRLFBezbcPbdRpN08/igicZRDtQiS
+ /EH+Kq/JT+V5+ctcsNhW95Stm5q68uA7xeWZuRoe19PI43NNXnyV1HaTV0eWrHl6vJrs
+ Gj/sV5cx5oI1j8RzsPvxLV+VzJcpjBTF41Xz6kuEdVoxN9+fbH87PeIuzy611nOtiYs3
+ VpuXZ/1qSPvuqryT5lX5T1718fxnzcRj4ikxJnaK5yGJl8Uu8ZLYS6sL4mBtxwidlYYp
+ 0m2R+iTVYGCavPUvXT9beL1Gfwz1UZQZzNJUifd/wipkNJ25Dm/6j9vH/Bfk94rnnygC
+ L2zgyJm6bVNx7xChZaVuc64CF7/RffC2bmujfjj8BFg8qxatUjWfILwBHHaHeh7oKZjT
+ lpbNOVKHLJ+TuunKYlLMUNtDUlLXJddlSxazmVVi6XbYmdMdbhyhOUL3xKdKZZP6r/ER
+ sP2wUvn5rFLZfk4a1oGX+m/AvP1FCmVuZHN0cmVhbQplbmRvYmoKNjAgMCBvYmoKNzM3
+ CmVuZG9iago4IDAgb2JqClsgL0lDQ0Jhc2VkIDU5IDAgUiBdCmVuZG9iago0IDAgb2Jq
+ Cjw8IC9UeXBlIC9QYWdlcyAvTWVkaWFCb3ggWzAgMCA2MTIgNzkyXSAvQ291bnQgMSAv
+ S2lkcyBbIDMgMCBSIF0gPj4KZW5kb2JqCjYxIDAgb2JqCjw8IC9UeXBlIC9DYXRhbG9n
+ IC9PdXRsaW5lcyAyIDAgUiAvUGFnZXMgNCAwIFIgL1ZlcnNpb24gLzEuNCA+PgplbmRv
+ YmoKMzkgMCBvYmoKPDwgL0xlbmd0aCA2MiAwIFIgL09yZGVyIDEgL0VuY29kZSBbIDAg
+ MTM2NCBdIC9GdW5jdGlvblR5cGUgMCAvQml0c1BlclNhbXBsZQo4IC9EZWNvZGUgWyAw
+ IDEgMCAxIDAgMSBdIC9Eb21haW4gWyAwIDEgXSAvUmFuZ2UgWyAwIDEgMCAxIDAgMSBd
+ IC9TaXplIFsgMTM2NQpdIC9GaWx0ZXIgL0ZsYXRlRGVjb2RlID4+CnN0cmVhbQp4Aa3B
+ BwKBAABA0ftfSTRUtDWMFu00dQV34L+3bT/6bB/OylmWdaHMy8yZpnmijNPIGUDv4c3p
+ QV3fUdqu5TRN21DqpuZUVV1RyqrkFKBX8eI8Qfkzp2R5xknTLKUkacKJ4ySmPOIH5w66
+ 3W+cKyi6RpQwCjlBEAYUP/A5F5B38TguyHEdjg2ybItiWibIMA3K2ThzTiD9pHM0kKqp
+ nCNIOSoUWZFBkixRREnkHED7w54jgHbC7n9fqv5GzAplbmRzdHJlYW0KZW5kb2JqCjYy
+ IDAgb2JqCjE4OAplbmRvYmoKMzggMCBvYmoKPDwgL0xlbmd0aCA2MyAwIFIgL09yZGVy
+ IDEgL0VuY29kZSBbIDAgMTM2NCBdIC9GdW5jdGlvblR5cGUgMCAvQml0c1BlclNhbXBs
+ ZQo4IC9EZWNvZGUgWyAwIDEgMCAxIDAgMSBdIC9Eb21haW4gWyAwIDEgXSAvUmFuZ2Ug
+ WyAwIDEgMCAxIDAgMSBdIC9TaXplIFsgMTM2NQpdIC9GaWx0ZXIgL0ZsYXRlRGVjb2Rl
+ ID4+CnN0cmVhbQp4AaXChVJCUQBAwb+2u7u7sekGFQMDW7ED61OOMTL48MWNnU1+kLSY
+ +OD7u+L4O8XfiAuPvWH3lZjt6CsSX4gaR15QnCOSI6w9lCP0rD74jOETQZmBJ+w+ErDt
+ f0T0A/5/fQ+ovMf303uPZs8dOt13GN7ilrl6i+UbVp2u3CD0mhWzy9dIv2I5f+kKzYtZ
+ dC5kKbxkQfL8JeYvmBfoukDoOS6zc+dIP2Muf/YMrafM6J0+5fcJ0/KnTjB/zJTAyWOc
+ HzFpceIIuYdM/Dl+iPoM4xnG9I5m+H3AqPyRA0zuMyJ2eB+HewxbH9pD4i5DxoO7qE8z
+ mGZAb3+a7zuK+3Yovk2f8N5tHG7Ra71nC4mb9Bh3b6I4RffPrhQ6O1N0bqjv2KD4Oh3C
+ 29exu0a77bY1RCdp+7c1icoErfktCXQ2J2iOq2+KYxijSWZjDMtRGp02RBEaocFsfQSV
+ Yerz68LorA2hsyZEYZAaydVBLAeodloVQKifKrOVfqT7qPyzwod6L+V6y7wUeiiTXOrB
+ vJtSgSVuvn4CXuWIVQplbmRzdHJlYW0KZW5kb2JqCjYzIDAgb2JqCjQxMAplbmRvYmoK
+ MzcgMCBvYmoKPDwgL0xlbmd0aCA2NCAwIFIgL09yZGVyIDEgL0VuY29kZSBbIDAgMTM2
+ NCBdIC9GdW5jdGlvblR5cGUgMCAvQml0c1BlclNhbXBsZQo4IC9EZWNvZGUgWyAwIDEg
+ MCAxIDAgMSBdIC9Eb21haW4gWyAwIDEgXSAvUmFuZ2UgWyAwIDEgMCAxIDAgMSBdIC9T
+ aXplIFsgMTM2NQpdIC9GaWx0ZXIgL0ZsYXRlRGVjb2RlID4+CnN0cmVhbQp4AY3CCTdU
+ cRgH4C8mEolEIpGSkpKSEolEIhljxqxmDGNm7Pu+71tf6/29neuY073jf+99n/Pw3wTb
+ jPOlcIwvTV7E2HCMLySjfKF7HmXTo3wuOcJnwhE+M3kaYcNhPpUM86nuSZhNh/hE8DjE
+ x0OyQT42eRRkwwAfCfv5KPnQz6Z9fCh44OMDr7iHD1T3PWw4yPvCbt5P3nOzVRfvXcee
+ S33Xhd0BcSd2VXecSN2PHUkHdq5uO2CzD9t2t/qg/SPbiy3VzV6k/o1N4R5s9mDDdjc2
+ 7K53Q/tLtgvrqmtdSP0Ta8KdWOvEqu0OrNpd6YD2h3g7Vm5cbkfq71gWbsNyG5YkW7Fk
+ ebEV2m/iLVg0XmiB+lcsSDZjoRnzkk2YtzzXhOtfMCfZiDnj2Uaof8as8CfMSDZgxvJ0
+ A65/xLRwPaZ1p+qh/gFTwu8xKVmHSfMTdfj/HSaEazGhO14L9bcYF36DhHANEoqUqKG4
+ /muKC1dTXDdWTaZfUUzyJY0JV9GYyWgVGb6gqGQlRXVHK8n0cxqVHXlGohU0YjJSQYZP
+ KSJcTpHk4XIyXUbDguEyCj8RL6WwaqiUDB9TSLiEQslDJWS1mIbsBosp+Ei8iIKqgSIy
+ fEgB4UIKJPsLyWoB+e36Csj3QDyffKrefEp9n7ySeeS96skjm7nksTuYS9p7sjk0qOrO
+ odR3yS2cTe5sctnOIpfdgSzS3hHPpIEbnZmU+jY5hTPImUH9kunUb9mRTtpb4mnkSPsH
+ inMKnAplbmRzdHJlYW0KZW5kb2JqCjY0IDAgb2JqCjU3MgplbmRvYmoKMzYgMCBvYmoK
+ PDwgL0xlbmd0aCA2NSAwIFIgL09yZGVyIDEgL0VuY29kZSBbIDAgMTM2NCBdIC9GdW5j
+ dGlvblR5cGUgMCAvQml0c1BlclNhbXBsZQo4IC9EZWNvZGUgWyAwIDEgMCAxIDAgMSBd
+ IC9Eb21haW4gWyAwIDEgXSAvUmFuZ2UgWyAwIDEgMCAxIDAgMSBdIC9TaXplIFsgMTM2
+ NQpdIC9GaWx0ZXIgL0ZsYXRlRGVjb2RlID4+CnN0cmVhbQp4AbXCiVYBUQAA0O8y++pL
+ s0WWyCCSdQahlMqSLUspwhd06uQ4ozHmzbx3zy1t7KVjlY0d+NquGC0qa1V5LR65EmV4
+ iytR9UssIroUi0uxALlQWP5eCAWt+YUA4aeQNzb3KYD9EHIWZj8EvXMhq5fPzsFm5vzu
+ O59B943PvPHXKM7468PTM95wLj37d8qlQV5NOYAT7sra1ITTPuZSCCbH3M9XzWzyFcYR
+ m9y+HLEwD9lL3Ykha/6ATQCOD9htJj7Q3Wfilsf6jMYeE0NT6jHSC8pdRvpLS106CneH
+ juq+6NAmt+kL8JE2bWiLjgCnIq394Ral8ZkKo3n+RCH8SJ2rhx4paJtk6NhgkzTzgQya
+ Gnggj78nA5D678n9DdJvKOFvAD+7I1C9Jc60+m4JCOuEz1hvnTAW99a3a7jX7NMarreK
+ n0LtqeK7N7gH3QruqeDugzF3xewy5j7QVcasLmEuw50lDKyCOS10KNi2zaGoyzYH7Cey
+ 7W/RdgLyGwqvtaMKZW5kc3RyZWFtCmVuZG9iago2NSAwIG9iagozODQKZW5kb2JqCjM1
+ IDAgb2JqCjw8IC9MZW5ndGggNjYgMCBSIC9PcmRlciAxIC9FbmNvZGUgWyAwIDEzNjQg
+ XSAvRnVuY3Rpb25UeXBlIDAgL0JpdHNQZXJTYW1wbGUKOCAvRGVjb2RlIFsgMCAxIDAg
+ MSAwIDEgXSAvRG9tYWluIFsgMCAxIF0gL1JhbmdlIFsgMCAxIDAgMSAwIDEgXSAvU2l6
+ ZSBbIDEzNjUKXSAvRmlsdGVyIC9GbGF0ZURlY29kZSA+PgpzdHJlYW0KeAGtwQcCgQAA
+ QNH7X0k0VLQ1jBbtNHUFd+C/t20/+mwfzspZlnWhzMvMmaZ5oozTyBlA7+HN6UFd31Ha
+ ruU0TdtQ6qbmVFVdUcqq5BSgV/HiPEH5M6dkecZJ0yylJGnCieMkpjziB+cOut1vnCso
+ ukaUMAo5QRAGFD/wOReQd/E4LshxHY4NsmyLYlomyDANytk4c04g/aRzNJCqqZwjSDkq
+ FFmRQZIsUURJ5BxA+8OeI4B2wu5/X6r+RswKZW5kc3RyZWFtCmVuZG9iago2NiAwIG9i
+ agoxODgKZW5kb2JqCjM0IDAgb2JqCjw8IC9MZW5ndGggNjcgMCBSIC9PcmRlciAxIC9F
+ bmNvZGUgWyAwIDEzNjQgXSAvRnVuY3Rpb25UeXBlIDAgL0JpdHNQZXJTYW1wbGUKOCAv
+ RGVjb2RlIFsgMCAxIDAgMSAwIDEgXSAvRG9tYWluIFsgMCAxIF0gL1JhbmdlIFsgMCAx
+ IDAgMSAwIDEgXSAvU2l6ZSBbIDEzNjUKXSAvRmlsdGVyIC9GbGF0ZURlY29kZSA+Pgpz
+ dHJlYW0KeAGNwgk3VHEYB+AvJhKJRCKRkpKSkhKJRCIZY8asZgxjZuz7vu9bX+v9vZ3r
+ mNO943/vfZ/z8N8E24zzpXCML01exNhwjC8ko3yhex5l06N8LjnCZ8IRPjN5GmHDYT6V
+ DPOp7kmYTYf4RPA4xMdDskE+NnkUZMMAHwn7+Sj50M+mfXwoeODjA6+4hw9U9z1sOMj7
+ wm7eT95zs1UX713Hnkt914XdAXEndlV3nEjdjx1JB3aubjtgsw/bdrf6oP0j24st1c1e
+ pP6NTeEebPZgw3Y3Nuyud0P7S7YL66prXUj9E2vCnVjrxKrtDqzaXemA9od4O1ZuXG5H
+ 6u9YFm7DchuWJFuxZHmxFdpv4i1YNF5ogfpXLEg2Y6EZ85JNmLc814TrXzAn2Yg549lG
+ qH/GrPAnzEg2YMbydAOuf8S0cD2mdafqof4BU8LvMSlZh0nzE3X4/x0mhGsxoTteC/W3
+ GBd+g4RwDRKKlKihuP5rigtXU1w3Vk2mX1FM8iWNCVfRmMloFRm+oKhkJUV1RyvJ9HMa
+ lR15RqIVNGIyUkGGTykiXE6R5OFyMl1Gw4LhMgo/ES+lsGqolAwfU0i4hELJQyVktZiG
+ 7AaLKfhIvIiCqoEiMnxIAeFCCiT7C8lqAfnt+grI90A8n3yq3nxKfZ+8knnkverJI5u5
+ 5LE7mEvae7I5NKjqzqHUd8ktnE3ubHLZziKX3YEs0t4Rz6SBG52ZlPo2OYUzyJlB/ZLp
+ 1G/ZkU7aW+Jp5Ej7B4pzCpwKZW5kc3RyZWFtCmVuZG9iago2NyAwIG9iago1NzIKZW5k
+ b2JqCjMzIDAgb2JqCjw8IC9MZW5ndGggNjggMCBSIC9PcmRlciAxIC9FbmNvZGUgWyAw
+ IDEzNjQgXSAvRnVuY3Rpb25UeXBlIDAgL0JpdHNQZXJTYW1wbGUKOCAvRGVjb2RlIFsg
+ MCAxIDAgMSAwIDEgXSAvRG9tYWluIFsgMCAxIF0gL1JhbmdlIFsgMCAxIDAgMSAwIDEg
+ XSAvU2l6ZSBbIDEzNjUKXSAvRmlsdGVyIC9GbGF0ZURlY29kZSA+PgpzdHJlYW0KeAGl
+ woVSQlEAQMG/tru7u7HpBhUDA1uxA+tTjjEy+PDFjZ1NfpC0mPjg+7vi+DvF34gLj71h
+ 95WY7egrEl+IGkdeUJwjkiOsPZQj9Kw++IzhE0GZgSfsPhKw7X9E9AP+f30PqLzH99N7
+ j2bPHTrddxje4pa5eovlG1adrtwg9JoVs8vXSL9iOX/pCs2LWXQuZCm8ZEHy/CXmL5gX
+ 6LpA6Dkus3PnSD9jLn/2DK2nzOidPuX3CdPyp04wf8yUwMljnB8xaXHiCLmHTPw5foj6
+ DOMZxvSOZvh9wKj8kQNM7jMidngfh3sMWx/aQ+IuQ8aDu6hPM5hmQG9/mu87ivt2KL5N
+ n/DebRxu0Wu9ZwuJm/QYd2+iOEX3z64UOjtTdG6o79ig+DodwtvXsbtGu+22NUQnafu3
+ NYnKBK35LQl0NidojqtvimMYo0lmYwzLURqdNkQRGqHBbH0ElWHq8+vC6KwNobMmRGGQ
+ GsnVQSwHqHZaFUConyqzlX6k+6j8s8KHei/lesu8FHook1zqwbybUoElbr5+Al7liFUK
+ ZW5kc3RyZWFtCmVuZG9iago2OCAwIG9iago0MTAKZW5kb2JqCjIgMCBvYmoKPDwgL0xh
+ c3QgNjkgMCBSIC9GaXJzdCA3MCAwIFIgPj4KZW5kb2JqCjcwIDAgb2JqCjw8IC9QYXJl
+ bnQgNzEgMCBSIC9Db3VudCAwIC9EZXN0IFsgMyAwIFIgL1hZWiAwIDczMyAwIF0gL1Rp
+ dGxlIChDYW52YXMgMSkKPj4KZW5kb2JqCjcxIDAgb2JqCjw8ID4+CmVuZG9iago2OSAw
+ IG9iago8PCAvUGFyZW50IDcxIDAgUiAvQ291bnQgMCAvRGVzdCBbIDMgMCBSIC9YWVog
+ MCA3MzMgMCBdIC9UaXRsZSAoQ2FudmFzIDEpCj4+CmVuZG9iago3MiAwIG9iago8PCAv
+ TGVuZ3RoIDczIDAgUiAvTGVuZ3RoMSAxMTg3MiAvRmlsdGVyIC9GbGF0ZURlY29kZSA+
+ PgpzdHJlYW0KeAG9egt4U1W28N7nmZwkbR7Ns02TNGnTR/qkDwKFnpa+oA2UlkKLrbSU
+ MoUBLFjLS5gOoIWiI86MgsiML3QUBw3FwaADl8utIz64F0UvPhD1iq/RiuNUUSEn/9on
+ pUI/v/n8vt9vzsk6a7/O3muvvfZaa6+TnlU3dSIN6kM0qpvf3r0YyVfGlwhR3R3L27uj
+ eUMd4Jc7enuc0TybihB96+LuXyyP5hVBhATPL5atHX0/rgUhs7qrs31RtB5dBlzYBQXR
+ PM4H7Ola3rMmmte/BvjmZTd0jNbHJUBeXN6+ZnR8dBbyzhXtyzuj7TNOAE7tvuHGntF8
+ F+C27lWdo+1xE9D3PwhDqQMtRUq0DCkQhbRwA2X8J4IHMVBL6gFKMxvvXxBb/DXSKeTu
+ HvRm9ZHE31x//e7i2cte1UZlJbRTyu1JBbzDpUlpCKkx1L+t2jhWQ2rJ5Qih+owQqgaY
+ CpAPkJ5xQCE+g3eguNYRUYkdDFI53rB+cRRnAf8/kp9BnCWqNUjZsbnY0bF5c3VaqRLX
+ oCIGIweuQB4Zlw96HneE8NRBjxvQlCiiBovskEOissjjCBctdFwuCimwGO/41vM7x0WA
+ bzwljq89uY5XoN2poirHyVKoH3S8lB6iAL3oCTFYjHWc8Pza8ZeiNMdTRZMdg14oG3Qc
+ KAV0yLG36NeOh7bIJQ+my+gBTwjvHnTcT9Ahx33Q/92b5Yq7oi9uiqLuLfJANxyU0YqD
+ IerxQ47lnhTHQngRiypHq2eZo8Xjd8wpDeHkQUeAvHbIUes96aghQw86xOhAhdHeCzwy
+ xXnRYX2eZx2p0RGSSGvR4HB6ah126N93/90On+d6R2l6CD/6dHVquqfae3dhCI/IYxAE
+ hBK0Ioo6vEfwn1AVSsPzUTK+52B1GtCMdww6NgPafbA6tSg5RH8i6h0HvdXeLQCFAMkA
+ jSE8R/TxO/lFfCM/gc/g0/gU3sUn8vF8nEKv0CpiFGqFoFAoOAWjoBRIEReKvCdmECmK
+ 47QEcQx5MnJaS5E0POCJKKyg0AwU4tAtpt4SS4l+qs5fWf4jjza5sK0844fL8kMyw4Lt
+ wbtrGpqC++zNwTySiNibr6r//0l2lsHbNfVrD9av/WxuRae7os1d0QnQFtze22UJ9i10
+ Og98tpZUOIN0StvCji6C2zuDa92d5cHP3OXOA/Xye+Oq55Lqenf5ATS3Yk7TgbliZ/lg
+ vVhf4W4vbz5YV1E985qxto2NVV3xI2NVkM6qyVh18nvjxppJquvIWDPJWDPJWHVinTxW
+ RkbFkoYyxB5DOvY4ymR3IjtThuwIRd4CeJtgqSFygT2FhEg4MkyDZsNJBN69hOPQk4hH
+ T6ONoG1eRfuwErnRMM5Db2I7TkdvIAm9jf4P2dB2dD88K9An+BvQMp/iVGhTiDahP6L7
+ It2oG5XA/QlmkRFNRJ9G1kdORL5DZWgADWEeG7A9chhlo364d6M9WE0tjBxAFlSLVoNW
+ 34ReQG9FBiN/h/4L0YdYh7OZyZF3QMBYKPGjbWgfehq7sBun4+siH0K5BWhsQfsigUgv
+ vHcBWmWjmWg9jPY+duAUnIF343P0cKQv8huYWwLUNaIOuJejX6NdaA/aL7dayCSwRui/
+ HNVA3W/Qy+gT9BUo3DRchtdQr9N/p79kJjO7I0NARyOM14buwzRwxYMb8SLcjffjp/B/
+ 4W+oIqqd9tOvM93MA0BbI9qKHkBH0PPoNHoHfYaG0fcojBmgaSqehdfjP8B7/0dNoFqp
+ DdRt1FvUBTqXPsfwzHb2FvbZCBN5PfI90JyI0tFk2OmzURPqhHsxWoFuQr9CWzCPdqID
+ 6L+A2nfRu1jAWpyNc3EVnoOvw7/Ea9GdeC9+Bp/F5/FH+FOgzkA5KDeVTfXCeJuobdR+
+ apA6TA3TOrqH3kAfo8/R3zBGppU5Bve7bCbbwyVwNfxs6ffSu5HMyI7IblgXE9welIYy
+ 0VTMABeXoy2wktuAZ3vQXvQ4egINosHIJexHQ+gVoOt9dAFdhBVLgNuF8/BEXIdnA4XL
+ 8HL8K7wLKNyHDwGVz+Jn0Rl8Bl+CW0JWSkllUtdR7dRauHejXdRpmT9q2kWn0pl0Dd0Q
+ +Qe9nz5Af8UkM/OZlcx6ZoDZxdzHJrBT2HnsfLabvYs9xL7E/i97gR3h7Fw/t5d7ijvN
+ K/h8fhcv4SSgxYmT0VPoKEjd3XQ35D1oGt4CqzoXvQzSO4yeQ5fQd+gY+hO2I4kmq5kS
+ eQCFIlthNY+gv9A3o2J0J/U7akakhH6UVuK8yEXoKwfW68qNxPS0VG9Kssed5HI6Eu0J
+ 8TarxWwyxhn0Om1sjEatEpQKnmMZmsLIV+GubHMGU9qCTIq7ujqT5N3tUNB+VUFb0AlF
+ lde2CTrJe+1QdU1LEVouHtdSjLYUx1pirbMYFWf6nBVuZ/BkudsZwvNnN0H69nJ3szM4
+ LKcDcnqHnNZA2uWCF5wVlq5yZxC3OSuClb1dAxVt5Zk+fFgEYyBk+tBhhESkIh0H0bT2
+ DaBc0TTSoiJoc5dXBK1uSEMdnVzRvihYN7upojze5WrO9AXxtA73wiBylwVjM0ZfJ++B
+ Ekyub4KxM31LgkA/2q5e5F60PSSihW0k1d7SFKTbm4NUGxlDlxE0u8uD5nUfWn7IXklV
+ 3HZVZZBKrmzvHKgMim3bgekk20Zy7bdBrqbBCd1StzQ3BfEtQBwhQqY9OouomUhuW+oM
+ Kt1l7q6BpW3Ac1TXNGgTbRXutvLmIKpvGrSKVjmT6Tts2TjZBUw5nFmaWUrwZJdlYxR/
+ vDla/uoxgi0bh94DXFM/xhdMxnZPBzKDzg4YBHgBtE4kj86JaKBjIrAPrmYMs1wC9EwL
+ UiBKdHKQTZ7eHuxrGCWjvat8lLil5YNKq022S2XN0L5tQDsJFhDaa93Oga8RrKx7+PNr
+ S9pHS7hk7deIVJL1HxOhIG6/ku4l9jMZTFKXxd1Flq9XXmrIuy0VVxVAntitTHA4fTUh
+ pKxrOoDxb5pDOHJLCJXbD4OBoRdcD9UZROCWlMNwkPH5oCDdBSmgoBIGqiSS4RxwDkxf
+ NOCsdHaBSDHJMoaKzoHmbGBYQxOwBc1pcgXF5vixZGdz8yToJ4v0A69A84Fm6GHpaA+A
+ 5aLsMDTK9tXArFLqmmY3BfvK44NieTMwHYT4WF1T8BjIb3MztMoZoxQo3rDEMkpzLtCc
+ kw71edFewK3pgy6aBwZInw1Nblfw2MBA/ADZddE8eMjjC8TRghAiTQiHQ7ivDt4F5HbF
+ yyx3uV1AVjPh6QQQ4CsCBG79v+ZwwRjd8GYhUFsgc7joZ+LwxJ/CYf9P4vCkMUqv4fBk
+ oHkS4XDxv4/DU67h8NR/zeGSMbqBSBGoLZE5XPozcbjsp3B42k/icPkYpddwuAJoLicc
+ rvz3cbjqGg5X/2sOTx+jG4icAdROlzlc8zNxuPancDjwkzg8c4zSazg8C2ieSThc9+/j
+ 8OxrOFz/rzncMEY3EDkHqG2QOdz4M3F47k/h8LyfxOGmMUqv4XAz0NxEODx/jMNifBBd
+ rYf7xqld9LMr5uuuYjn7PNpN+eH4vA+1Ahgh3Qdl+QAt7Fz0MPMB2gPph5gb0WRIrwdc
+ BbgEcDbgMmi/DUAJ+U28HfVBWT8pB9hA29EmKC8j/ZI8pG2cH8UQDGAEXy0aV4LgEOLA
+ F0bIieaTw/w1FwXxtisXnP5/wsVCGw6Ah0jWj1/KHy8eLRWQCijSoBjIxwJokQ7pARtQ
+ HFBtgpQZzn5WOO/Fw6nODqckcuXDfTP6KzoH54tzlJYqowbpufQTTALTywrsFjbEXuZ+
+ y0/iB/j3FFMVW5UxyiblnwWtMFP4QnUrnNh2IwTnh+MwWx5NFV0sZwe/nOHtNBJYxk7T
+ lE3J8XaMrArlPteyYghazBwpDoSLZ2q/KQ5ow8WopDhcTCA3Z4LOpfMC7GYeCl0+yR7/
+ fmqIqb/0BKESo1apg+pk34LZVIppXjpFu5pare2n+rUco4s1xFkNMbEMa1ih/D6bvY+l
+ WJsxzvi6q+ww/jOCIbUzvwmsvBzW+f1+7XlUUpKbg1v1hsISbOZ4ThdnNjmwO8WbUtC6
+ qbqhau/2vAZn7sYpjz3YuIiegH2P3LiQkn73jXRq6OHwJ93nznwfJvQYgZ6ATE++aNHr
+ lAaj2WzTaxQGJb1C873SevXwIyNkaL0fIhPlHwXk8ZEZjjM0F4vdhUV6Xb43JRtPwNtm
+ 3bR9ZkXV6S35zYSAMywXkr6SvpBOSy880dT+xS6Mcd7QI+GPu2H8PiDiSYgx0ChFNOBU
+ WmBhfNyNrAzb7fpVlM+BsDwiKgkM5+YYXDpXH86WXsHp0v8SntKw8oh9FNaOQkR2zoq/
+ 7KKwl00VJnJFymquS1gjbGW2crvpu5hd3D76YeZRLoRDwgl8QniDfkMwYp7jKKRQKuEh
+ YJ6l4gQhWQ/ZOJZN1kMdr0gnMS5BBYc1TinQrEKlASpVAsOxIRw3qKQpQIcEq7rzplWW
+ jN6Z2hFLIOz3w0/nt8q0W7JRibk4UFJcrPf7s0FM2P6sjA3aGnAnmWPxQWaouT/LMlpA
+ QwE91KyDlvDr1xYX8wBkrVErdqngMO2Cw7ALU9m4N/Q4bqEEaXBB+P3F0lHqGTg7l+PZ
+ 308lDJI50hI5w65nL8AucaAeMW2e8Hv+9wr6Oqo5vsm+mFmNt7GPxQ0yTwt/Y55XvUW9
+ HfeO5d34by1acwirRLdNobCpSx00rS+1KR2mIrOiyJHI21yxRYlWp+se1/658j4IDMMu
+ COj8w68NwzSHS4qH9f5sLawVoVhfVOhymk1mFwimO4kyxpkm5BUVFrk45HJ6U3S45X+e
+ wibc8+cFvPRyYvachx89fvKPDzZmO3BuqvS0FJGOHzpE7WDmvXJoZNvA0sI26R/ffntx
+ qX/VP6RXXz6JO2kbyNDDsP4UzFaFskkk+xlQP0pUA5FsThtC+BR6RtZFNVChAnkhmIY4
+ V01GTi4GYbpyM+cuj1Avh/PpnEsPMX7miPR8BEm3SBehYxhjD0LMAfYYdFwkmvl0hlHS
+ 6YhSKrhebFPRimSlVVCFcMJBV/3jUZ7IqiFAdmkYuBGOCm50rD2MMWyn+sNrpf9mj0lh
+ aX8Ehe8G6X0I5rEShhMgitAkpjvd8RYj6zWkpGMIQ6SnUV67wu5MMnDmJK7IHD9Pa/Mh
+ b3KqNcMXwokw8OhijA48FB4CCYL9CpqphCxI2K8z+2FNdC7gfwFsVXehyZyIjXEcnwih
+ D9AeZiNZpGychd0yV/Ap3NqV39Kct+jtP03Kmbh03eJGhdon7Y/h1JiiOrZKx6XT1Gnm
+ uNRjSb/51ixbuLJ84tZ5S15KT9t5b0enxx+fnJs4tXTb7deHj8KsaDQ5co6ZyCwAze5H
+ k9Ad4qzJVEHhWrwNM28k4pR/fpT+sTtGw0LEz2DLgLgJk5KVkpVOCph4VVK8yTfJwacL
+ Kl+eapIhgAJZkwrSp6bYim2B+ExFoMA6ufiv2IpcqBo/QXTlzJHA8IgsmOd1/pMffihL
+ Jijok36d3kw2FiaYQMbo1orBsRj0qCyhhUXeQsIlEFme412QduVB9AZ0bCIGNmVhL7R0
+ J6UU5IMsG6hz8UU54nxv2exJLffS+2clTWmd35meKEjDyqqV2HBw+3aKTkiQXtQI9ORA
+ S8/v//Pexoe7Kb3OqFRrzd766aXL7rggxNqKpk3ISy65o2VHVdVzkjp/xsRUTbprUrKY
+ WfDYvS/MzzVi8vEJ5GR95ANmD8iiHix2mZisdKpi9Gpk9eh5leD0sCrjFsqWZHcIDo1X
+ ZXUl7XLVzRyVyZHzZKcOk00KPx1MHyQC6Y1xlDvJm+I1kmWHuU7QRwUE5k64QT/2zy/P
+ 9Nfn+qVPcUJhaWB18rpE/z33Tkq8+VfMfOnFryVpsNBZt409Fh6pTc273DN4Z0/tjttr
+ Vt8WitJbFXmLyYd1J7Z6hVhxj+lRE9WfgKcbm/Rd+jXCWn3I+LzhhFFhoTjG/irjSbTx
+ phhBrX1a7YlTJWoLYx2oMNFstzkVhWarw9nvqh6dz6jeCY/IemeY2EVQPjIma7oS9KWs
+ dcg0zKB3iNrhOZeTKtCiCXmMGdNahSunc0dBQsKE2xfNUWK3MOdW6Tvpu2+x/h8nMWuR
+ 4qlnp+SW3VG7cc30rcvmbup5Fk/8DlvxxNCneK+8FiUg052wFlqY3SzR94karInRTmlp
+ ZPZoeU6wewSVkbYZHJyD9jI2h61QY0107HJVV4zKKFmQ8Mh5WIkfVgXEE5alFZnMRGEU
+ xGB3EiIkX1kWeVWodbtzsEv6bMqenv+QLmF85umNnVPrN9y0ei3TMi9AKb4Xd7Y34YKv
+ sBmLl1c9dceJuflHbtv5F9iH2ZGzzCRYD1DBKAk9Lk6vVPTH7cT3gD3DSpbTsrYatlI7
+ 3XkrviW23yHQJtpsMBnM1YpaU615uq3F1GKebzuL32Y+tX/svOjUzsCV2q3sZi0DZvAu
+ ccKsmAUxN8TQMTHxnCfJxZv1vniViaaS6ELz+qTENnWfmlLbPJQj5q5Eq9sDrLginUQ4
+ W8GOnB/OjrLjZNSUtIL2RCtb8cpWBHsRtBMoLrh5FzxGjQnZjEinRZMxPrU8Bj/Lr79u
+ 61tVokFFhU1c++SGpqJEM3ar5t92+ZR0HDs+jKN7bl668qbPFq9o76u5fW9ZWl58Tvui
+ +7AalF88fOKEi0ZlUhlzPfBJA18WctB8UTuQCEqD9eRk83ouWeNJC+ES0Zng9FlicyiH
+ 3pHszfEZbHkJW+IzlYU+a27eVcscVUU6Pyw1aKLwyZJhfwnMTkc0cqvniqaRxVQPkytw
+ 6eJAUpM83iuTnEJ0ExjQgnz9hCLqyMDmFXf7E52T7lZN6RKxsWqd9Mgr0rcxuFAdn7V8
+ d35SWnbj1lcvfXXuur/vfPjeB2+vWbFgxgC9yppx4x8ufXP6l6G9D+WZvL8o21NZ6S7F
+ 3sv/xDV0dK9uA2O3j30JZs+jyWJSLarFLagFPl0cADXM8YISHB/EeTEPjvCgqy4qxbIj
+ TJxCsHayk0YcFR34KQD7pHdBSmVg4DOQtPoSHDUopJSq8ZPyOAY0mXyDfgbYzKBGsNoa
+ sNroVBTjsyEkjKaNZ1EIacHEG7KJBUfQOGrBcSKGvV0AeyWO6GQvflL6ANul+ZY4RXoG
+ tm86qpmQQsb+bhGF0yYz+y/NfPiP4N3DhSFqj5jl7BHwDL4UB0Wqkn2N+pBiYhWCspHd
+ xt6h+I3yOfZFxZv8u4qzSpWCs3DZdDaTymZyRfRErpau5lrpZm4pvYRbw2xldtJ38Y/R
+ TzL7uEf5Q3SI+Rv9AmOr4Wbwc9mtzGbFEHtC8Sb9JvMO/5ZCxSqVDMtyKhV8a+UhCd8C
+ BMpJ0y/pwbdQgqfJcJRSYGhO4AU4UNk0WPAilVOVoxJVjMqq1vS76j4gOuRyq3wM+QJ4
+ DwcQ2bCZ/f2BrAxG9i/XNQ8hPRg7vz+2X6sgriRIHOykla3gSWOXEtxJXufahC24A7dL
+ m/Ft0qPSpV7pE/bI5Y/wbmlBeBF+db30GOFVH9Cxh5kPX4COlwZQEawifBKGpwkgGWAJ
+ nNeWwrlsLeB1gLcBHgB8D+B7AD8GcBjgY+B2DLR3wdckGvxSDfJAnxb5mQxy54Be7WDd
+ FOAJZcNpzwzvcPBVUIlj4Q0dCqA4SCWC9bMjL2ArykLZ2A391cG3yVFTN6QdGfaPXDk5
+ FBcDdwLD2uGoDwR+KShXuI20i5xaiJU3gvxclXQZiSEEo28mmL3jNn+WVqCks3Epi3sz
+ zdL7cZ4l69LNINjGguyGLRsCU50TG5qWMfMnVvobipaGZ1OHpqbWLsyfHl5NbWv3zZqV
+ 2RzuZsT7Gj1i0YS6tsxMmH8/yF476BcTzLBGzGSxESfjItyk6lJxWK/llB5QcjGMYGYL
+ zbGUzaqL8cZaLdajV7ZdIDw06niDSoG1Hy7xy+oEgaPyI3Px0gNnpLPm9N47CxOk89hQ
+ lNvUv4RpOXAynETtnJs1Z31pZ3gQSJyTXEZ2F+g/sNt7mE5YLXLiDoipZhor1FvVW7W0
+ WWOJXayhWY8ljld5YlQWi4IqNNtsikKd1WoL4d6DY2pdNtKg6EaPBiB9q9CqlaMqT7Zk
+ HjgKoIJ88jRi6rNbb92wob9/A5UlfS59DPfnOA5MrhXHhU+/MLh374EDe/cOLpYex41f
+ fo7nS498TonAyw1SA7MbZFMDUjFDTDMbFEKCjfI4eRsneAwqa4xCY9EUam1JnCPeYfFa
+ f9Qvkq2O7BuBaxQ1wlHRiHoPBXpiYmRPidhlWUDonht/DZ5QZ3H96g12rJTCL2+am50p
+ fYR1WfkLNlP3Hf/dzDVHA5mheyi/9JF0QXpPerXUUxE+wV54oCptOrA5qoOoS0wLxARm
+ HEY0rjpIxWrgiFolWg28hlMLTiqHEimanMypGJVXDYfyEF500FW3+IqsvxY9krcS/Qus
+ fg3OXsR5AFM5KthRYql3VIb4dM2fJ7uk97G2LLeuj2nBWDpLU90lm8MXmbKjy1OnEZoo
+ WPu34ftqO8pAPrRRnKXUcilWDa1kXCpVjTBdVeUqd1annaEV9iSnWmBMGYzJ5vPpecaX
+ qvL5Yo2C024KJPHGTD6QbMtSI3sgNhMFMqyZWVd5byNwLJH90RE4O4KCAvZHhSR8UntS
+ 3qjXt16PW7Fs5mWPNBncuYJ82JbM6HlSduzkjQyq35lSgHGHMrHgjjkdqalS5HBt7fCZ
+ lzE2SB9w1uyVrbPS0yP7Guf847IU+Ro+NrfUOv15eTlW65SsivK+nW8+dKLIOWmSN9dk
+ npg6u379gyfffJSGjQAxksjfqTVsF+zTGYe0vliH2qd7Bq9EDG4RTTxq4TBngaWJ5UYY
+ pRf9FtbJEsIxB11tZHleKz4fLh4pJuvzBYRM4OQ/XAI+ABwHC0icaILRrSMn4sIiI8/B
+ 3HTGXdh24EDSPI09pv/FGTn08pdwjnTqpfCxaS6MX2f5QO5i6j4i75FPmEbQHSQOVitm
+ CSabKd000TSX7+Q5G1gMzhSjEVjwn20awWuzqGwJuNBijU/4QXmQfan3B8KvyTwnnrMc
+ T8IkjkS8KmJPie/JE/eTkJaMHzB5V/22ED7nS58xTtO0DXO+mpONP2fKwje0Zjf0ikuo
+ 2ZeO7mbzDMW+J9qepe60A+9soOPmwf9QOPRHcZaXm8Mt4h7m/gLfvTmspaqgah3VQ69m
+ uCq8FfWzO9k/sU+zJ+iP8UWspJ0M49WDjaScGHv10AVHsfDXMo6mBAUFxieE1YM0BJew
+ +hBj5TsJv61XB1+s2r9ZZMVIoi5jARcwiGOxFkhHDwrgXYK7gl0GOhnnSashVLUWix8w
+ ZZeOMmWXz8I8IBrJuWAeauQn/5ADT4QFT0QBQIIONIAAXgn5twoCMSYRhysp9WiK+Crx
+ ZAw5gmOg+rHrkX04TRqS3n58v/SG9N84bx8MdoHWXTpK2y5/BOmvovqB8LCOgU/qmBZ3
+ KkAVUzxjYGwC7aU8TAqXLhQyfqGCmS40Ms3CXcw9wv3Mk8JTzNP8s8IQ86LwKvO28CFz
+ kTEztIVhaa+eojDDWhia9erBpxSUFkGl9Op5hUJQWQSlCliNEWZ4gUEcCxEvlRIMsZIH
+ X4XGgsBQHPzXi8S/FI8hiHipNY9FJX2U89F4VyDbMqQdgj0N/ggJQpAoBNhgADhwY21/
+ hmIDxL7WNWufs2jZ/owNiqtzY3Vsv9byQ0tyJFqJWyeAywJ8hKcK23CPtAe3HhrEDdJu
+ SP/hr0eoVMoiDeHi8HD4NK6SDsOaGKUq4N8COYL8ptjtFeYKi4W7hL3CaQGcLsxxCbxO
+ k8k7NVP4XE0N38oTC7yaX6vRmGMLNf3KrapdqpCKi4tTKzSUU6326lUqgeMph0LhhTgh
+ SWoEoxr4xPFK5KB8Boc2No43AY9iNCo1yOdBqBAAi2rDbxXWTqNpjGcjgfOWy8AfAqOh
+ QlDigfPh8+CwyNFCECcMwUIWvLn6NeuemzAqvCQNpxF/9hUBdmBTYdFU7I1KGRX1hA94
+ 0mtt1gxG6sZTvngfooIDyzYeScnKwpteoShBr1umZlZdPkt7Lp2SXrwL01wc0f3yFSH/
+ OPqxywGFNPgEavDEPCgFpYJPVgD/n6pAlfBfpWr4G2AteGgzwRebjepRA/wXai6aB/9g
+ aoavC9eRf7WCdBEJIxdHvkOUlk0rqwhkVHcu6+3sWdLRnll2w7JFpNWVawskdgDcDxAE
+ OAZwCuA9gC+jDbEWsBMgB0AEqANoA+gG6APYAXA/QBDgGMApgPcAvoxOmNICdgLkAIgA
+ dQBtkdELwTWWxuBhXJtPHZdPG5eXj5NXvV86rl42uVfVV4yrrxyXrx+Xbx+XXzgu3zEu
+ D8y9Zj7yOl81/i/G1S8Zl186Lv/LcXn5v9ZX9bdiXP0N4/Ld4/KrxuVvHJfvGZe/aVy+
+ d1x+9bj8mnH5tST//wAT5F4+CmVuZHN0cmVhbQplbmRvYmoKNzMgMCBvYmoKNzgxMgpl
+ bmRvYmoKNzQgMCBvYmoKPDwgL1R5cGUgL0ZvbnREZXNjcmlwdG9yIC9Bc2NlbnQgNzcw
+ IC9DYXBIZWlnaHQgNzIwIC9EZXNjZW50IC0yMzAgL0ZsYWdzIDMyCi9Gb250QkJveCBb
+ LTEwMTggLTQ4MSAxNDM2IDExNTldIC9Gb250TmFtZSAvQUJDQkVNK0hlbHZldGljYS1C
+ b2xkIC9JdGFsaWNBbmdsZQowIC9TdGVtViAwIC9NYXhXaWR0aCAxNTAwIC9YSGVpZ2h0
+ IDU0OSAvRm9udEZpbGUyIDcyIDAgUiA+PgplbmRvYmoKNzUgMCBvYmoKWyAyNzggMCAw
+ IDAgMCAwIDAgMCAzMzMgMzMzIDAgMCAwIDAgMjc4IDAgMCAwIDAgMCAwIDAgMCAwIDAg
+ MCAwIDAgMCAwIDAgMAowIDcyMiAwIDcyMiAwIDY2NyA2MTEgMCAwIDAgMCAwIDAgMCAw
+ IDAgMCAwIDcyMiAwIDAgMCAwIDAgMCAwIDAgMCAwIDAgMCAwCjAgNTU2IDYxMSA1NTYg
+ NjExIDU1NiAwIDYxMSAwIDI3OCAyNzggNTU2IDAgODg5IDYxMSA2MTEgNjExIDAgMzg5
+ IDU1NiAzMzMKNjExIDU1NiA3NzggNTU2IDU1NiBdCmVuZG9iagoyMyAwIG9iago8PCAv
+ VHlwZSAvRm9udCAvU3VidHlwZSAvVHJ1ZVR5cGUgL0Jhc2VGb250IC9BQkNCRU0rSGVs
+ dmV0aWNhLUJvbGQgL0ZvbnREZXNjcmlwdG9yCjc0IDAgUiAvV2lkdGhzIDc1IDAgUiAv
+ Rmlyc3RDaGFyIDMyIC9MYXN0Q2hhciAxMjEgL0VuY29kaW5nIC9NYWNSb21hbkVuY29k
+ aW5nCj4+CmVuZG9iago3NiAwIG9iagooTWFjIE9TIFggMTAuNi44IFF1YXJ0eiBQREZD
+ b250ZXh0KQplbmRvYmoKNzcgMCBvYmoKKEQ6MjAxMTExMDcxOTEwNDVaMDAnMDAnKQpl
+ bmRvYmoKMSAwIG9iago8PCAvUHJvZHVjZXIgNzYgMCBSIC9DcmVhdGlvbkRhdGUgNzcg
+ MCBSIC9Nb2REYXRlIDc3IDAgUiA+PgplbmRvYmoKeHJlZgowIDc4CjAwMDAwMDAwMDAg
+ NjU1MzUgZiAKMDAwMDA1Mjc0MCAwMDAwMCBuIAowMDAwMDQzNzk1IDAwMDAwIG4gCjAw
+ MDAwMDMwMzggMDAwMDAgbiAKMDAwMDAzOTI2MyAwMDAwMCBuIAowMDAwMDAwMDIyIDAw
+ MDAwIG4gCjAwMDAwMDMwMTggMDAwMDAgbiAKMDAwMDAwMzE0MiAwMDAwMCBuIAowMDAw
+ MDM5MjI3IDAwMDAwIG4gCjAwMDAwMDQ1ODkgMDAwMDAgbiAKMDAwMDAwODA1MCAwMDAw
+ MCBuIAowMDAwMDE1NDYzIDAwMDAwIG4gCjAwMDAwMTYzMDYgMDAwMDAgbiAKMDAwMDAx
+ MTA2MCAwMDAwMCBuIAowMDAwMDE1NDQyIDAwMDAwIG4gCjAwMDAwMDgwNzEgMDAwMDAg
+ biAKMDAwMDAxMDI4MiAwMDAwMCBuIAowMDAwMDEwMzAzIDAwMDAwIG4gCjAwMDAwMTEw
+ NDAgMDAwMDAgbiAKMDAwMDAxNjMyNiAwMDAwMCBuIAowMDAwMDE3MDI4IDAwMDAwIG4g
+ CjAwMDAwMDQ0MzMgMDAwMDAgbiAKMDAwMDAzMTMxOSAwMDAwMCBuIAowMDAwMDUyNDY2
+ IDAwMDAwIG4gCjAwMDAwMDQyNzUgMDAwMDAgbiAKMDAwMDAwMzk2NyAwMDAwMCBuIAow
+ MDAwMDAzODA5IDAwMDAwIG4gCjAwMDAwMDM1MDMgMDAwMDAgbiAKMDAwMDAwMzY1OSAw
+ MDAwMCBuIAowMDAwMDA0MTI1IDAwMDAwIG4gCjAwMDAwMzAzOTcgMDAwMDAgbiAKMDAw
+ MDAzMDQ0NCAwMDAwMCBuIAowMDAwMDM4MzMwIDAwMDAwIG4gCjAwMDAwNDMxNTAgMDAw
+ MDAgbiAKMDAwMDA0MjM0MyAwMDAwMCBuIAowMDAwMDQxOTIwIDAwMDAwIG4gCjAwMDAw
+ NDEzMDEgMDAwMDAgbiAKMDAwMDA0MDQ5NCAwMDAwMCBuIAowMDAwMDM5ODQ5IDAwMDAw
+ IG4gCjAwMDAwMzk0MjYgMDAwMDAgbiAKMDAwMDAzNzQzMyAwMDAwMCBuIAowMDAwMDE3
+ MDQ4IDAwMDAwIG4gCjAwMDAwMjAwMzggMDAwMDAgbiAKMDAwMDAyMDA1OSAwMDAwMCBu
+ IAowMDAwMDIyNjk4IDAwMDAwIG4gCjAwMDAwMjI3MTkgMDAwMDAgbiAKMDAwMDAyNDAw
+ MCAwMDAwMCBuIAowMDAwMDI0MDIxIDAwMDAwIG4gCjAwMDAwMjc2NjIgMDAwMDAgbiAK
+ MDAwMDAyNzY4MyAwMDAwMCBuIAowMDAwMDI5MDc3IDAwMDAwIG4gCjAwMDAwMjkwOTgg
+ MDAwMDAgbiAKMDAwMDAzMDM3NiAwMDAwMCBuIAowMDAwMDMwNDkxIDAwMDAwIG4gCjAw
+ MDAwMzEyOTkgMDAwMDAgbiAKMDAwMDAzMTM1NiAwMDAwMCBuIAowMDAwMDM3NDEyIDAw
+ MDAwIG4gCjAwMDAwMzc0NzAgMDAwMDAgbiAKMDAwMDAzODMxMCAwMDAwMCBuIAowMDAw
+ MDM4MzY3IDAwMDAwIG4gCjAwMDAwMzkyMDcgMDAwMDAgbiAKMDAwMDAzOTM0NiAwMDAw
+ MCBuIAowMDAwMDM5ODI5IDAwMDAwIG4gCjAwMDAwNDA0NzQgMDAwMDAgbiAKMDAwMDA0
+ MTI4MSAwMDAwMCBuIAowMDAwMDQxOTAwIDAwMDAwIG4gCjAwMDAwNDIzMjMgMDAwMDAg
+ biAKMDAwMDA0MzEzMCAwMDAwMCBuIAowMDAwMDQzNzc1IDAwMDAwIG4gCjAwMDAwNDM5
+ NTggMDAwMDAgbiAKMDAwMDA0Mzg0MyAwMDAwMCBuIAowMDAwMDQzOTM2IDAwMDAwIG4g
+ CjAwMDAwNDQwNTEgMDAwMDAgbiAKMDAwMDA1MTk1NCAwMDAwMCBuIAowMDAwMDUxOTc1
+ IDAwMDAwIG4gCjAwMDAwNTIyMDYgMDAwMDAgbiAKMDAwMDA1MjY0NiAwMDAwMCBuIAow
+ MDAwMDUyNjk4IDAwMDAwIG4gCnRyYWlsZXIKPDwgL1NpemUgNzggL1Jvb3QgNjEgMCBS
+ IC9JbmZvIDEgMCBSIC9JRCBbIDw0MDJjNDE5YjU1N2U4MTRkOTA1MTdiOGZhZDAxYWZk
+ Mz4KPDQwMmM0MTliNTU3ZTgxNGQ5MDUxN2I4ZmFkMDFhZmQzPiBdID4+CnN0YXJ0eHJl
+ Zgo1MjgxNQolJUVPRgoxIDAgb2JqCjw8L0F1dGhvciAoUm9iZXJ0IEx5KS9DcmVhdGlv
+ bkRhdGUgKEQ6MjAxMTA5MTkxNzE1MDBaKS9DcmVhdG9yIChPbW5pR3JhZmZsZSBQcm9m
+ ZXNzaW9uYWwgNS4zLjIpL01vZERhdGUgKEQ6MjAxMTExMDcxOTEwMDBaKS9Qcm9kdWNl
+ ciA3NiAwIFIgL1RpdGxlIChyc19jb21wdXRlKT4+CmVuZG9iagp4cmVmCjEgMQowMDAw
+ MDU0NTMzIDAwMDAwIG4gCnRyYWlsZXIKPDwvSUQgWzw0MDJjNDE5YjU1N2U4MTRkOTA1
+ MTdiOGZhZDAxYWZkMz4gPDQwMmM0MTliNTU3ZTgxNGQ5MDUxN2I4ZmFkMDFhZmQzPl0g
+ L0luZm8gMSAwIFIgL1ByZXYgNTI4MTUgL1Jvb3QgNjEgMCBSIC9TaXplIDc4Pj4Kc3Rh
+ cnR4cmVmCjU0NzEwCiUlRU9GCg==
+ </data>
+ <key>QuickLookThumbnail</key>
+ <data>
+ TU0AKgAAEs6AP+BP8AQWDQeEQmFQuGQ2HQ+IRGJROKRWLReMRmNRuOR2KQOCR6RSOSSW
+ TSeUSmVSuJSCWS+YTGZTOaTWVS6bTmdTueT2fRucT+hUOiUWjSd9Ul/uKmAACU+j1GWP
+ 2qAARVepVmtQ5511/vKwAAGWOEAGzACB0WzAG0QK1We0xN4XMAB67Vu8XmCvS+P+5vCx
+ WSaWu2yGh4S4y93YsACHHXrIVm+PS/XQF5cAYi3YO4ZuDZrDTLQWXO6GKO/UY3H5HWUX
+ Jv/UO8AZcFxTRwvCOPdAAO73CgDFu4ABLiQh28fM2d78sAZMACfocm2YmE6PCcEABHtS
+ PbwbY1asa3xT/X9ixgzfwfraXpb+0l34AAq/MAOb7e0G2Rzuh0AAJv+AB8QEAALwKAAS
+ QQABmwWAB/QcABwQiAAMQoAAHQuABuQ03jfKSfQAAHEIABbEgAB2HQdLQz72PU9j1rY7
+ ARxkkcBHxBsHvHHKGHzHjmr67AFSC9rqSGtzuoKfckgAsB5AAe0nxBER4ynCcKnVK8LQ
+ xKZ4gAC0vSyBwAHTMYAHrMwAARNKnKgfk2gBJJ9gBIIFR8ej/QAqh+gACs+SKgkjz9QL
+ vwQEiOLSa9ET3PqgSMs6iLSwlHrdD06n+452zlISH0BFrp0bTzTU4iVRILF70xXUCMVI
+ AC/wPBKNzafgAGxWkOA6mtVp1XKS0o152V+2bMIWfB9oJHFIoNIjrRa39TIXZVHWSz1S
+ xdZlIRdaKEn6fyCAKAaCgOAq2IOtNWhLc6OVjWdag5dtAo2Vl4oQFF6ABX52ABHh8zuC
+ co2/PN/IQ74BYJG5/S7L5d4UAAr4aABw4gAEtsC9F1Afi4AXUGuNtJVKL16vp15FYLay
+ IaZ0ANBoGTotrkoKwy2XHFVS2Sz9m5kzObvUhlr5fm2ZZhmuaZ7m2iaGgwFnxOwSApWT
+ R4nc4S3TN1EGuAAN6xjtT2pjyFF7r4AN0cYAYuB4AK6eeMzdC8w0pdoOQzDYNbnsmMGH
+ u4ABdvVbAAaW/YQCwAHJwYAAbw0wAA/j+7LwXCDTx6GUBQE4UrK51ZIhhuHgA4AH0Bb0
+ Z26aEJDoOfZpnPRdJm1VZy03VdPmec9RFXX9kh4DnrJoRghONrrZqF0VhqlE6wDet0DU
+ 0iU7m+ceZ47CSZxHfeP5fp3JT/n2xVLCZAykxnSAAE/FQJvHkBPOgWBueJDbOd9NyOhd
+ s0yJs39vV9i3H46AhgDHnLgIgIL7WQQViZ0ATtTVkNaBQAG5gadGtN5D2oHp/gk9YhS0
+ HtwSevBSDMHX1qhgqW5dRr3FKZTo9Mbg8Xzj6AU+pcj935vyhgQpmQ6RzNjAuBpW4+R8
+ D3TKPRtIEgKOBHVDc/wGHjADYLDF/bsImP6guQYBA9UuO7X3BtJZYV6AogQAAasXwAAZ
+ jEQwd49Xfj7AIAAASKnkvYgwy8gkMTcPtenHWN0EFIlujlDQ5Q+WDgmAsno0cIy+n2HM
+ 5ghcKXzj5ha/eF7NFHQQNJHB2AmxEB5T2BluABwEPnAUAxMI5hwjcMyAKNIGAOAfOGBY
+ C6IwbA+Zcy1yK436vxfe82KZsndofem9GLcXRqTBjDGMhY4R2xrHkAoCRmVvuzji+99z
+ +FqTQdK6OGbp2Yu0mhNdZj+JqyPdkP4eyHwXAQSbFiQhlByzrcxCgeKdB8AKTCpB2UtI
+ 7wcdNM+SC4x4DtHWksd6+AEyfAAVRg4BQDspH8m4dQ5WxgeBMCksQDgIQRloz5oMkXsT
+ WTkPcwAIgHo2IW9EFNJZgTCQoBh445h5LfHOAJfpZo9yxdi82WT9o3PXOrPYhq0ZvyUp
+ otJIdOj1FJAADECKXJBpuNfOscsJoJgAG6PI2s8WzRYn3UCjSf561ap5LGCxCTEsxq/V
+ t2bsn61lntPgBQ9jZUgRtL0sIKq6RdGnXdAiBiDnOpYt8dgCZVABjWAAe49U7DyHc5cC
+ 4HARHVq8QUfJzACAGc4iGNY5BuNWAQ58AAFAMq3pqQUec/XCgQX7RyvY8jZAJAY2YfQ+
+ B7AAk4nSHkPgErCJCPW0Zs6KOmAGPtfYNgKpcIW5Q17gxyVQemNseCdB7gJquuMAQ818
+ FsT1A+adN61VAVRN5+cTag2Pu1eIzY/U4ogALQUBwGZKALHvLoCFIiFPRBXfUiCNapDd
+ G64Vw7AFaDYX4e0b+Azmj+PQAkFIRY1ACLYMsXwsU9gblUNcZgwzkxrHWOUcAAAPgoBe
+ c2xFBR9qyAaBECkR24YZw2OwdA4rOgYA84kcUpARgsBpVIagzAAAQArewBtpl82wxEnH
+ E1KhwDaGkhYCIFSrAqBkY0FAMQADFFwKg4A6angiBWDMAALwdhHliAO14AAcgXuIQp7o
+ /7kPhfGQsbY8Ta3PoqQcFI4BYGNAVFcyE1Yny3ISNcfeJxvgbCGzUBdbgAO7h9FhtAAA
+ WaPIhCV8T53GLqruNOzoFMTkHYAN4dSshxACBAqUglsE7DxHaf0fo/E44/yYPYehgB1D
+ kG8gQDzUrzIfAGAS9NrEwzZH1ZFjI+0PwDTfsRgMnT0YjQ+Pa3YEwLq3GuMsX6BwXA5l
+ LGu18PgD2cHmO18BhANAjBXJQA4/UPg8AycK4qSjXtizY+fN1zUygJAiQgFw5hbmNf6S
+ /PkNIoEqGqP2Vo3ALhAkoA0fBwtFEM0bo8FhEDsFPjS2xtSsm/ZJ01pshQ4x4xpGmPPJ
+ karuSOii7CtD7LwP6vBV+aKz5HXbm3TVcYCR/I2CCBw2T07jF9KZi7SZDM3m1HqAiZbP
+ gXjjzuCEAe7FpT4JM9atPJSK0auyQYapdQADbAyER0/ClMAjAfoshWjUSAt4kYzijiF1
+ DR7dgGYo770jRHpyOnzP61wzmzPqGT1TQ59tDWaJ0zrQzbM1C8BfNwABDA904hPPTKMQ
+ HDvHoQ8T0DzAPvdmQMRwCpMa4khAiBVC+NmuFNa3wFemAoA49A4h1GyW2wcDoFaKgLAQ
+ ykBgCXODPG7U8DgFKKjxHrD4HoKwQgAGsOJ8CxFZGG+Gvsfa20ugQPQO8elsQigxgOBg
+ CMLiDDTAICbrYHAkkIAcPlTAJAIQ+SIc7s/aThdr4t23t5xOjkKHaPSNY4h5AIAAAKAI
+ dc4ArFAG8KtQvAsitik6ZYls5M5m76dsnAvAAMACT0BOAqQ+3aTiNewGG+uUggG2HkTC
+ Ho8yIQBkG6FCKsH6uSIOGyHIn+WIT0Hg+GtkKgHmHwQ+W8LYHyH4T0BCAs3uHIHaSaAc
+ 9Sc6+iAAGyHMXwBWA6cCA+AqbMGqHEn+H4QeAsAeNqHpBwsIH0VkAfCNBwVkBYA+cCAk
+ 9yIQGmAS7QG0A+CelkAcHwXw7EHqLKIMHmL4y6Bew+Ie4mKg/mTcGhEEOyO2IuV26qRY
+ IcUuwDEONtETEQVSnSH+G9Eo8oIWG0HjBG6MdMBmG4E80SH4w2Iw3+Iy5aJZDUykGuA+
+ Cim0AiHyXwpBDqIWTNDrD3D4IdD84qQwXUGfF7EI3u78pmIdEaImNHEWP+tPGHEeI5GI
+ INElEo1qTS/8zdBEbOAOX6LSBqGuEu0SH0G2Iy6mlkm7HCJ6GkAaBsAAGuBECzFaH1Fg
+ AcTsIWHsTOBeBgBg/gTXF0TCXUGdH6x2AgzmIsVWjbGEIaVbGgAABlIUXej4g8eUI8qW
+ VkNev0v3GkUDEwbMHkAM6OLOBAGuFIQIH+Xwpu4CaGo3HCj0IOW4mwwYz9Aejmm0myz8
+ HGAO+OHKBECcdmAiH0cu7ETsNHFoqOBiylD67VD/F2TdH6GcbqbNGaJIckPYHPKkAAFv
+ KqAADFKwJPKga6IrEkQ0lJItGo+CANGxJO5UI+o26ePaIOtGUw14ZSAQoIjzLOfpLSjg
+ 6gIUAlJ4KsAcbTFmTPIUyfKK/jKPH2TcQWGacQeWHqHyNlC8tiLMsGJ6YASeh8cMdAKH
+ B4tiAuAcBGePEkG3NC8oSJEwoqHgAKtOXG72qImim+iaZg5WOaHiNkKevSs2PRNWqFDt
+ Jc8G5pAaZoAmH0fA/UTsemOcBnORHw/lKQVkGZOdKYeOHaHywAAUA6GIjUZwpsdpLpHI
+ hlO7EMijJRLo8HO+IYHuHibNFcCsec8gH/NDG+APPiUCGyHjLG5HO2p3FMiwWzP1LUHS
+ HGv2H+H8T0AyBA/EkkWQp+aNAgeaSIAoH3J6AenOu6OcBpQtOVMK4uABOcx0POUCHkH0
+ 1qAIAyF6uyjwLhAcPSLPP6qwu67+hAdE5RLUZdRZRmIMH0Ho3ugCCoUDEkG1R+tlPlEu
+ Hk3uHcAIxOmyAKHkxc2MJUmyHOHCGyZsAyA/QOmkJOvMmmH0Ae+OmeAqH3OGAgbSSISe
+ tjQsxvMHHy7YTdQ4kQvnRCIKAqF2a0Z4m5O0dUq5NVNbHAmu74kgdPQET/Ja8GH0Hq3u
+ AmH2CqIYYANeGzUcTQTUenPooqHaAIyYZkB0HcFoAABQAfAyz2m5T3RkQUHoX6GiAeB+
+ IQaaP6BIAdQmISOWh9TPQxH1Q0GXVvTcISHiHzQCApTmEgD+wsk0TC2g0oAgToHOHISa
+ 1WIIxMfPUCP8AuTo2CT0f8+gHyT09iP8AsNqc+ZSHcHYtjWgHgHcRslQfUh4Vkt0Q+Ae
+ Ai/8oo/8GgGSkOsWPQAUASZSn9DqAKAMW+AkAqTow0S4CYCwBUMyH4yYAoH7UUnQqYL6
+ v/Ug/8SJPomWHcAKyYM2B+HgFmOeAVVfN4jlFJEM5lAlN/QYISGYHugcGcAeCCIQAuH7
+ VZQkqjViAAY2BrVpTWVkGVZ4qgpGH3A8H6AgF0AAHEG8MAlES4AaAec4lAc4huSa14jW
+ AhXcoKH61KHuacsGAgAkfOGUGCxcBaBmvYAeAk/8HaHVDqh6T1Xac5XAh9NmRsAmAqfO
+ KoIIlAZSAqAufVWTWWQeAaAcc4FqFUasB8CM+PbmPQHYHUTsBgBweMH+HyxOAoH9R4NH
+ UYL6gUGtSCc4NGG0HkxPUq7sIKB+HWFZU4AOUwIWFqGSGow4AsmWA9CAZqG4HMUwBKA2
+ xOwYLYHvC8LEAQvSHtB4OAHmtiAkAafOHW+EKsAyX6HoHuX2HSHebS9svS+otoH0TiHn
+ d6Mbea5MGUH01GGWAdZcMJQeqeBHVcIYvxZuIhEWNpZ0AAGTfnA+nxV21qH0AbaIkiml
+ JktCmff9ZKz9gBAimsVDZPgJTvTtJiZyH4HwmWAwADPW543dcygXPic5YmHiX6HYAIla
+ IOCCHSFKAABSAIkOscEcFgwsHKHabTDAc4AlCKAAGAGk1qBndwRAYKQcYO9veDC49mbM
+ FsGYG0AACcBsi490vSHcHktiF0GilIBiBEgcAIYKHkHuRtiigcCgBy3LSuGOH4akF+AF
+ ZwZ8AsH8cuBAAbY+LSX1ITIWIfTKNU+ORCW+XVfmGTYiUCHiH1A8HyAWFyvCa1Iea4Wb
+ ZNKdkEklRcSNkNGXgcmWAyAFPWeXEki+6yANkua1PoxOHWAIcCIOCEHKE/hIADFFgFSv
+ ZOqi2NDEVYHrXMAidAz6G6HOl0AzGBlMfmGSAHHuGYAxFYZmAwH7fQAcMAWGQGBxmOi6
+ GRmVc4IZRAP6HsH8wAAEREm88DUBkXRrJfAG5W75Jk7zf8p/m0XIH6ToAwAVjJLVcwMo
+ 0vjySIGxdAAAHWAGpUZaCIHHG4BUH8lIR0I4GQAKBuAAGWA2CuN+A0H+kOBGAaNk2NZq
+ Bzoci6GPojjyWfkTPyqjGDIZkJopILLXRtkIjtRgg+IgMJnUH+4zonLUGyHkyYHVnmZq
+ BcG+FGN4H+P7T5N7N3ANgXAJpuIsG0AIUKG2A7l8INoNoQAaOENHjboc2weEVloiGOAB
+ kuZSjevHo2osedP3GXLm6urEnvqvqzK5LXPLGdYcMoGkGiySsoZSeWGuHiyYHSAClbII
+ scmclrp3gLDtIdq9N273rtAOp6ZyA2zUQOAc52ghjaRQRSUYIJF6GebOK6YNkRo5rnEb
+ rmU2hCnxkHsloyIYTmUrEEGhnaewGxrccSAFnpNdJKdqm6qI6spofntTZBAepxO5PGII
+ A2H8uSBKAfsMnwvwB3uBn5uEJoNftBmYixracCHSAEvZZFAMdLNWdqiaMQZnO5VDZFT0
+ dTtkqGdeVuuTVaUwNGUpuAB3uHvMJgNfsbqjkwIWG/PQOaLEaE7vpvNjvpZM5evFufVD
+ p1lPT+AgACSaA4AabTvEqMB5wPvPwSJUNfKVuOgvRPQbwhqxLUWdwfpDRbo/LsecrDou
+ u6iwUoB7xDwVxGJNFoH/mUGRvXqnwlrBw3wknoRXxdwvwpsxs3Ozr1xnLuUCYACBx7xJ
+ x+JFh3poP5TVyANYALyRH/IDyNyYIsKDybyhyjyk6fo5ynytyuPHyfyxy3y5yzs1y7zB
+ zCKPy1zFzLzMKFzJzPzVzWJoICAADgEAAAMAAAABAF0AAAEBAAMAAAABADYAAAECAAMA
+ AAAEAAATfAEDAAMAAAABAAUAAAEGAAMAAAABAAIAAAERAAQAAAABAAAACAESAAMAAAAB
+ AAEAAAEVAAMAAAABAAQAAAEWAAMAAAABADYAAAEXAAQAAAABAAASxgEcAAMAAAABAAEA
+ AAE9AAMAAAABAAIAAAFSAAMAAAABAAEAAAFTAAMAAAAEAAAThAAAAAAACAAIAAgACAAB
+ AAEAAQAB
+ </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>{{67, 91}, {969, 926}}</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>{{-129, -19}, {834, 772}}</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/rs_compute.png b/docs/html/images/rs_compute.png
new file mode 100644
index 0000000..263b2ec
--- /dev/null
+++ b/docs/html/images/rs_compute.png
Binary files differ
diff --git a/docs/html/images/rs_graphics.graffle b/docs/html/images/rs_graphics.graffle
new file mode 100644
index 0000000..5dee4c6
--- /dev/null
+++ b/docs/html/images/rs_graphics.graffle
@@ -0,0 +1,3107 @@
+<?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.28.0.154505</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-09-19 10:15:24 -0700</string>
+ <key>Creator</key>
+ <string>Robert Ly</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>{{95.9835, 355}, {107.033, 31}}</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>Line</key>
+ <dict>
+ <key>ID</key>
+ <integer>246</integer>
+ <key>Position</key>
+ <real>0.19373114407062531</real>
+ <key>RotationType</key>
+ <integer>0</integer>
+ </dict>
+ <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 bindRootScript()}</string>
+ <key>VerticalPad</key>
+ <integer>0</integer>
+ </dict>
+ </dict>
+ <dict>
+ <key>Bounds</key>
+ <string>{{71, 431.245}, {157, 24}}</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>247</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.628571</string>
+ <key>g</key>
+ <string>0.768599</string>
+ <key>r</key>
+ <string>1</string>
+ </dict>
+ <key>FillType</key>
+ <integer>2</integer>
+ <key>GradientAngle</key>
+ <real>90</real>
+ <key>GradientColor</key>
+ <dict>
+ <key>b</key>
+ <string>0.236788</string>
+ <key>g</key>
+ <string>0.532236</string>
+ <key>r</key>
+ <string>0.990271</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.131021</string>
+ <key>g</key>
+ <string>0.363196</string>
+ <key>r</key>
+ <string>0.725948</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 Renderscript object}</string>
+ <key>VerticalPad</key>
+ <integer>0</integer>
+ </dict>
+ </dict>
+ <dict>
+ <key>Bounds</key>
+ <string>{{71, 306.83}, {157, 24}}</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>200</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.628571</string>
+ <key>g</key>
+ <string>0.768599</string>
+ <key>r</key>
+ <string>1</string>
+ </dict>
+ <key>FillType</key>
+ <integer>2</integer>
+ <key>GradientAngle</key>
+ <real>90</real>
+ <key>GradientColor</key>
+ <dict>
+ <key>b</key>
+ <string>0.236788</string>
+ <key>g</key>
+ <string>0.532236</string>
+ <key>r</key>
+ <string>0.990271</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.131021</string>
+ <key>g</key>
+ <string>0.363196</string>
+ <key>r</key>
+ <string>0.725948</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 RenderscriptGL context}</string>
+ <key>VerticalPad</key>
+ <integer>0</integer>
+ </dict>
+ </dict>
+ <dict>
+ <key>Class</key>
+ <string>LineGraphic</string>
+ <key>FontInfo</key>
+ <dict>
+ <key>Font</key>
+ <string>DroidSans</string>
+ <key>Size</key>
+ <real>11</real>
+ </dict>
+ <key>Head</key>
+ <dict>
+ <key>ID</key>
+ <integer>247</integer>
+ <key>Info</key>
+ <integer>8</integer>
+ </dict>
+ <key>ID</key>
+ <integer>246</integer>
+ <key>OrthogonalBarAutomatic</key>
+ <false/>
+ <key>OrthogonalBarPoint</key>
+ <string>{0, 0}</string>
+ <key>OrthogonalBarPosition</key>
+ <real>36</real>
+ <key>Points</key>
+ <array>
+ <string>{149.5, 330.83}</string>
+ <string>{71, 443.245}</string>
+ </array>
+ <key>Style</key>
+ <dict>
+ <key>stroke</key>
+ <dict>
+ <key>Color</key>
+ <dict>
+ <key>a</key>
+ <string>0.7</string>
+ <key>b</key>
+ <string>0</string>
+ <key>g</key>
+ <string>0</string>
+ <key>r</key>
+ <string>0</string>
+ </dict>
+ <key>CornerRadius</key>
+ <real>4</real>
+ <key>HeadArrow</key>
+ <string>Ball</string>
+ <key>LineType</key>
+ <integer>2</integer>
+ <key>TailArrow</key>
+ <string>0</string>
+ </dict>
+ </dict>
+ <key>Tail</key>
+ <dict>
+ <key>ID</key>
+ <integer>200</integer>
+ <key>Info</key>
+ <integer>5</integer>
+ </dict>
+ </dict>
+ <dict>
+ <key>Class</key>
+ <string>LineGraphic</string>
+ <key>FontInfo</key>
+ <dict>
+ <key>Font</key>
+ <string>DroidSans</string>
+ <key>Size</key>
+ <real>11</real>
+ </dict>
+ <key>Head</key>
+ <dict>
+ <key>ID</key>
+ <integer>202</integer>
+ <key>Info</key>
+ <integer>6</integer>
+ </dict>
+ <key>ID</key>
+ <integer>245</integer>
+ <key>OrthogonalBarAutomatic</key>
+ <false/>
+ <key>OrthogonalBarPoint</key>
+ <string>{0, 0}</string>
+ <key>OrthogonalBarPosition</key>
+ <real>4.1290435791015625</real>
+ <key>Points</key>
+ <array>
+ <string>{149.5, 236.415}</string>
+ <string>{149.5, 266.076}</string>
+ </array>
+ <key>Style</key>
+ <dict>
+ <key>stroke</key>
+ <dict>
+ <key>Color</key>
+ <dict>
+ <key>a</key>
+ <string>0.7</string>
+ <key>b</key>
+ <string>0</string>
+ <key>g</key>
+ <string>0</string>
+ <key>r</key>
+ <string>0</string>
+ </dict>
+ <key>CornerRadius</key>
+ <real>4</real>
+ <key>HeadArrow</key>
+ <string>Ball</string>
+ <key>LineType</key>
+ <integer>2</integer>
+ <key>TailArrow</key>
+ <string>0</string>
+ </dict>
+ </dict>
+ <key>Tail</key>
+ <dict>
+ <key>ID</key>
+ <integer>235</integer>
+ <key>Info</key>
+ <integer>5</integer>
+ </dict>
+ </dict>
+ <dict>
+ <key>Class</key>
+ <string>LineGraphic</string>
+ <key>FontInfo</key>
+ <dict>
+ <key>Font</key>
+ <string>DroidSans</string>
+ <key>Size</key>
+ <real>11</real>
+ </dict>
+ <key>Head</key>
+ <dict>
+ <key>ID</key>
+ <integer>251</integer>
+ <key>Info</key>
+ <integer>8</integer>
+ </dict>
+ <key>ID</key>
+ <integer>242</integer>
+ <key>OrthogonalBarAutomatic</key>
+ <false/>
+ <key>OrthogonalBarPoint</key>
+ <string>{0, 0}</string>
+ <key>OrthogonalBarPosition</key>
+ <real>57</real>
+ <key>Points</key>
+ <array>
+ <string>{228, 443.245}</string>
+ <string>{344.75, 303.184}</string>
+ </array>
+ <key>Style</key>
+ <dict>
+ <key>stroke</key>
+ <dict>
+ <key>Color</key>
+ <dict>
+ <key>a</key>
+ <string>0.7</string>
+ <key>b</key>
+ <string>0</string>
+ <key>g</key>
+ <string>0</string>
+ <key>r</key>
+ <string>0</string>
+ </dict>
+ <key>CornerRadius</key>
+ <real>4</real>
+ <key>HeadArrow</key>
+ <string>Ball</string>
+ <key>LineType</key>
+ <integer>2</integer>
+ <key>TailArrow</key>
+ <string>0</string>
+ </dict>
+ </dict>
+ <key>Tail</key>
+ <dict>
+ <key>ID</key>
+ <integer>247</integer>
+ <key>Info</key>
+ <integer>7</integer>
+ </dict>
+ </dict>
+ <dict>
+ <key>Bounds</key>
+ <string>{{54.5, 266.076}, {190, 73.3394}}</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>202</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 RsSurfaceView or RsTextureView\
+\
+}</string>
+ <key>VerticalPad</key>
+ <integer>0</integer>
+ </dict>
+ </dict>
+ <dict>
+ <key>Bounds</key>
+ <string>{{54.5, 186.245}, {190, 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>235</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 Activity}</string>
+ <key>VerticalPad</key>
+ <integer>0</integer>
+ </dict>
+ </dict>
+ <dict>
+ <key>Bounds</key>
+ <string>{{54.5, 401.585}, {190, 68}}</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>234</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 \
+\
+Renderscript entry point\
+\
+\
+\
+\
+}</string>
+ <key>VerticalPad</key>
+ <integer>0</integer>
+ </dict>
+ </dict>
+ <dict>
+ <key>Bounds</key>
+ <string>{{29.75, 139.33}, {239.5, 350.67}}</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>233</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 \
+\
+\
+\
+Android Framework\
+\
+\
+\
+\
+\
+\
+\
+\
+\
+\
+\
+\
+\
+\
+\
+\
+\
+\
+\
+\
+\
+\
+\
+\
+\
+}</string>
+ <key>VerticalPad</key>
+ <integer>0</integer>
+ </dict>
+ </dict>
+ <dict>
+ <key>Class</key>
+ <string>Group</string>
+ <key>Graphics</key>
+ <array>
+ <dict>
+ <key>Class</key>
+ <string>LineGraphic</string>
+ <key>FontInfo</key>
+ <dict>
+ <key>Font</key>
+ <string>DroidSans</string>
+ <key>Size</key>
+ <real>11</real>
+ </dict>
+ <key>Head</key>
+ <dict>
+ <key>ID</key>
+ <integer>250</integer>
+ </dict>
+ <key>ID</key>
+ <integer>249</integer>
+ <key>OrthogonalBarAutomatic</key>
+ <false/>
+ <key>OrthogonalBarPoint</key>
+ <string>{0, 0}</string>
+ <key>OrthogonalBarPosition</key>
+ <real>4.1290435791015625</real>
+ <key>Points</key>
+ <array>
+ <string>{439.75, 326.693}</string>
+ <string>{439.75, 351.997}</string>
+ </array>
+ <key>Style</key>
+ <dict>
+ <key>stroke</key>
+ <dict>
+ <key>Color</key>
+ <dict>
+ <key>a</key>
+ <string>0.7</string>
+ <key>b</key>
+ <string>0</string>
+ <key>g</key>
+ <string>0</string>
+ <key>r</key>
+ <string>0</string>
+ </dict>
+ <key>CornerRadius</key>
+ <real>4</real>
+ <key>HeadArrow</key>
+ <string>FilledArrow</string>
+ <key>LineType</key>
+ <integer>2</integer>
+ <key>TailArrow</key>
+ <string>0</string>
+ </dict>
+ </dict>
+ <key>Tail</key>
+ <dict>
+ <key>ID</key>
+ <integer>251</integer>
+ <key>Info</key>
+ <integer>5</integer>
+ </dict>
+ </dict>
+ <dict>
+ <key>Bounds</key>
+ <string>{{344.75, 351.997}, {190, 47.0177}}</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>250</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.274119</string>
+ <key>g</key>
+ <string>0.950739</string>
+ <key>r</key>
+ <string>0.787494</string>
+ </dict>
+ <key>FillType</key>
+ <integer>2</integer>
+ <key>GradientAngle</key>
+ <real>90</real>
+ <key>GradientColor</key>
+ <dict>
+ <key>b</key>
+ <string>0.223529</string>
+ <key>g</key>
+ <string>0.776471</string>
+ <key>r</key>
+ <string>0.643137</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.165602</string>
+ <key>g</key>
+ <string>0.586124</string>
+ <key>r</key>
+ <string>0.428309</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 Renderscript Graphics Engine}</string>
+ <key>VerticalPad</key>
+ <integer>0</integer>
+ </dict>
+ </dict>
+ <dict>
+ <key>Bounds</key>
+ <string>{{344.75, 279.675}, {190, 47.0177}}</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>251</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 Graphics Renderscript (.rs)}</string>
+ <key>VerticalPad</key>
+ <integer>0</integer>
+ </dict>
+ </dict>
+ <dict>
+ <key>Bounds</key>
+ <string>{{320, 238}, {239.5, 179}}</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>252</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 \
+\
+\
+Renderscrpt Runtime Layer\
+\
+\
+\
+\
+\
+\
+\
+\
+\
+\
+\
+\
+}</string>
+ <key>VerticalPad</key>
+ <integer>0</integer>
+ </dict>
+ </dict>
+ </array>
+ <key>ID</key>
+ <integer>248</integer>
+ </dict>
+ </array>
+ <key>GridInfo</key>
+ <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-11-07 10:35:41 -0800</string>
+ <key>Modifier</key>
+ <string>Robert Ly</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>coded</string>
+ <string>BAtzdHJlYW10eXBlZIHoA4QBQISEhAdOU1ZhbHVlAISECE5TT2JqZWN0AIWEASqEhAx7X05TU2l6ZT1mZn2WgWQCgRgDhg==</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>
+ JVBERi0xLjMKJcTl8uXrp/Og0MTGCjUgMCBvYmoKPDwgL0xlbmd0aCA2IDAgUiAvRmls
+ dGVyIC9GbGF0ZURlY29kZSA+PgpzdHJlYW0KeAG9m01zHrcNgO/7K/YoH7xZkvt5bNMk
+ 00wPbeRpD0kPqWzHduU4kZSm+fd9QAIg39UrWZ52OhpZBJYEQeKDAEj/3P+l/7kf+ZnX
+ pV9T6m9e9X/rf+w/+/w29Fe3fcg/t1f983GYe/ltOr7uP/vzq5urVz/d/fL9dXfzFlJx
+ DplcnOY+hWlYxrj1cQvDtq+xv3rff/bH96H/w4c8bxxL53nrU9qHNNM37fuwxrB1pW98
+ tG9ch2kck9KtfZWJaQp9nITuuvVhX4Y1xaiE05FwCHs/7UMYpXNMy7CFaBxPx85LqH2n
+ fRzCHHYlPB/7bnPtm7ZlSDEsyvFifcOy5W1Lc7/MsmnwkPZ5mJc1KN31sb5xDfBg7Nau
+ oZCdYg+T87bIBk/jkBCGkt0KWVGDFBOczv37fp4XJC3ta9obpBfZHIQ/7/lDGhZBGQgx
+ bSd2UcZItxTWIU0pACqJxMoLbWld5RmldU0rlL6AXYpjHVyAPfcW9E7f079CZ4S9mOlI
+ S9kzop2wbqu76t94+33WdWhmbtlu1EV0PGyjG0LV8P7mbfcz9iDm8hwFQGVXdmmUcaKt
+ l29Cf/sGzX7ApkL/NaPfFdv6/LIbh2lNY1owK2nsU27EfV/7y8+Rh880ZstkCllDTJtL
+ SNpVQp2AZeujmFPZellbxBBMQlOYXEJTQNmKIE3IYS0S6iZaRULSaiQkYN5wG1yASSUk
+ 9A2jf9EOaQkXQoeWsWcSyquy1ZmEykov2U68Ebp9248dnqjZmKMIfv+iD1HlE/vn6zYs
+ 2zZt/fNl6V8goS/DMLKtL17333YX3zwTpxb7i1fW+PEZEgDxUv/6hxvrcWuNK2vcPOsK
+ lZ900F2vDaf/iyKM/N1bRbw3IjpRd2Fj/6Q9vrcev1mj5env/Yuv+y9eqMalac36OCdc
+ zLR0mHEKLUbEnhIeU4xZe4GZSp8w7BuicxgvARVRm9yjm0ZUSoYKlTJmXNEeIKM54tyk
+ h81rMOJX3hTToQbTMow7zgF2yqg0tVQd0lmFhn5XTIErX8fvdcSsa5FZT1dbubBdM05t
+ f7Iynu4s5idHpNCKxf43WXXYWcw2jGFdVrxHl4/RE+9xTnXjzkEzY2rZgcSzDqTTQ/ng
+ QFDWlNI2q9/g1ACzpxkTeMh/5IV0cd2HZWWcq4hjGhVxnIpbTvExbHjwIv64xUxFfH/B
+ YMDDIjJ1FUlx5vitKpLiUnqoijhsKoLv1x6NijhOxadUHdJZXeDGR3fscYR9hK1F/FNR
+ EV+tqUjdNVUR359GRRz3vj/xW/15v6XCl6P46LowrW0niJqOjqu/+Eqdg3sl9xI/PeNQ
+ wYG90R7maNxbuf8yR+NOyv2KeamXSss/+HROxMn6J5vw4Ay7i+8uhiPXTua7Z8/6s64s
+ icaN6JPrqWFwIO52DOdaKNo97+KGsrEnjoFMpeop0d0udmN62qWEnkYitUoVr5b7mKYa
+ bJpKyKo9Wk1VnGue0TXNs5ld85Jhjj0OsJyhRTN9Pa6ryVZsutr7nqiuOoyuwls+KBx3
+ 4s5kVZPszcGdlazg4M46D1H0JE4zEflOuFncWTrrziy0at1Z9/mlRD9xIw6iQagaovi1
+ QHiCX3vUn/W4vGHfccGmJ51jWj2xXqYX4uInUhCHp0Kl6gkpwxg4Sk1PiMmxyzW0ekK+
+ In2gkg9byV8yXPXEMFVPOu9lMjW6DpeZJaZSqSsvR9g1zb7XEbOup+qJrbjqie1J0Ym6
+ b41P8718kk8zDTjj0yT3medpPefT/l9+6DHfibp9gu/sLr4wV/nDwd0aHtdZ/ZpkDaMo
+ 8mdf3Yb+h9s2GMgBvuyYmZEdghWTtmEuR6v1IVMZSRWufdAUFXHZ5ZA5J/BlWo4fpo0y
+ rQ3n9N5JnZmBceQxiQxREEKPTNkRKP+b+4Nes5av+X13bxli+jYHgZewaHOgq8aizeGI
+ OocPkhO05KXCDqvH9KAVl4W4q1P4GniFcQk7S4+47BKXzXvEpYN2eJTxVwZLcCuDpXMX
+ MbKcLzmxOJFq5ZnIW6gwkLcIF9LGnjiXEEYBOcTzh0KhM1BC59o+1yrfp30na2PzYQ5+
+ IKaYwn6ncyVbnvChPfKGZEvNvPkOSeQJITYhsr/yryS1YsfLarFkU7khr22lGKiCEHeE
+ jejSEtvprCM3Wq0j74sj/+TElj3sgqSFopK68Qo3IlaMijSwrmUlPnCYPRNZqVSnLW9p
+ 0YdpIxuUXNdFTOHGZpKmiVjajYhzLxFxVymUxB/qJmKZqYj4tNWIOCAKmKsi7px9F7Eu
+ z0WscBWxIg6e+JAV3xMgsSWGOHKOvrg6SZAp8yyr5MdhHj3O5FAnQb743Y8vbz68fdl/
+ efP9+1e/frj557P+xbuabXLQo1JwTg1BJDaFBmaRU8pVIyKr0kUsTAbAyEpVSsG45fFs
+ U/4schd6Ml66x0UiuE2qeEouLoQn2fBkPoM4sYUdAzmu52Gj/FFRnIUNOYE6m4zB5WOZ
+ +2FAOxInKpO5qy2p0zmpfuiST7ZIZHiCKFEXgVZc8MSwKgEX6vnRzLGINxIxyEaUQGs+
+ a59G6759fmLeKIyTaLPlhMgmbIOrsMnlS5civWlkYWRWKsxpZJsZf5W9LR4GYQtswp6W
+ bUCNMFAVNj3wRPQoymWQCltBic1M2NYjy8XJKVQmUxna3O23rgWw7AIq08wiSuJLcmHb
+ krNsFSBWV2Hb14PBHtLBexI9JINsw0JRYcFO1+5Qx+r/mzpWd/HkFO5MmezO077frAhm
+ aaXlfx8eiIzu2shIzvi8fTM1IcoSG6WrInJDZB0pHgA5lE6qVfM0YwfUkIvOzeiOkBDP
+ LC6E0m/RIdcy7EaVUglORM6NlilkWqZg1TIolv5FIYycQmUyUx6d++RbC0jpRNTKuVY1
+ 80W5avuqTzaKVaqi2Xe2Tk5/3IqwOWI84lY4+cOyc8dgtzuHPK6WmosqzlTjl2UvVxqX
+ b5aHvEue68nepXsgi8tLorCE9XOFYbJ3RONfDKceJGz4JQq8KvuwEfMICT9OJJfFR5rs
+ I9m4nj4qe7nnoQf08nFSILH9fJwoWGWf74WEYpaak1MoT2YijTp3+82GFa5U9s61yt4X
+ ZbLvbNWFK4dc9o55ipdpRXtwMyL0NW1cAnksoMVyogGrP7vD8Cr2v8z4rfhzR7G65j1u
+ 3eJzd4zSJeyIKuHOcXqEcBvG+U8onuOBidM/kzAJJzfP0iHt5LyU7uivAUMiKajWbZBK
+ 2MBGwobKcnNyApG0n5whBmrPxinYF5Wwc60SnnRRNWLwVWe9c8gl7Bi3bmHTrHsl8wDe
+ LRz/aGhPEBYlDy+xw3rWuo3Yk637oRqNLCnHWuM6Ly57Cb4yosqeQEhxRZYSp5OFEFhr
+ LEhhBRIYmMrazdNg6nxrGz/IpbJYa7Fug0z25WMbP1iPIlEy7kxOoRIdqkilaud+QIES
+ P9gX7SiZiK4z0/FFeQDhqy4+R/eghhD+/SnWPTWiPVg3aTVR5jh9JIjwquylXVv5Kf/a
+ 68zuBF6Z7f+1Nfnmhk5zkVO2uDA7k40EDoC0x3NRzsXbV7/2H26ILiwF+dgUPkPXXgiS
+ ghEWkq0/TwcXd/HN7YsnUD9T1YrkoFua9/s0v21ipn+b/7yr26oXh15g/x/sIRcwAZWT
+ BR4CRdnCusCPFqPEN0ReC0z4UTlTJSRD54mAFSGHKuftKWKnBDrKNZh1iuJ9AckBiXFI
+ kQE7qQ7ZOZ2/Jy4SA/ma0FQEbnzlFUfkDUTcKQlzT166SN5DHqmgOIMTxEdAcnxWQWHE
+ CDAlV2hSAmowUnh6rLwlfiJEPFPi7p9fcWspEVfOawA3DSFNJL6OiCi2vIepw6gfLbmo
+ RAUjyQsWbv15IiNX5+hokCcADYY69RoSHNZhnEdTlG0x2uIjCyZPD50yqvLI2pU2lHBf
+ qzBr81dMZVLXdpWvsuwcaAzPq5aav6hPfN8rDEuS114bLA5OzoCKQH8KIu9493BBMXBl
+ wb0Hu7JwSyCqJLNQEp0pakRem5Bmrj3ubZgmymmG6XiXMyxR4gcbRwFkplq2s3lxkY9Y
+ boNBPzkawfg43jBxtYCiVeqc39siobVzUDHOZxlHLMnlwBA5SZivUKfw4xjj4N76Ht91
+ Mc+8y6jZOHBpIndkZdtFy0DKJawieBt0QMAHnpbvXASJvaYVWTMGzuQxi4Ewz3HUwNc9
+ BRnskUtg70P1QnpgwRE7VaiwwKZl2A2e8dJ7QutW7iB6NoRHYiM3AmjmCOdCnwh1lj5I
+ KXIHlDeie8wc2fxIEWVhDBrHacteQAeprsSy2MEyQRAMpor3wRmtzCEPrXheVbhZVpaU
+ V7vhcsrbnmVk0CZMIOpS0eZVFuf5ui+kV5AZw847tX5FAiRLhWeCz00wa+AncxSYTYbB
+ BGnqxA5HKRIyG29uqCILTl6FxdSx25i9eN1FErb8GOywtKIXElSvMME9Af3k4ivKUwQD
+ rztGlWqn47I35zXcFskDC4BLlcH4UPH0+LIM4oQziJKEFBpK+JrcIU9lAMuHD4Ou+5Uq
+ Z668OQ7Nn3DXmVhu6zyMlC8KPdQuveRcE1ahzxhdRVfnsoW3eyLRcwuX2BnRsFF4Uslv
+ sWlxFlYn+2jgzIPGsmP5scb2iYHziq+hMoHHX3hyJs++2N8xhnwrdPSrWHgH9+KX1bxl
+ 2x0UIamEHSdiSyNKxTPHLEPuUstgSm7yjeeSmVaRcKJgPaG4DSXzJXkqA7KE3c1c1113
+ HDJxYrmt82TZ+aztl6YtBiSnprKaJeyrcAn7Its9UQnbN2KUxx5dFG/I8zSX4SFCLvVH
+ PMN0iJ0I5B67nyz3hh7GebysofSTimx2L8nDr5o6Nzpxyvz9MDRKHJCwxENcC+tWk/Og
+ 3Ypy5Zqyu7hz1muU2rKhzkbCj1xaK87GwaqKOULJXYoqchoHnKAAcceTal1OwA0PKWBR
+ RXk2M8q5bTodOU/kO3pL+qYAjgrpO9T4GsehSUZLmjaLqFjnUPulbWdFdEZVEXUNjSKW
+ XSjGqTviiug7JEW47GqENSIK3h+bqzm+pCgPp/0lRZG0xNZlv7Kr2c+6GivnWWwmj7bL
+ Q4pPdTXZUXJtYRU4OUwUJEF2sRgui3TimorqG7EVAp14a2MxvYDEWBks8pXXhvsYm7OE
+ 9Dd/z2eJAVm+HJM21DfdcYjLaOWmzpIl53O2X9p26WWMlqNE11Cdmi9Rjg7bETtKDH6K
+ ozEJ3rfV51y7Ef1wDJ+x1sccTXnc5dZ6dDT906v53YU5gX9ohf6d/nXq7i7u1eox5Z2M
+ V8JGniJ3cSTZ5p1OBpG3nK1EdxmMHPz6TU+rBsNVEL2twzyKpjlIaF0u5J0cBas6lVSv
+ +soI4HVPIsiFP7EZj1k6Ekdl0ihVDJedDPYOgA8DVw0lgkVm8XGrLqnOy35UngBEb1qE
+ VuchMZUNJM4jjeDMJvjlDDWD/lggkiSMFsWSN+fjk33D43fzD5Xn6wKIovH9Lm7AVtyA
+ Jj7eEYmKy828CxT314obv9GKeyNdypfzLm4Ccpuq479NnIgbsBU3YJWKUWowkmkbCK3k
+ AO/kDkDtyHsJOZ5sHKAuycTNIudGugCn4gbxFD/hsjxEI5IRRp5gn3MSZrRWcbcHR+Xh
+ evO03azc/t5dulm79zAidmd3992FvcjsyuPy/wBuuobCCmVuZHN0cmVhbQplbmRvYmoK
+ NiAwIG9iago0MjM5CmVuZG9iagozIDAgb2JqCjw8IC9UeXBlIC9QYWdlIC9QYXJlbnQg
+ NCAwIFIgL1Jlc291cmNlcyA3IDAgUiAvQ29udGVudHMgNSAwIFIgL01lZGlhQm94IFsw
+ IDAgNTc2IDczM10KPj4KZW5kb2JqCjcgMCBvYmoKPDwgL1Byb2NTZXQgWyAvUERGIC9U
+ ZXh0IC9JbWFnZUIgL0ltYWdlQyAvSW1hZ2VJIF0gL0NvbG9yU3BhY2UgPDwgL0NzMiAy
+ NiAwIFIKL0NzMSA4IDAgUiA+PiAvRXh0R1N0YXRlIDw8IC9HczIgMzcgMCBSIC9HczEg
+ MzggMCBSID4+IC9Gb250IDw8IC9GMS4wIDI3IDAgUgo+PiAvWE9iamVjdCA8PCAvSW0z
+ IDEzIDAgUiAvSW0yIDExIDAgUiAvSW02IDE5IDAgUiAvSW03IDIxIDAgUiAvSW0xIDkg
+ MCBSCi9JbTggMjMgMCBSIC9JbTUgMTcgMCBSIC9JbTQgMTUgMCBSID4+IC9TaGFkaW5n
+ IDw8IC9TaDMgMjkgMCBSIC9TaDIgMjggMCBSCi9TaDEgMjUgMCBSIC9TaDUgMzEgMCBS
+ IC9TaDkgMzUgMCBSIC9TaDEwIDM2IDAgUiAvU2g4IDM0IDAgUiAvU2g3IDMzIDAgUiAv
+ U2g0CjMwIDAgUiAvU2g2IDMyIDAgUiA+PiA+PgplbmRvYmoKMjkgMCBvYmoKPDwgL0Nv
+ bG9yU3BhY2UgMzkgMCBSIC9TaGFkaW5nVHlwZSAyIC9Db29yZHMgWyA5NS41IC0yNC4w
+ MDg4NCA5NS41IDI0LjAwODg3Cl0gL0RvbWFpbiBbIDAgMSBdIC9FeHRlbmQgWyBmYWxz
+ ZSBmYWxzZSBdIC9GdW5jdGlvbiA0MCAwIFIgPj4KZW5kb2JqCjI4IDAgb2JqCjw8IC9D
+ b2xvclNwYWNlIDM5IDAgUiAvU2hhZGluZ1R5cGUgMiAvQ29vcmRzIFsgOTUuNSAtMjQu
+ MDA4ODQgOTUuNSAyNC4wMDg4NwpdIC9Eb21haW4gWyAwIDEgXSAvRXh0ZW5kIFsgZmFs
+ c2UgZmFsc2UgXSAvRnVuY3Rpb24gNDEgMCBSID4+CmVuZG9iagoyNSAwIG9iago8PCAv
+ Q29sb3JTcGFjZSAzOSAwIFIgL1NoYWRpbmdUeXBlIDIgL0Nvb3JkcyBbIDEyMC4yNSAt
+ ODkuOTk5OTggMTIwLjI1IDkwLjAwMDA0Cl0gL0RvbWFpbiBbIDAgMSBdIC9FeHRlbmQg
+ WyBmYWxzZSBmYWxzZSBdIC9GdW5jdGlvbiA0MiAwIFIgPj4KZW5kb2JqCjMxIDAgb2Jq
+ Cjw8IC9Db2xvclNwYWNlIDM5IDAgUiAvU2hhZGluZ1R5cGUgMiAvQ29vcmRzIFsgOTUu
+ NSAtMzQuNSA5NS40OTk5OCAzNC41MDAwNApdIC9Eb21haW4gWyAwIDEgXSAvRXh0ZW5k
+ IFsgZmFsc2UgZmFsc2UgXSAvRnVuY3Rpb24gNDMgMCBSID4+CmVuZG9iagozNSAwIG9i
+ ago8PCAvQ29sb3JTcGFjZSAzOSAwIFIgL1NoYWRpbmdUeXBlIDIgL0Nvb3JkcyBbIDc5
+ IC0xMi41IDc5IDEyLjUwMDAzIF0gL0RvbWFpbgpbIDAgMSBdIC9FeHRlbmQgWyBmYWxz
+ ZSBmYWxzZSBdIC9GdW5jdGlvbiA0NCAwIFIgPj4KZW5kb2JqCjM2IDAgb2JqCjw8IC9D
+ b2xvclNwYWNlIDM5IDAgUiAvU2hhZGluZ1R5cGUgMiAvQ29vcmRzIFsgNTQuMDE2NSAt
+ MTYgNTQuMDE2NDkgMTYuMDAwMDIKXSAvRG9tYWluIFsgMCAxIF0gL0V4dGVuZCBbIGZh
+ bHNlIGZhbHNlIF0gL0Z1bmN0aW9uIDQ1IDAgUiA+PgplbmRvYmoKMzQgMCBvYmoKPDwg
+ L0NvbG9yU3BhY2UgMzkgMCBSIC9TaGFkaW5nVHlwZSAyIC9Db29yZHMgWyA3OSAtMTIu
+ NSA3OSAxMi41MDAwMyBdIC9Eb21haW4KWyAwIDEgXSAvRXh0ZW5kIFsgZmFsc2UgZmFs
+ c2UgXSAvRnVuY3Rpb24gNDYgMCBSID4+CmVuZG9iagozMyAwIG9iago8PCAvQ29sb3JT
+ cGFjZSAzOSAwIFIgL1NoYWRpbmdUeXBlIDIgL0Nvb3JkcyBbIDk1LjUgLTM3LjE2OTcg
+ OTUuNDk5OTggMzcuMTY5NzQKXSAvRG9tYWluIFsgMCAxIF0gL0V4dGVuZCBbIGZhbHNl
+ IGZhbHNlIF0gL0Z1bmN0aW9uIDQ3IDAgUiA+PgplbmRvYmoKMzAgMCBvYmoKPDwgL0Nv
+ bG9yU3BhY2UgMzkgMCBSIC9TaGFkaW5nVHlwZSAyIC9Db29yZHMgWyAxMjAuMjUgLTE3
+ NS44MzUgMTIwLjI0OTkgMTc1LjgzNTEKXSAvRG9tYWluIFsgMCAxIF0gL0V4dGVuZCBb
+ IGZhbHNlIGZhbHNlIF0gL0Z1bmN0aW9uIDQ4IDAgUiA+PgplbmRvYmoKMzIgMCBvYmoK
+ PDwgL0NvbG9yU3BhY2UgMzkgMCBSIC9TaGFkaW5nVHlwZSAyIC9Db29yZHMgWyA5NS41
+ IC0yNS41ODQ4NSA5NS40OTk5OCAyNS41ODQ4OQpdIC9Eb21haW4gWyAwIDEgXSAvRXh0
+ ZW5kIFsgZmFsc2UgZmFsc2UgXSAvRnVuY3Rpb24gNDkgMCBSID4+CmVuZG9iagoxMyAw
+ IG9iago8PCAvTGVuZ3RoIDE0IDAgUiAvVHlwZSAvWE9iamVjdCAvU3VidHlwZSAvSW1h
+ Z2UgL1dpZHRoIDUwMiAvSGVpZ2h0IDg4MiAvSW50ZXJwb2xhdGUKdHJ1ZSAvQ29sb3JT
+ cGFjZSA1MCAwIFIgL0ludGVudCAvUGVyY2VwdHVhbCAvU01hc2sgNTEgMCBSIC9CaXRz
+ UGVyQ29tcG9uZW50CjggL0ZpbHRlciAvRmxhdGVEZWNvZGUgPj4Kc3RyZWFtCngB7dAx
+ AQAAAMKg9U9tCy+IQGHAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDA
+ gAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwY
+ MGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAED
+ BgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDA
+ gAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwY
+ MGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAED
+ BgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDA
+ gAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwY
+ MGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAED
+ BgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDA
+ gAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwY
+ MGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAED
+ BgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDA
+ gAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwY
+ MGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAED
+ BgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDA
+ gAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwY
+ MGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAED
+ BgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDA
+ gAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwY
+ MGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAED
+ BgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDA
+ gAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwY
+ MGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAED
+ BgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDA
+ gAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwY
+ MGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAED
+ BgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDA
+ gAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwY
+ MGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAED
+ BgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDA
+ gAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwY
+ MGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAED
+ BgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDA
+ gAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwY
+ MGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAED
+ BgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDA
+ gAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwY
+ MGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAED
+ BgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDA
+ gAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwY
+ MGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAED
+ BgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDA
+ gAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwY
+ MGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAED
+ BgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDA
+ gAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwY
+ MGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAED
+ BgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDA
+ gAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwY
+ MGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAED
+ BgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDA
+ gAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwY
+ MGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAED
+ BgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDA
+ gAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwY
+ MGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAED
+ BgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDA
+ gAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwY
+ MGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAED
+ BgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDA
+ gAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwY
+ MGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAED
+ BgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDA
+ gAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwY
+ MGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAED
+ BgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDA
+ gAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwY
+ MGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAED
+ BgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDA
+ gAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwY
+ MGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAED
+ BgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDA
+ gAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwY
+ MGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAED
+ BgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDA
+ gAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwY
+ MGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAED
+ BgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDA
+ gAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwY
+ MGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAED
+ BgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDA
+ gAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwY
+ MGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAED
+ BgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDA
+ gAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwY
+ MGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAED
+ BgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDA
+ gAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwY
+ MGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAED
+ BgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDA
+ gAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwY
+ MGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAED
+ BgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDA
+ gAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwY
+ MGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAED
+ BgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDA
+ gAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwY
+ MGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAED
+ BgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDA
+ gAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwY
+ MGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAED
+ BgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDA
+ gAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwY
+ MGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAED
+ BgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDA
+ gAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwY
+ MGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAED
+ BgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDA
+ gAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwY
+ MGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAED
+ BgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDA
+ gAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwY
+ MGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgIHfwABF0AABCmVu
+ ZHN0cmVhbQplbmRvYmoKMTQgMCBvYmoKNTgxNgplbmRvYmoKMTEgMCBvYmoKPDwgL0xl
+ bmd0aCAxMiAwIFIgL1R5cGUgL1hPYmplY3QgL1N1YnR5cGUgL0ltYWdlIC9XaWR0aCA0
+ MDIgL0hlaWdodCAxMTYgL0ludGVycG9sYXRlCnRydWUgL0NvbG9yU3BhY2UgNTAgMCBS
+ IC9JbnRlbnQgL1BlcmNlcHR1YWwgL1NNYXNrIDUzIDAgUiAvQml0c1BlckNvbXBvbmVu
+ dAo4IC9GaWx0ZXIgL0ZsYXRlRGVjb2RlID4+CnN0cmVhbQp4Ae3QMQEAAADCoPVPbQdv
+ iEBhwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIAB
+ AwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBg
+ wIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYM
+ GDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIAB
+ AwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBg
+ wIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYM
+ GDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIAB
+ AwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBg
+ wIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYM
+ GDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIAB
+ AwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBg
+ wIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwb+
+ gQEilgABCmVuZHN0cmVhbQplbmRvYmoKMTIgMCBvYmoKNjM0CmVuZG9iagoxOSAwIG9i
+ ago8PCAvTGVuZ3RoIDIwIDAgUiAvVHlwZSAvWE9iamVjdCAvU3VidHlwZSAvSW1hZ2Ug
+ L1dpZHRoIDQwMiAvSGVpZ2h0IDE3MCAvSW50ZXJwb2xhdGUKdHJ1ZSAvQ29sb3JTcGFj
+ ZSA1MCAwIFIgL0ludGVudCAvUGVyY2VwdHVhbCAvU01hc2sgNTUgMCBSIC9CaXRzUGVy
+ Q29tcG9uZW50CjggL0ZpbHRlciAvRmxhdGVEZWNvZGUgPj4Kc3RyZWFtCngB7dABDQAA
+ AMKg909tDjeIQGHAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAED
+ BgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDA
+ gAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwY
+ MGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAED
+ BgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDA
+ gAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwY
+ MGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAED
+ BgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDA
+ gAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwY
+ MGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAED
+ BgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDA
+ gAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwY
+ MGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAED
+ BgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDA
+ gAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwY
+ MGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAED
+ BgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDA
+ gAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDgY2AhCQABCmVuZHN0cmVh
+ bQplbmRvYmoKMjAgMCBvYmoKOTE3CmVuZG9iagoyMSAwIG9iago8PCAvTGVuZ3RoIDIy
+ IDAgUiAvVHlwZSAvWE9iamVjdCAvU3VidHlwZSAvSW1hZ2UgL1dpZHRoIDMzNiAvSGVp
+ Z2h0IDcwIC9JbnRlcnBvbGF0ZQp0cnVlIC9Db2xvclNwYWNlIDUwIDAgUiAvSW50ZW50
+ IC9QZXJjZXB0dWFsIC9TTWFzayA1NyAwIFIgL0JpdHNQZXJDb21wb25lbnQKOCAvRmls
+ dGVyIC9GbGF0ZURlY29kZSA+PgpzdHJlYW0KeAHt0DEBAAAAwqD1T20MH4hAYcCAAQMG
+ DBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCA
+ AQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgw
+ YMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMG
+ DBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCA
+ AQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgw
+ YMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgw8BwYE68A
+ AQplbmRzdHJlYW0KZW5kb2JqCjIyIDAgb2JqCjMzMQplbmRvYmoKOSAwIG9iago8PCAv
+ TGVuZ3RoIDEwIDAgUiAvVHlwZSAvWE9iamVjdCAvU3VidHlwZSAvSW1hZ2UgL1dpZHRo
+ IDUwMiAvSGVpZ2h0IDQ5MCAvSW50ZXJwb2xhdGUKdHJ1ZSAvQ29sb3JTcGFjZSA1MCAw
+ IFIgL0ludGVudCAvUGVyY2VwdHVhbCAvU01hc2sgNTkgMCBSIC9CaXRzUGVyQ29tcG9u
+ ZW50CjggL0ZpbHRlciAvRmxhdGVEZWNvZGUgPj4Kc3RyZWFtCngB7dAxAQAAAMKg9U9t
+ B2+IQGHAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDA
+ gAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwY
+ MGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAED
+ BgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDA
+ gAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwY
+ MGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAED
+ BgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDA
+ gAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwY
+ MGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAED
+ BgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDA
+ gAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwY
+ MGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAED
+ BgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDA
+ gAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwY
+ MGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAED
+ BgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDA
+ gAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwY
+ MGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAED
+ BgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDA
+ gAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwY
+ MGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAED
+ BgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDA
+ gAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwY
+ MGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAED
+ BgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDA
+ gAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwY
+ MGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAED
+ BgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDA
+ gAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwY
+ MGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAED
+ BgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDA
+ gAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwY
+ MGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAED
+ BgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDA
+ gAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwY
+ MGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAED
+ BgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDA
+ gAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwY
+ MGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAED
+ BgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDA
+ gAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwY
+ MGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAED
+ BgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDA
+ gAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwY
+ MGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAED
+ BgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDA
+ gAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwY
+ MGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAED
+ BgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDA
+ gAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwY
+ MGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAED
+ BgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDA
+ gAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwY
+ MGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAED
+ BgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDA
+ gAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwY
+ MGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAED
+ BgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDA
+ gAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwY
+ MGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAED
+ BgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDA
+ gAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwY
+ MGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAED
+ BgwYMGDAgIF/YEM5AAEKZW5kc3RyZWFtCmVuZG9iagoxMCAwIG9iagozMjQxCmVuZG9i
+ agoyMyAwIG9iago8PCAvTGVuZ3RoIDI0IDAgUiAvVHlwZSAvWE9iamVjdCAvU3VidHlw
+ ZSAvSW1hZ2UgL1dpZHRoIDIzNiAvSGVpZ2h0IDg0IC9JbnRlcnBvbGF0ZQp0cnVlIC9D
+ b2xvclNwYWNlIDUwIDAgUiAvSW50ZW50IC9QZXJjZXB0dWFsIC9TTWFzayA2MSAwIFIg
+ L0JpdHNQZXJDb21wb25lbnQKOCAvRmlsdGVyIC9GbGF0ZURlY29kZSA+PgpzdHJlYW0K
+ eAHt0DEBAAAAwqD1T20MH4hAYcCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMG
+ DBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCA
+ AQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgw
+ YMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMG
+ DBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCA
+ AQMGDBgwYMCAAQMGDBgwYMCAAQMG/gMD6FAAAQplbmRzdHJlYW0KZW5kb2JqCjI0IDAg
+ b2JqCjI4MwplbmRvYmoKMTcgMCBvYmoKPDwgL0xlbmd0aCAxOCAwIFIgL1R5cGUgL1hP
+ YmplY3QgL1N1YnR5cGUgL0ltYWdlIC9XaWR0aCA0MDIgL0hlaWdodCAxMjIgL0ludGVy
+ cG9sYXRlCnRydWUgL0NvbG9yU3BhY2UgNTAgMCBSIC9JbnRlbnQgL1BlcmNlcHR1YWwg
+ L1NNYXNrIDYzIDAgUiAvQml0c1BlckNvbXBvbmVudAo4IC9GaWx0ZXIgL0ZsYXRlRGVj
+ b2RlID4+CnN0cmVhbQp4Ae3QMQEAAADCoPVPbQlPiEBhwIABAwYMGDBgwIABAwYMGDBg
+ wIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYM
+ GDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIAB
+ AwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBg
+ wIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYM
+ GDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIAB
+ AwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBg
+ wIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYM
+ GDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIAB
+ AwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBg
+ wIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYM
+ GDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIAB
+ AwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBg
+ wIABAwYMGDBg4DMwPtoAAQplbmRzdHJlYW0KZW5kb2JqCjE4IDAgb2JqCjY2NQplbmRv
+ YmoKMTUgMCBvYmoKPDwgL0xlbmd0aCAxNiAwIFIgL1R5cGUgL1hPYmplY3QgL1N1YnR5
+ cGUgL0ltYWdlIC9XaWR0aCA0MDIgL0hlaWdodCAyMzggL0ludGVycG9sYXRlCnRydWUg
+ L0NvbG9yU3BhY2UgNTAgMCBSIC9JbnRlbnQgL1BlcmNlcHR1YWwgL1NNYXNrIDY1IDAg
+ UiAvQml0c1BlckNvbXBvbmVudAo4IC9GaWx0ZXIgL0ZsYXRlRGVjb2RlID4+CnN0cmVh
+ bQp4Ae3QMQEAAADCoPVPbQwfiEBhwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIAB
+ AwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBg
+ wIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYM
+ GDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIAB
+ AwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBg
+ wIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYM
+ GDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIAB
+ AwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBg
+ wIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYM
+ GDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIAB
+ AwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBg
+ wIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYM
+ GDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIAB
+ AwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBg
+ wIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYM
+ GDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIAB
+ AwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBg
+ wIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYM
+ GDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIAB
+ AwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBg
+ wIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYM
+ GDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIAB
+ AwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBg
+ wIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYM
+ GDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGPgPDGFw
+ AAEKZW5kc3RyZWFtCmVuZG9iagoxNiAwIG9iagoxMjc1CmVuZG9iago1MyAwIG9iago8
+ PCAvTGVuZ3RoIDU0IDAgUiAvVHlwZSAvWE9iamVjdCAvU3VidHlwZSAvSW1hZ2UgL1dp
+ ZHRoIDQwMiAvSGVpZ2h0IDExNiAvQ29sb3JTcGFjZQovRGV2aWNlR3JheSAvSW50ZXJw
+ b2xhdGUgdHJ1ZSAvQml0c1BlckNvbXBvbmVudCA4IC9GaWx0ZXIgL0ZsYXRlRGVjb2Rl
+ ID4+CnN0cmVhbQp4Ae2dW1PaWhiGyUpCQiAcKycL21Y51EOcwSJGBTcWilAREQL0//+R
+ HWrbASrfHeubPX2/Gy7eCS/zPKy14GoFAhgQAAEQAAEQAAEQAAE5BBQhVIxUAkIoyja5
+ ilD1oGGGMDIJmIauqW87UVTdDNuxRBIjkUAiHo1YhibecCLUYDiWyuTfF4oYeQQK+7l0
+ 0g7pfy4TRTUiqfxB6fjUcc4xsgg4ZyfVw0Imbumbq0RRg5F3hbJTd2+bLYw8As2bRu3k
+ MJ/wlayf70IPpwrV2k2723voY+QRePjaaTWco1zM3Ni3VDOWK9ea3W9Po+cxRh6B59Gw
+ f++efdiLrC8SRQunDpyb7uN46nkzjDwCnjcZDdqX1by/SFa3LRG0M6V6ezD25vPFYvEd
+ I4eAz3o+m456t84/KUtb/QUsjFj+2O0+TZc+YESOjh8tSyUvg38vDv1ta9WIaiben972
+ Rh5WiEQbv5RMHr9cljL2upFQouA0H549LBDZRr4v5pNhp1HJ2sG1NRJKFp1Wf+wbkf6J
+ /vrC+fSpe1XJRf8wcg4jPF+OpRG3usXIjOcz/d2tv42s/mtX/V1ruUZghOHLASMM0MlK
+ GCHxMIQwwgCdrIQREg9DCCMM0MlKGCHxMIQwwgCdrIQREg9DCCMM0MlKGCHxMIQwwgCd
+ rIQREg9DCCMM0MlKGCHxMIQwwgCdrIQREg9DCCMM0MlKGCHxMIQwwgCdrIQREg9DCCMM
+ 0MlKGCHxMIQwwgCdrIQREg9DCCMM0MlKGCHxMIQwwgCdrIQREg9DCCMM0MlKGCHxMIQw
+ wgCdrIQREg9DCCMM0MlKGCHxMIQwwgCdrIQREg9DCCMM0MlKGCHxMIQwwgCdrIQREg9D
+ CCMM0MlKGCHxMIQwwgCdrIQREg9DCCMM0MlKGCHxMIQwwgCdrIQREg9DCCMM0MlKGCHx
+ MIQwwgCdrIQREg9DCCMM0MlKGCHxMIQwwgCdrIQREg9DCCMM0MlKGCHxMIQwwgCdrIQR
+ Eg9DCCMM0MlKGCHxMIQwwgCdrIQREg9DCCMM0MlKGCHxMIQwwgCdrIQREg9DCCMM0MlK
+ GCHxMIQwwgCdrIQREg9DCCMM0MnK30Y2bzp+vVeXfBbhLghsNfJ69/QuKvGeBIHFwjfS
+ uapkN++eThTOXu9nJx5GtAMCvpHl/ezlzPr97MKM75/cfB1N57igfQfUt7/lwp/Zy+N9
+ vZSO6KvniDCiuWqjM5zMoGQ7vh0kvpC5N+7f1T6+C2urRhQ9kj6q3fWfp7M5RiqBmTcZ
+ dq9PC8mQGlgZRbOShZOr+8HoZTLFyCQwGQ97rYtSNmqIFSGBgDDszOG52+59Gz5hJBIY
+ Pg66rfpxMWWtHSOBgKKF4vkj57LZ/tLFSCTQub+7vjg+SNuGunqM+MtF6FYi9+HT+efL
+ K9e9xsgh4LqNeu2sXExHzbVzfbl/Kapuxfb2D47KlU8YaQSqldLHYi5lm9r6KfJTiRmJ
+ p9KZbA4jj0A2s5eMhg1NbOxZP5QILWhaETuKkUnADluGvnmGLH0sRxGqpgeDQQMjiYAP
+ W9c19a0F8qrEl6IoAiORgA/8jf3qlw68ggAIgAAIgAAI/N8J/Ac/+KIKCmVuZHN0cmVh
+ bQplbmRvYmoKNTQgMCBvYmoKMTIwNAplbmRvYmoKNjMgMCBvYmoKPDwgL0xlbmd0aCA2
+ NCAwIFIgL1R5cGUgL1hPYmplY3QgL1N1YnR5cGUgL0ltYWdlIC9XaWR0aCA0MDIgL0hl
+ aWdodCAxMjIgL0NvbG9yU3BhY2UKL0RldmljZUdyYXkgL0ludGVycG9sYXRlIHRydWUg
+ L0JpdHNQZXJDb21wb25lbnQgOCAvRmlsdGVyIC9GbGF0ZURlY29kZSA+PgpzdHJlYW0K
+ eAHtl2tT2moUhUlCLtwFVISCekopViGdQ+sdGKkgl4MClQD9/3+koTNtwcv2i33XnOna
+ n2DWkJV5HvZLCAQ4JEACJEACJEACJEACaghoum5wlBLQdU17Tq6mG6ZlOyGOSgKObQaN
+ p51ohulEYolkiqOQQHIjHg3bQf0JJ7phRRLpTC5f2OWoI1B4k91OxULm4zXRDDuazu2X
+ Diuu+5GjioBbPTooFjIbYfPhlmiGFd0svHePz+uNJkcdgcblae2omEv6StZ/33Uzki4c
+ 1C5bnW6vz1FHoHfTbp6677IJ58G5ZTiJ7Ptao/Pf3Wg84agjMB7d9r+cV//Ziq4viRaM
+ pPfdy85wMvW8GUcdAc+7Hw1aJwc5f0lWjy3dimVKx63BxJvPF4vFN44aAj7r+Ww66tbd
+ vXQ4uPoErNuJ3OF552669EEjanT8aFkq+Tq4+lT0j61VI4aTzFfq3ZHHDVFo46eS++H1
+ SSkTWzcSShbcRm/scUFUG/m2mN/ftk/LOzFrbUdCqV232Z/4RpTf0V9fOJ/edc7K2fgj
+ Ix9pBPPlWBo5P3jGyAxzT3936y8jq//aDf/UWu4IjQC+HDQCgC5W0oiIBxDSCAC6WEkj
+ Ih5ASCMA6GIljYh4ACGNAKCLlTQi4gGENAKALlbSiIgHENIIALpYSSMiHkBIIwDoYiWN
+ iHgAIY0AoIuVNCLiAYQ0AoAuVtKIiAcQ0ggAulhJIyIeQEgjAOhiJY2IeAAhjQCgi5U0
+ IuIBhDQCgC5W0oiIBxDSCAC6WEkjIh5ASCMA6GIljYh4ACGNAKCLlTQi4gGENAKALlbS
+ iIgHENIIALpYSSMiHkBIIwDoYiWNiHgAIY0AoIuVNCLiAYQ0AoAuVtKIiAcQ0ggAulhJ
+ IyIeQEgjAOhiJY2IeAAhjQCgi5U0IuIBhDQCgC5W0oiIBxDSCAC6WEkjIh5ASCMA6GIl
+ jYh4ACGNAKCLlTQi4gGENAKALlbSiIgHENIIALpYSSMiHkBIIwDoYiWNiHgAIY0AoIuV
+ NCLiAYQ0AoAuVtKIiAcQ0ggAulhJIyIeQEgjAOhiJY2IeAAhjQCgi5U0IuIBhDQCgC5W
+ 0oiIBxDSCAC6WEkjIh5ASCMA6GIljYh4ACGNAKCLlaIRbyF+luGfIPDLiBb4PUYotes2
+ +xMa+RPIX7jm0shZORu31o0kC26jN/YWC27JCwBfO17M72/bp+Wd2LoRJ5mv1Lsjb04l
+ r038hestfCPD65NSJmau7ohuJ3Ifzju3Uxp5AeBrx76Q2dfB1afiVmTdiBXLlD63BhNv
+ TievDV24nn8izWfTu5u6u5cKB1d3RAuG03vuRXs4mXr+zDhqCPisp/ejfuv4IJdwjN9P
+ Wv4rw05kS7V6e3A7Go8nHEUExuPR3bDXOqvub0ZMfc2IboZThXLt4qp90+31OYoI9Hrd
+ m+vmiVvc8Vdk9dAKBDTDim7mS9XPZ5eNRpOjikCjfnH67+Hb7EbowYosldjRVHbv3Yej
+ StXlqCJQrRyW3+a3E2FTX18R/wTztyQcT29n3+QLHHUE8rmdrWTM35BHQpZKTDsci28k
+ /UlxFBBYkk4m4tGQFXxKiK9EN4KW7TghjjoCjm2Zz/j48eilabpucBQS0HVde+LAWnsQ
+ 5hsSIAESIAESIIH/L4HvkRHshAplbmRzdHJlYW0KZW5kb2JqCjY0IDAgb2JqCjEyNDMK
+ ZW5kb2JqCjYxIDAgb2JqCjw8IC9MZW5ndGggNjIgMCBSIC9UeXBlIC9YT2JqZWN0IC9T
+ dWJ0eXBlIC9JbWFnZSAvV2lkdGggMjM2IC9IZWlnaHQgODQgL0NvbG9yU3BhY2UKL0Rl
+ dmljZUdyYXkgL0ludGVycG9sYXRlIHRydWUgL0JpdHNQZXJDb21wb25lbnQgOCAvRmls
+ dGVyIC9GbGF0ZURlY29kZSA+PgpzdHJlYW0KeAHtnGtz6VAUhuUekYhI0Wg5Tl2qWjHD
+ cavSoVKl4tII9f//yEnq9LBbvnfvWe8HY5sxs961nsiYeVcCARB0ADoAHYAO/JwOUDTN
+ kCOaok61lqIZjhfEICkSBZ5ljtulGE4MKaoWJURaJCxLAksfmS3N8CFVTyQvU2kylLo0
+ 4lElyDHfzFKMIOvJTL50Z5oVEmSWb4u5dEKT+K9mKYaXz1IFs95+6PbIULfTqt1lk5rE
+ 0egvFM2F9FSx2ulbo5cxGXp5Hj62KjlDDbIoxYyoGoVq13qdzRdLMrSY2+NB27yKyTwy
+ WIoN6RmzY02XK9ddkyHXdRaTQePmIiIyhxDTvJLI1/uTpbvZvL+/b/GX52KzWc1H3UpG
+ lxCIaUFNltrWbOU7JcLrduuZXb+99v/k4jJ3eMEyonZ59zCau4RM9YNLz6xjD5uFhMIj
+ XoNayuy+LFxShrozu1nNrHbRCH/xGk2bvfHS84r/pbp38OH15ojXCple7095Xe97QsI7
+ f66+V+HwBssEo2l/ruR5fb6/SarglQRy9x48hmGucL3ugcDwHTAM9xwMsUVKBoaBYQQI
+ DA/AMDCMIbZIycAwMIwAgeEBGAaGMcQWKRkYBoYRIDA8AMPAMIbYIiUDw8AwAgSGB2AY
+ GMYQW6RkYBgYRoDA8AAMA8MYYouUDAwDwwgQGB48hj9ya0gw/DO35hIVvdz+94pmaj9z
+ phhO71TJXn7Yz9R+z15qqfIuP3zqm/h97nu1h63rczQ/TIuRi9vO89zPwONn6mjFfpZ/
+ 40yfGvmEgmTgaSFsFJtD21kTY9a36i4nj9VsLIR4pTg5nq0+juer9YYYrV3HtjrldBTd
+ 46BYKZq6bQ4m8zdnRYgcZ2mPerWCF5VG9nMC/oJO1mz3R69Te0aG7OnE6tVLaR1FOBCg
+ 2GAkmSs3HvpPQ4sMDQeP97VSJq4IXxclaU7SjN9Fs9ZotolQq1mvlgvpeFhEtq78bTNv
+ q1lSYxe/svnrIhG6LuSv0oauiOzhYsNusY6iOVFW9Vji3CBC54n4WTQcOr7ETdEsL0qy
+ EiZEihwKCkc2uD9Hy7AcT4w47tRjCP7ZpSjvGRNEyHNy+Pdm5w9eoQPQAejAj+vAX1W0
+ pJsKZW5kc3RyZWFtCmVuZG9iago2MiAwIG9iago4NDIKZW5kb2JqCjY1IDAgb2JqCjw8
+ IC9MZW5ndGggNjYgMCBSIC9UeXBlIC9YT2JqZWN0IC9TdWJ0eXBlIC9JbWFnZSAvV2lk
+ dGggNDAyIC9IZWlnaHQgMjM4IC9Db2xvclNwYWNlCi9EZXZpY2VHcmF5IC9JbnRlcnBv
+ bGF0ZSB0cnVlIC9CaXRzUGVyQ29tcG9uZW50IDggL0ZpbHRlciAvRmxhdGVEZWNvZGUg
+ Pj4Kc3RyZWFtCngB7ddrU5J7FIZxeTgjB9EUtU0nQx0PNOlWMg9tDfKQiAoIff8vsqGm
+ Aqu7/aKee/Z0rTe9WFOr+V3+oSYmGAQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAA
+ AQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAAB
+ BBBAAAEEEPj/CkSCIMqEKhAEkciPfmAiQTSeSKbSTJgCqWQ8Fv1+k0g0nprMFYrTTIgC
+ xal8NpOMBd9pEkQTk4WZ0uJf5UdMeALlhwtz07l0/NtnEokmszOLTyprG9XqCyYsgerm
+ +upSuTSVid9/JZFoIvugvFzd2Ts4PGLCEzjcr22tLy0WB0nGv9+D+ORMeXVr/7hxenbO
+ hCdw9q5+VKs+Xyik7n1uRVOFheWtw8b7q9b1DROewHWreX6yt/l0Njv+SCKxyZkn1f3G
+ 5U2n271jwhPodtuti+Pd1cXBIxn92AoSuVJl5/jiptvr9fv9D0w4AgPr3l2ndXpQfTyT
+ iY3+CzhIFhbX9hpXnWEPioST4+OVYZLbi3+2lwYfW6NFoqniXxsHp60uLyTEGp+TtC/f
+ 7lZKufEi6WK5enh23eWBhF3kQ7/XbtZrK/O5xNgbSU8/qh6d3wyKhP43+uMP9jpXjVcr
+ C/lvirygiOeHY1hkb/UHRe48f6c/++qXIqP/a48OPrWGb4Qihh8OihjQ5UmKSB7DkiIG
+ dHmSIpLHsKSIAV2epIjkMSwpYkCXJykieQxLihjQ5UmKSB7DkiIGdHmSIpLHsKSIAV2e
+ pIjkMSwpYkCXJykieQxLihjQ5UmKSB7DkiIGdHmSIpLHsKSIAV2epIjkMSwpYkCXJyki
+ eQxLihjQ5UmKSB7DkiIGdHmSIpLHsKSIAV2epIjkMSwpYkCXJykieQxLihjQ5UmKSB7D
+ kiIGdHmSIpLHsKSIAV2epIjkMSwpYkCXJykieQxLihjQ5UmKSB7DkiIGdHmSIpLHsKSI
+ AV2epIjkMSwpYkCXJykieQxLihjQ5UmKSB7DkiIGdHmSIpLHsKSIAV2epIjkMSwpYkCX
+ JykieQxLihjQ5UmKSB7DkiIGdHmSIpLHsKSIAV2epIjkMSwpYkCXJykieQxLihjQ5UmK
+ SB7DkiIGdHmSIpLHsKSIAV2epIjkMSwpYkCXJykieQxLihjQ5UmKSB7DkiIGdHmSIpLH
+ sKSIAV2epIjkMSwpYkCXJykieQxLihjQ5UmKSB7DkiIGdHmSIpLHsKSIAV2epIjkMSwp
+ YkCXJykieQxLihjQ5UmKSB7DkiIGdHmSIpLHsKSIAV2epIjkMSwpYkCXJykieQxLihjQ
+ 5UmKSB7DkiIGdHmSIpLHsKSIAV2epIjkMSwpYkCXJykieQxLihjQ5UmKSB7DkiIGdHmS
+ IpLHsKSIAV2epIjkMSwpYkCXJykieQxLihjQ5UmKSB7DkiIGdHnyS5HIxNeJpqcfvTg6
+ v+n25e9l+TsEflikSpHf4f2zP7Pf73Wa9Vcr8/nE+BspljcPz667fR7Jzwh/8X5QpN2s
+ 15ZLubEiQWrq4fr+u1anR5JfLK7/uP5g7m4vT3Yqc9n46BsJkvmF1Vq92b4jiSb8xdtB
+ kF735vzNy2cPJmOjRSLx7NzS1pvzVueux4QqcNe9bTZeb5SL6ejXf2lNTERimenyeu3k
+ onXb7jAhCrTbN813h9uV+XwyGC0yESRypaXq3vHp+8vmFROaQLN5ed44+nutPJMZ+xoZ
+ PpL01OLzzd2D47f1BhOaQL1+8ub19trj2VwyOvo1MnguQTxTXHi6Wt3ere0xoQm8qu28
+ 3KiUZ/Opse/14edXJBrPFGYfPl6qrKwyoQmsLFeeleenc6nY+LfIxyRBPJUtzMyW5heY
+ 0ATmS3MPpvOZZCy495n1KUkskcpkc3kmRIFcdjKdjN//Dhn2GE4kiMbiCSZUgXh88D6+
+ 80A+JRlEGUzAhCcwBP+Mz68IIIAAAggggAACCCCAAAIIIIAAAggggAACCCCAAAIIIIAA
+ AggggAACCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAggggAAC
+ CPwXgX8B0P1liwplbmRzdHJlYW0KZW5kb2JqCjY2IDAgb2JqCjE1ODEKZW5kb2JqCjU1
+ IDAgb2JqCjw8IC9MZW5ndGggNTYgMCBSIC9UeXBlIC9YT2JqZWN0IC9TdWJ0eXBlIC9J
+ bWFnZSAvV2lkdGggNDAyIC9IZWlnaHQgMTcwIC9Db2xvclNwYWNlCi9EZXZpY2VHcmF5
+ IC9JbnRlcnBvbGF0ZSB0cnVlIC9CaXRzUGVyQ29tcG9uZW50IDggL0ZpbHRlciAvRmxh
+ dGVEZWNvZGUgPj4Kc3RyZWFtCngB7ZfZUhpbAEXpbuYGkcEJxVm0UNFgnKKY4IQ4gChT
+ /v9HbmNdE1DZb5z9kH1erMo2LGstT4M+n44MyIAMyIAMyIAMyIAZA5ZtOzpGDdi2ZY2K
+ a9lOIBgKR3RMGgiHAn7n6yaWEwi78UQypWPQQHJyIhYN+e0vmthO0E2kZ7ILuUUdcwZy
+ 83PTqXgk8PmaWE4ols4ubxR2isU9HVMGirvbW2u5mclo4OMtsZxgLJPLFw9Pz8sXOuYM
+ lM+OS9tr2aSXZPj93Q646dxW6axyU72r6ZgzcHd7fXFcXJ9LhD88t5xwYi5fKt881BvP
+ TR1zBp4bT7XL092VqdjwJbH8bnq5eHbz2Gy12x0dcwba7dfGfeVoK+tdksHHlh2Mz2wc
+ Vu6b7W631+v91jFjwHPd7bQa1fPiUjrqH/wEbIcS2cLpTb3V76EiZnK8UfpJXu5/Hax5
+ j63BIk44ubBzXm20dUMM1nhP8vp4dbQxEx8uEknmiuW757YuiOkiv3vd16fr483ZeHDo
+ jkRSi8WLWtMrYvwn+ueB3Vb95mRzbuJTkT0V4fxy9Iucbo0o0uH8TP829U+Rwb/aHe+p
+ 1b8jKkL45VARgnSIVBGohzCqCEE6RKoI1EMYVYQgHSJVBOohjCpCkA6RKgL1EEYVIUiH
+ SBWBegijihCkQ6SKQD2EUUUI0iFSRaAewqgiBOkQqSJQD2FUEYJ0iFQRqIcwqghBOkSq
+ CNRDGFWEIB0iVQTqIYwqQpAOkSoC9RBGFSFIh0gVgXoIo4oQpEOkikA9hFFFCNIhUkWg
+ HsKoIgTpEKkiUA9hVBGCdIhUEaiHMKoIQTpEqgjUQxhVhCAdIlUE6iGMKkKQDpEqAvUQ
+ RhUhSIdIFYF6CKOKEKRDpIpAPYRRRQjSIVJFoB7CqCIE6RCpIlAPYVQRgnSIVBGohzCq
+ CEE6RKoI1EMYVYQgHSJVBOohjCpCkA6RKgL1EEYVIUiHSBWBegijihCkQ6SKQD2EUUUI
+ 0iFSRaAewqgiBOkQqSJQD2FUEYJ0iFQRqIcwqghBOkSqCNRDGFWEIB0iVQTqIYwqQpAO
+ kSoC9RBGFSFIh0gVgXoIo4oQpEOkikA9hFFFCNIhUkWgHsKoIgTpEKkiUA9hVBGCdIhU
+ EaiHMKoIQTpEqgjUQxhVhCAdIlUE6iGMKkKQDpEqAvUQRhUhSIdIFYF6CKOKEKRDpIpA
+ PYRRRQjSIVJFoB7CqCIE6RCpIlAPYVQRgnSIVBGohzCqCEE6RKoI1EMYVYQgHSJVBOoh
+ jCpCkA6RKgL1EEYVIUiHSBWBegijihCkQ6SKQD2EUUUI0iFSRaAewqgiBOkQqSJQD2FU
+ EYJ0iFQRqIcwqghBOkSqCNRDGFWEIB0iVQTqIYwqQpAOkSoC9RBGFSFIh0gVgXoIo4oQ
+ pEOkikA9hFFFCNIhEhZpw/+qcSwG/hSxfH+PE0kt7l3Umu3eWJh6UWRgVJFcsVx7VhGk
+ bjxbr9t6uj7ZnI0Hh+5IOLmwe171iuiSjMf7qFft9Xrd16ero/zMcBE7lJgv/Litt7re
+ dyjKKH1j+HdPd+flofJ9fToWGLwjdnBiNn90+fjS6ScZA1gv+bUB74Z028935f3ldNQ/
+ WMQKuJnV/fPb+mu7o2PUQLvVfLg6LixMhp2/n7R8PsuJTM5vHf6sPjWaLzomDTTrD9dn
+ +2vT8aA9WMRnB2OZpe3D8nX1/kHHoIH72u3lj2/5+WRk6KHVvyShienlQumk/LNSudQx
+ ZKBS+XVxdlTML6TdD1fE57P94Ymp3Hqh+K10cPBdx4yBg4PS3s7mSjYVCzqD7+v955fl
+ JYmnpucXl1dX13RMGVhdWcrNZRLu5yBvSYLReCKVzkzpmDOQSScn3HDg0w15e5f3rkkw
+ HIm6bkzHkAHXdaORUMCxPz6y3j92Wbbj+P0BHWMG/H6/l2NUj/+7WDomDbzfBn2VARmQ
+ ARmQARmQARkwYOA/LaDxbQplbmRzdHJlYW0KZW5kb2JqCjU2IDAgb2JqCjE0NzYKZW5k
+ b2JqCjU3IDAgb2JqCjw8IC9MZW5ndGggNTggMCBSIC9UeXBlIC9YT2JqZWN0IC9TdWJ0
+ eXBlIC9JbWFnZSAvV2lkdGggMzM2IC9IZWlnaHQgNzAgL0NvbG9yU3BhY2UKL0Rldmlj
+ ZUdyYXkgL0ludGVycG9sYXRlIHRydWUgL0JpdHNQZXJDb21wb25lbnQgOCAvRmlsdGVy
+ IC9GbGF0ZURlY29kZSA+PgpzdHJlYW0KeAHt3NlS4lAQBmCykbAEBGTVuCFLKcRSRxEV
+ HRRUlIAIAX3/F5lEaigCcuq0V1Pj/19YVprm4quOqHU6Ph8CAQhAAAIQgMD/LSCIooQQ
+ BERREFaNhCBKil/VAgi/gKYqsvS1qCApWkiPxuIIt0BsLRIOqrL4hago+UPRRDq3aWwh
+ vALGRjYV1wPK8ogKkhpO5HYKBxXTPEL4BMzqYTlvpNeCyuKECpI/vG4UzbP6deMG4RVo
+ XNVODvO5mAPq/VQSlVDCKJ9cNduPTx2EV+DpoXVTM/ezUW3hjpe0aLZ40mi/9PqvA4RX
+ 4LVvde7q1d1k2DugghxK7JhX7e5gZNtjhFfAtof95+Z5OecM6PwNL/r1dOGs+TywJ5P3
+ 9/cPhEfAkZqMR/3Ha3M7EZTnf2cS1WjuoN7ujVxNePJgfr7GBX17/n2ad274eU9Ji21W
+ rh/7NqaT2/Iv6LB7f15I617PQMwwG0+vNoaT5vnxPhlarVopo/s98xmIb5k3nYHjSXy/
+ H//yyajXvihlI0ueR/D8znC4nvXyCs/xd97xZ/fMPOf/QpKc+92dT3iShwOeZDJmAzyZ
+ POQiPMlkzAZ4MnnIRXiSyZgN8GTykIvwJJMxG+DJ5CEX4UkmYzbAk8lDLsKTTMZsgCeT
+ h1yEJ5mM2QBPJg+5CE8yGbMBnkwechGeZDJmAzyZPOQiPMlkzAZ4MnnIRXiSyZgN8GTy
+ kIvwJJMxG+DJ5CEX4UkmYzbAk8lDLsKTTMZsmHkunlecnq9j9qK4LLDSc3r+c7kBVxgC
+ zoHvkdW6KGUWz3/GjOr0fDKjGaUlAcfTPZ9cTHvPJ4va2sbh1UPf3UdY6sGFVQLu7sb4
+ rXt3Vkh59xFENZIt11rWcAzQVXhfXHc4J/agc3u8tx7y7MsISjiVP7nt9EfjCUIQGNtv
+ VvuyYsQCnn0uQQ7GjcPa3XP/bThCuAWGw4H10DgtZCLq/HFvn89dkMub9ebjS9fqIZwC
+ ltXttG9+HRiJoGf9yOcT5MBabr96ft28b7URToFW6+728vRgO6mrC/vFPlEJxrK7ZfP0
+ vFZHOAUuamfHlYKRjGieTyN3M9Z5ekgwmtzYzhdKZYRToFQs7BmZuK7J3p+en6CiooWj
+ iWQ6k0U4BTLp1Ho8suKBLIIo+7VgWI8g3AJ6OBRQv3gay3QX3nkAk6z4EYKAojgPC5r/
+ z9JUcvZVcCIivAIu18wO30AAAhCAAAT+GYE/v2FL9wplbmRzdHJlYW0KZW5kb2JqCjU4
+ IDAgb2JqCjkyNQplbmRvYmoKNTkgMCBvYmoKPDwgL0xlbmd0aCA2MCAwIFIgL1R5cGUg
+ L1hPYmplY3QgL1N1YnR5cGUgL0ltYWdlIC9XaWR0aCA1MDIgL0hlaWdodCA0OTAgL0Nv
+ bG9yU3BhY2UKL0RldmljZUdyYXkgL0ludGVycG9sYXRlIHRydWUgL0JpdHNQZXJDb21w
+ b25lbnQgOCAvRmlsdGVyIC9GbGF0ZURlY29kZSA+PgpzdHJlYW0KeAHt2FtTk2cYRmHy
+ ZUtIQEBkY6NtKcK4iVOtIlWwKKhYIiKEpP//jzRpp50G9faY1fWe9OBpZ3qvyw9tp6Z8
+ FrCABSxgAQtYwAIWsIAFLGABC1jAAhawgAUsYAELWMACFrCABSxgAQtYwAIWsIAFLGAB
+ C1jAAhawgAUsYAELWMACFrCABSxgAQtYwAIWsIAFLGABC1jAAhawgAUsYAELWMACFrCA
+ BSxgAQtYwAIWsIAFLGABC1jAAhawgAUsYAELWMACFrCABSxgAQtYwAIWsIAFLGABC1jA
+ AhawgAUsYIGrXaBUFGUfrUBRlEpf/XVZKsrVWr0x7YMVaNSrlfJX3EvlamOmPTe/4GMV
+ mL8222rWK8WX3ItybWZucXntu84tH6pA5+bqjYX2dPULn3upXG8trn2/cfd+t/vQByrQ
+ fXBva72zfK1Z/exrL5VrreudO90nOy9293yoArvPtx/dW1+bH7Ff+jNdUZ1Z7Gw9er5/
+ +PbdkQ9V4N2bg73t7k+rc43LP+PLjbnVO492D3//cPLx1Icq8PGkd/Rq58EPS61LH3up
+ MrP4fff54fHpeb9/4UMV6PfPTt7vP91aG33sEz/ii1p7eePJ/vvT/mAwHA7/8GEKjDgH
+ F+cnb190by82KxP/9VbU59bu7hx+OB+bq44h/2vImP3T+98er49+xE+olxvz391/8fak
+ 75fOEv+H/ez49dON5fYl9en5Tnf33ce+HzpQ/Y/h4Kx3sL250q5NfuvTC7e6e0enI3Xi
+ 6v/9psH5h8Nnm6uzn6s/VB37q2OsvrP1NfUL7O7/97B/1Sf+71x59BN+/K2rzvzVoTrT
+ Na9SPfdhXlVnuuZVquc+zKvqTNe8SvXch3lVnemaV6me+zCvqjNd8yrVcx/mVXWma16l
+ eu7DvKrOdM2rVM99mFfVma55leq5D/OqOtM1r1I992FeVWe65lWq5z7Mq+pM17xK9dyH
+ eVWd6ZpXqZ77MK+qM13zKtVzH+ZVdaZrXqV67sO8qs50zatUz32YV9WZrnmV6rkP86o6
+ 0zWvUj33YV5VZ7rmVarnPsyr6kzXvEr13Id5VZ3pmlepnvswr6ozXfMq1XMf5lV1pmte
+ pXruw7yqznTNq1TPfZhX1ZmueZXquQ/zqjrTNa9SPfdhXlVnuuZVquc+zKvqTNe8SvXc
+ h3lVnemaV6me+zCvqjNd8yrVcx/mVXWma16leu7DvKrOdM2rVM99mFfVma55leq5D/Oq
+ OtM1r1I992FeVWe65lWq5z7Mq+pM17xK9dyHeVWd6ZpXqZ77MK+qM13zKtVzH+ZVdaZr
+ XqV67sO8qs50zatUz32YV9WZrnmV6rkP86o60zWvUj33YV5VZ7rmVarnPsyr6kzXvEr1
+ 3Id5VZ3pmlepnvswr6ozXfMq1XMf5lV1pmtepXruw7yqznTNq1TPfZhX1ZmueZXquQ/z
+ qjrTNa9SPfdhXlVnuuZVquc+zKvqTNe8SvXch3lVnemaV6me+zCvqjNd8yrVcx/mVXWm
+ a16leu7DvKrOdM2rVM99mFfVma55leq5D/OqOtM1r1I992FeVWe65lWq5z7Mq+pM17xK
+ 9dyHeVWd6ZpXqZ77MK+qM13zKtVzH+ZVdaZrXqV67sO8qs50zatUz32YV9WZrnmV6rkP
+ 86o60zWvUj33YV5VZ7rmVarnPsyr6kzXvEr13Id5VZ3pmlepnvswr6ozXfMq1XMf5lV1
+ pmtepXruw7yqznTNq1TPfZhX1ZmueZXquQ/zqjrTNa9SPfdhXlVnuuZVquc+zKvqTNe8
+ SvXch3lVnemaV6me+zCvqjNd8yrVcx/mVXWma16leu7DvKrOdM2rVM99mFfVma55leq5
+ D/OqOtM1r1I992FeVWe65lWq5z7Mq+pM17xK9dyHeVWd6ZpXqZ77MK+qM13zKtVzH+ZV
+ daZrXqV67sO8qs50zatUz32YV9WZrnmV6rkP86o60zWvUj33YV5VZ7rmVarnPsyr6kzX
+ vEr13Id5VZ3pmlepnvswr6ozXfMq1XMf5lV1pmtepXruw7yqznTNq1TPfZhX1ZmueZXq
+ uQ/zqjrTNa9SPfdhXlVnuuZVquc+zKvqTNe8SvXch3lVnemaV6me+zCvqjNd8yrVcx/m
+ VXWma16leu7DvKrOdM2rVM99mFfVma55leq5D/OqOtM1r1I992FeVWe65lWq5z7Mq+pM
+ 17xK9dyHeVWd6ZpXqZ77MK+qM13zKtVzH+ZVdaZrXqV67sO8qs50zatUz32YV9WZrnmV
+ 6rkP86o60zWvUj33YV5VZ7rmVarnPsyr6kzXvEr13Id5VZ3pmlepnvswr6ozXfMq1XMf
+ 5lV1pmtepXruw7yqznTNq1TPfZhX1ZmueZXquQ/zqjrTNa9SPfdhXlVnuuZVquc+zKvq
+ TNe8SvXch3lVnemaV6me+zCvqjNd8yrVcx/mVXWma16leu7DvKrOdM2rVM99mFfVma55
+ leq5D/OqOtM1r1I992FeVWe65lWq5z7Mq+pM17xK9dyHeVWd6ZpXqZ77MK+qM13zKtVz
+ H+ZVdaZrXqV67sO8qs50zatUz32YV9WZrnmV6rkP86o60zWvUj33YV5VZ7rmVarnPsyr
+ 6kzXvEr13Id5VZ3pmlepnvswr6ozXfMq1XMf5lV1pmtepXruw7yqznTNq1TPfZhX1Zmu
+ eZXquQ/zqjrTNa9SPfdhXlVnuuZVquc+zKvqTNe8SvXch3lVnemaV6me+zCvqjNd8yrV
+ cx/mVXWma16leu7DvKrOdM2rVM99mFfVma55leq5D/OqOtM1r1I992FeVWe65lWq5z7M
+ q+pM17xK9dyHeVWd6ZpXqZ77MK+qM13zKtVzH+ZVdaZrXqV67sO8qs50zatUz32YV9WZ
+ rnmV6rkP86o60zWvUj33YV5VZ7rmVarnPsyr6kzXvEr13Id5VZ3pmlepnvswr6ozXfMq
+ 1XMf5lV1pmtepXruw7yqznTNq1TPfZhX1ZmueZXquQ/zqjrTNa/6V7009Z9Xnl649XDv
+ 6LQ/zP+016tZ4OvqXdWvJuk3/62Hw8F57+DZ5sps7dK3Pt95sPvuY3/ox/7NiFfubxip
+ n/UOtu8styfVi8a1m/eevzk5H8h+5VC/8S88HL2LT8evnmzcaFUnvvWiPru6tX3QO7uQ
+ /RsRr9x5hD7onx69/PnH6zOVCfVStXVj/dHLo5Pzi4GPVuCi/6l3+Ov9zvx0+T9/gp+a
+ KlWaC51726/en3w6O/exCpydnfbe7D7eWJmtFxPqU0Wtvbze3dl/+/tx74OPVKDXOz46
+ 3PvlbmexOfnb+vhjn7629tODpy/2Xx8c+kgFDg5evfz18d3bS+16eeK39dF3X1Sb86s/
+ bHUfP93e8ZEKPNt+8vP9jc7SbGPyz3LjH/alcrU5t3Tz9vrG5paPVGDzzsaPnZWFdqNy
+ 6Xf1v9iLaqM1t7i0vLLqIxVYWb5xfWG2Wa8Ul3++/81eqTWarfasj1Wg3ZqZrlc/+z19
+ bD5+paJcqdZ8tALV6ug7/9KH/jf7CH70Ch+qwNj0H1//agELWMACFrCABSxgAQtYwAIW
+ sIAFLGABC1jAAhawgAUsYAELWMACFrCABSxgAQtYwAIWsIAFLGABC1jAAhawgAUsYAEL
+ WMACFrCABSxgAQtYwAIWsIAFLGABC1jAAhawgAUsYAELWMACFrCABSxgAQtYwAIWsIAF
+ LGABC1jAAhawgAUsYAELWMACFrCABSxgAQtYwAIWsIAFLGABC1gAUuBPhGXoYQplbmRz
+ dHJlYW0KZW5kb2JqCjYwIDAgb2JqCjI4MTIKZW5kb2JqCjUxIDAgb2JqCjw8IC9MZW5n
+ dGggNTIgMCBSIC9UeXBlIC9YT2JqZWN0IC9TdWJ0eXBlIC9JbWFnZSAvV2lkdGggNTAy
+ IC9IZWlnaHQgODgyIC9Db2xvclNwYWNlCi9EZXZpY2VHcmF5IC9JbnRlcnBvbGF0ZSB0
+ cnVlIC9CaXRzUGVyQ29tcG9uZW50IDggL0ZpbHRlciAvRmxhdGVEZWNvZGUgPj4Kc3Ry
+ ZWFtCngB7ddZd1QFGkbhVCojGYCAgTBEBg2DMggyCwgyyBQIJIT+/3+kK3brMiDbu+7F
+ dp8bLz5dK+9+cirl2FhPBSpQgQpUoAIVqEAFKlCBClSgAhWoQAUqUIEKVKACFahABSpQ
+ gQpUoAIVqEAFKlCBClSgAhWoQAUqUIEKVKACFahABSpQgQpUoAIVqEAFKlCBClSgAhWo
+ QAUqUIEKVKACFahABSpQgQpUoAIVqEAFKlCBClSgAhWoQAUqUIEKVKACFahABSpQgQpU
+ oAIVqEAFKlCBClSgAhWoQAUqUIEKVKACFahABSpQgQpUoAIVqEAFKlCBClSgAhWoQAUq
+ UIEKVKACFahABSpQgQpUoAIVqEAFKlCBClSgAhWoQAUqUIEK/M8LDAaD8R5ZgREq/CIN
+ xocTk1NT0z2qAlNTkxPD8c/AD8Ynpmbn5hcW9/aYCiwuLszvmZ4c/iX7YDg5O7/v4PLh
+ lZUjPaICKyuHvlraOzc98Rev+2A4tWff8rGT35w5d+58j6fAuXNn106vrhxYmJkY/+Sv
+ +/jk3NKRU+cv/3jj1u0eVYFb169eWFtdXpyZ+PhDfjAxu//Itxdv3H3w6PGTHlOBx49/
+ +fnO1e9OLC9Mf/y3fTi9cOj0pVsPn754tb7+usdTYH19/eXzx/eunV89MDe5+2UfTOxZ
+ Wv3+5sPnr99ujp6tHk2BEee7jVdP711dW1mc3v2XfTA5v/zN1fvP3my+3x49H3o0BXY8
+ 37979fj2hdWl2Yld3+fGpxdXzt589Ordjvi/ekwFRr+/21sbz+5fOXVwbvf3ufGZfUe/
+ u/P09dZ25ibxnS07n1rv3718eO3b5fndf9iHs/uPX7j765ut3nQb+m/u2+9ePbqxdmhh
+ atfXueHs0urFe882tnrVneqb649unjm8+Kn6pdSF4v+ZtL25/vjW2ZXPqL/X7v5nD0v9
+ n+j/h/qu/2Hf+bu+8wnfu+78nUjd6cqrUuc+zmvqTldelTr3cV5Td7ryqtS5j/OautOV
+ V6XOfZzX1J2uvCp17uO8pu505VWpcx/nNXWnK69Knfs4r6k7XXlV6tzHeU3d6cqrUuc+
+ zmvqTldelTr3cV5Td7ryqtS5j/OautOVV6XOfZzX1J2uvCp17uO8pu505VWpcx/nNXWn
+ K69Knfs4r6k7XXlV6tzHeU3d6cqrUuc+zmvqTldelTr3cV5Td7ryqtS5j/OautOVV6XO
+ fZzX1J2uvCp17uO8pu505VWpcx/nNXWnK69Knfs4r6k7XXlV6tzHeU3d6cqrUuc+zmvq
+ TldelTr3cV5Td7ryqtS5j/OautOVV6XOfZzX1J2uvCp17uO8pu505VWpcx/nNXWnK69K
+ nfs4r6k7XXlV6tzHeU3d6cqrUuc+zmvqTldelTr3cV5Td7ryqtS5j/OautOVV6XOfZzX
+ 1J2uvCp17uO8pu505VWpcx/nNXWnK69Knfs4r6k7XXlV6tzHeU3d6cqrUuc+zmvqTlde
+ lTr3cV5Td7ryqtS5j/OautOVV6XOfZzX1J2uvCp17uO8pu505VWpcx/nNXWnK69Knfs4
+ r6k7XXlV6tzHeU3d6cqrUuc+zmvqTldelTr3cV5Td7ryqtS5j/OautOVV6XOfZzX1J2u
+ vCp17uO8pu505VWpcx/nNXWnK69Knfs4r6k7XXlV6tzHeU3d6cqrUuc+zmvqTldelTr3
+ cV5Td7ryqtS5j/OautOVV6XOfZzX1J2uvCp17uO8pu505VWpcx/nNXWnK69Knfs4r6k7
+ XXlV6tzHeU3d6cqrUuc+zmvqTldelTr3cV5Td7ryqtS5j/OautOVV6XOfZzX1J2uvCp1
+ 7uO8pu505VWpcx/nNXWnK69Knfs4r6k7XXlV6tzHeU3d6cqrUuc+zmvqTldelTr3cV5T
+ d7ryqtS5j/OautOVV6XOfZzX1J2uvCp17uO8pu505VWpcx/nNXWnK69Knfs4r6k7XXlV
+ 6tzHeU3d6cqrUuc+zmvqTldelTr3cV5Td7ryqtS5j/OautOVV6XOfZzX1J2uvCp17uO8
+ pu505VWpcx/nNXWnK69Knfs4r6k7XXlV6tzHeU3d6cqrUuc+zmvqTldelTr3cV5Td7ry
+ qtS5j/OautOVV6XOfZzX1J2uvCp17uO8pu505VWpcx/nNXWnK69Knfs4r6k7XXlV6tzH
+ eU3d6cqrUuc+zmvqTldelTr3cV5Td7ryqtS5j/OautOVV6XOfZzX1J2uvCp17uO8pu50
+ 5VWpcx/nNXWnK69Knfs4r6k7XXlV6tzHeU3d6cqrUuc+zmvqTldelTr3cV5Td7ryqtS5
+ j/OautOVV6XOfZzX1J2uvCp17uO8pu505VWpcx/nNXWnK69Knfs4r6k7XXlV6tzHeU3d
+ 6cqrUuc+zmvqTldelTr3cV5Td7ryqtS5j/OautOVV6XOfZzX1J2uvCp17uO8pu505VWp
+ cx/nNXWnK69Knfs4r6k7XXlV6tzHeU3d6cqrUuc+zmvqTldelTr3cV5Td7ryqtS5j/Oa
+ utOVV6XOfZzX1J2uvCp17uO8pu505VWpcx/nNXWnK69Knfs4r6k7XXlV6tzHeU3d6cqr
+ Uuc+zmvqTldelTr3cV5Td7ryqtS5j/OautOVV6XOfZzX1J2uvCp17uO8pu505VWpcx/n
+ NXWnK69Knfs4r6k7XXlV6tzHeU3d6cqrUuc+zmvqTldelTr3cV5Td7ryqtS5j/OautOV
+ V6XOfZzX1J2uvCp17uO8pu505VWpcx/nNXWnK69Knfs4r6k7XXlV6tzHeU3d6cqrUuc+
+ zmvqTldelTr3cV5Td7ryqtS5j/OautOVV6XOfZzX1J2uvCp17uO8pu505VWpcx/nNXWn
+ K69Knfs4r6k7XXlV6tzHeU3d6cqrUuc+zmvqTldelTr3cV5Td7ryqtS5j/OautOVV6XO
+ fZzX1J2uvCp17uO8pu505VWpcx/nNXWnK69Knfs4r6k7XXlV6tzHeU3d6cqrUuc+zmvq
+ TldelTr3cV5Td7ryqtS5j/OautOVV6XOfZzX1J2uvCp17uO8pu505VWpcx/nNXWnK69K
+ nfs4r6k7XXlV6tzHeU3d6cqrUuc+zmvqTldelTr3cV5Td7ryqtS5j/OautOVV6XOfZzX
+ 1J2uvCp17uO8pu505VWpcx/nNXWnK69Knfs4r6k7XXlV6tzHeU3d6cqrUuc+zmvqTlde
+ lTr3cV5Td7ryqtS5j/OautOVV6XOfZzX1J2uvCp17uO8pu505VWpcx/nNXWnK69Knfs4
+ r6k7XXlV6tzHeU3d6cqrUuc+zmvqTldelTr3cV5Td7ryqtS5j/OautOVV6XOfZzX1J2u
+ vCp17uO8pu505VWpcx/nNXWnK69Knfs4r6k7XXlV6tzHeU3d6cqrUuc+zmvqTldelTr3
+ cV5Td7ryqtS5j/OautOVV6XOfZzX1J2uvCp17uO8pu505VWpcx/nNXWnK69Knfs4r6k7
+ XXlV6tzHeU3d6cqrUuc+zmvqTldelTr3cV5Td7ryqtS5j/OautOVV6XOfZzX1J2uvCp1
+ 7uO8pu505VWpcx/nNXWnK69Knfs4r6k7XXlV6tzHeU3d6cqrUuc+zmvqTldelTr3cV5T
+ d7ryqtS5j/OautOVV6XOfZzX1J2uvCp17uO8pu505VWpcx/nNXWnK69Knfs4r6k7XXlV
+ 6tzHeU3d6cqrUuc+zmvqTldelTr3cV5Td7ryqtS5j/OautOVV6XOfZzX1J2uvCp17uO8
+ pu505VWpcx/nNXWnK69Knfs4r6k7XXlV6tzHeU3d6cqrUuc+zmvqTldelTr3cV5Td7ry
+ qtS5j/OautOVV6XOfZzX1J2uvCp17uO8pu505VWpcx/nNXWnK69Knfs4r6k7XXlV6tzH
+ eU3d6cqrUuc+zmvqTldelTr3cV5Td7ryqtS5j/OautOVV6XOfZzX1J2uvCp17uO8pu50
+ 5VWpcx/nNXWnK69Knfs4r6k7XXlV6tzHeU3d6cqrUuc+zmvqTldelTr3cV5Td7ryqtS5
+ j/OautOVV6XOfZzX1J2uvCp17uO8pu505VWpcx/nNXWnK69Knfs4r6k7XXlV6tzHeU3d
+ 6cqrUuc+zmvqTldelTr3cV5Td7ryqtS5j/OautOVV6XOfZzX1J2uvCp17uO8pu505VWp
+ cx/nNXWnK69Knfs4r6k7XXlV6tzHeU3d6cqrUuc+zmvqTldelTr3cV5Td7ryqtS5j/Oa
+ utOVV6XOfZzX1J2uvCp17uO8pu505VWpcx/nNXWnK69Knfs4r6k7XXlV6tzHeU3d6cqr
+ Uuc+zmvqTldelTr3cV5Td7ryqtS5j/OautOVV6XOfZzX1J2uvCp17uO8pu505VWpcx/n
+ NXWnK69Knfs4r6k7XXlV6tzHeU3d6cqrUuc+zmvqTldelTr3cV5Td7ryqtS5j/OautOV
+ V6XOfZzX1J2uvCp17uO8pu505VWpcx/nNXWnK69Knfs4r6k7XXlV6tzHeU3d6cqrUuc+
+ zmvqTldelTr3cV5Td7ryqtS5j/OautOVV6XOfZzX1J2uvCp17uO8pu505VWpcx/nNXWn
+ K69Knfs4r6k7XXlV6tzHeU3d6cqrUuc+zmvqTldelTr3cV5Td7ryqtS5j/OautOVV6XO
+ fZzX1J2uvCp17uO8pu505VWpcx/nNXWnK69Knfs4r6k7XXlV6tzHeU3d6cqrUuc+zmvq
+ TldelTr3cV5Td7ryqtS5j/OautOVV6XOfZzX1J2uvCp17uO8pu505VWpcx/nNXWnK69K
+ nfs4r6k7XXlV6tzHeU3d6cqrUuc+zmvqTldelTr3cV5Td7ryqtS5j/OautOVV6XOfZzX
+ 1J2uvCp17uO8pu505VWpcx/nNXWnK69Knfs4r6k7XXlV6tzHeU3d6cqrUuc+zmvqTlde
+ lTr3cV5Td7ryqtS5j/OautOVV6XOfZzX1J2uvCp17uO8pu505VWpcx/nNXWnK69Knfs4
+ r6k7XXlV6tzHeU3d6cqrUuc+zmvqTldelTr3cV5Td7ryqtS5j/OautOVV6XOfZzX1J2u
+ vCp17uO8pu505VWpcx/nNXWnK69Knfs4r6k7XXlV6tzHeU3d6cqrUuc+zmvqTldelTr3
+ cV5Td7ryqtS5j/OautOVV6XOfZzX1J2uvCp17uO8pu505VWpcx/nNXWnK69Knfs4r6k7
+ XXlV6tzHeU3d6cqrUuc+zmvqTldelTr3cV5Td7ryqtS5j/OautOVV7H6Fv/HXb/QAn+o
+ D8b+9Axnl1Yv3Xu2sfXhC53Vj40FPqt+/OLdZ2+2PnzIHft9kccP25uvHt08c3hhave7
+ PrP/2IWfnqb+RaL+zQ89epO337365fraoYXJXerj03uPnr/9ZH1ze/Sv9Lb/TcYv7DwS
+ ff/2xYMfv1me/0h9avHw2vWHL9++32H/wlb142KB0Zu+vfXm17uXTxzYM7HrXR9Mzh08
+ efmnJ+vvtt732ApsbW68+OXG+WP7ZoZ/+gY/NjYYzu47evba/acvX2+87ZEV2Fh//ujO
+ 5dPLC1Pju9THxqfmD3793bW7j54+f9HjKvD82ZMHt39YO7p/dvcH/M7LPr24fOLclZs/
+ 3X8weh72SAqMMH++d+f6xbVjB+Y+ftXHxsYnZha/On763MUfrlztURW4cun7MyePLM1P
+ DXd9l9v5sB+M2OeXlo+unjh16nSPqMCpk18fXzm4d+4v0H9jn9qzsHfpwMGvelQFDh7Y
+ vzg3M/npm/7bV7vR6z41M7tnrkdWYM/s9ORw/JOP99+/zw/Gh8OJiYnJHlGBEeiI/LPm
+ /7Uf9MgK/P5S988KVKACFahABSpQgQpUoAIVqEAFKlCBClSgAhWoQAUqUIEKVKACFahA
+ BSpQgQpUoAIVqEAFKlCBClSgAhWoQAUqUIEKVKACFahABSpQgQpUoAIVqEAFKlCBClSg
+ AhWoQAUqUIEKVKACFahABSpQgQpUoAIVqEAFKlCBClSgAhWoQAUqUIEKVKACFahABSpQ
+ gQpUoAIVqEAFKlCBClSgAhWoQAUqUIEKVKACFahABSpQgQpUoAIVqEAFKlCBClSgAhWo
+ QAUqUIEKVKACFahABSpQgQpUoAIVqEAFKlCBClTg/1ng3++OKP0KZW5kc3RyZWFtCmVu
+ ZG9iago1MiAwIG9iago0NTczCmVuZG9iagozNyAwIG9iago8PCAvVHlwZSAvRXh0R1N0
+ YXRlIC9jYSAwLjcgPj4KZW5kb2JqCjM4IDAgb2JqCjw8IC9UeXBlIC9FeHRHU3RhdGUg
+ L0NBIDAuNyA+PgplbmRvYmoKNjcgMCBvYmoKPDwgL0xlbmd0aCA2OCAwIFIgL04gMyAv
+ QWx0ZXJuYXRlIC9EZXZpY2VSR0IgL0ZpbHRlciAvRmxhdGVEZWNvZGUgPj4Kc3RyZWFt
+ CngB1VlnWBTNsu6ZTcCypCXnHEVylpwkSA6CSFrSknMOSlKCIIiAgKCACCKCGAgCImAC
+ RIKAEQmiIKhgAgThDur3fec+55x/98+d55med6uqq2unerqn3gGAbdktONgfpgMgIDA8
+ 1MpQh/eggyMv7gWgBDSAEYgBSjdSWLC2hYUp+K/H9wkA7SrHJHd9/Vez/6yg9/AMIwEA
+ WSBqd48wUgCCrwMA65CCQ8MBQK0j8uGo8GAEox8gmDEUCRDBL3ex92+8sovdf2EM+peN
+ jZUuABhWACio3dxCvQEgCCJy3kiSN+KHoAcAliHQgxwIAPEggjVIPm4eALAVIzZ7AgKC
+ dnEfgkXd/8WP979gNzf3v326uXn/jX//F6QnMrAeOSzY3y3m14//yybAPwK5X78OBqSl
+ DvQ3280NM3IueLjpmSBXTuTcDvb/lTPEBmL3DLS1RmS7eE+gu5n5H6zhFWpghWCkL2QR
+ HK6zi5F7BnkFh1vY/JEnxvromiGYGpEXeIbp/+XnnK+b8W7OaBB5c2iElS2CBRHcHRZp
+ rY9gZEZBb2J9bOz/2Hz18NT7I4dhL7KB0W8bmIEcbrQ7FiOSc36/IJPdGJCxYEVgAvyB
+ J4gAoUgbCCSBKdAFen9aSeAF3BBNJKILA37gLYIDkB5BSJ8gBPP+sdP9N4nBr37eSL//
+ 7ZEXkBDbiL/H/D0aLzLmXz7JwAPBf8ndkDF2dbvRhbmQk/8Z8y+LXX+/opGul16U3vor
+ JrQwWhatgNZBq6M10CqAF82MZgeSaHm0MlobrYlWQ3QqwAC8QTx7/xXjrv+AZq/I4qAY
+ VTsfRLv7393/0gK7X9bkv3//WwSAPLTcsvxXBACEe0YjzwEAukHBMaFkb59wXm3kyfXc
+ w2sUSNq7h1dWWkZmV/3/5thds34H+8Xq11oEMT/+RxbQCIAyGZmPzv/I3E8C0C6JPPv1
+ /8iEC5G1wReAAUFSRGjkb3/o3QsGUAFaZIayAW4gAESR+ywLFIEa0AL6wBiYAxvgAJyR
+ +eODzMFQEAXiwVGQDrLASXAalIAKUAVqQQNoBi2gA9wB98AAGAbj4AWYBvNgCayA72AT
+ giAcRICIEBvEAwlBEpAspAxpQPqQKWQFOUCukDcUCEVA8VAKlAXlQyXQeagOugq1QXeg
+ h9AI9AyagRahz9APGAVTw4wwFywMS8HKsDZsAtvAh2FvOASOhVPhHLgYroQvwzfhO/AA
+ PA5Pw0vwNxRA4VHMKD6UJEoZpYsyRzmivFChqERUJqoQVYm6gmpH3UeNoaZRy6gNNBZN
+ RPOiJZF5uh9tiyahQ9CJ6Gx0CboWfRPdhx5Dz6BX0NsYAoYTI4FRxRhhDmK8MVGYdEwh
+ pgZzA3MXM46Zx3zHYrHMWBGsEnY/1gHri43DZmPPYhux3dgR7Bz2Gw6HY8NJ4NRx5jg3
+ XDguHXcGdxl3GzeKm8etU+ApeChkKQwoHCkCKZIpCikuUXRRjFK8o9ikpKMUolSlNKf0
+ oIyhzKWspmynfEw5T7lJRU8lQqVOZUPlS3WUqpjqCtVdqpdUX/B4PD9eBW+JJ+OP4Ivx
+ TfgH+Bn8BjUDtTi1LrUTdQR1DvVF6m7qZ9RfCASCMEGL4EgIJ+QQ6gi9hCnCOg2RZi+N
+ EY0HTRJNKc1NmlGaj7SUtEK02rTOtLG0hbTXaB/TLtNR0gnT6dK50SXSldK10U3SfaMn
+ 0svQm9MH0GfTX6J/SL/AgGMQZtBn8GBIZahi6GWYI6KIAkRdIomYQqwm3iXOM2IZRRiN
+ GH0ZsxgbGIcYV5gYmOSZ7JiimUqZOpmmmVHMwsxGzP7MuczNzBPMP1i4WLRZPFkyWK6w
+ jLKssXKwarF6smayNrKOs/5g42XTZ/Njy2NrYXvFjmYXZ7dkj2IvZ7/LvszByKHGQeLI
+ 5GjmeM4Jc4pzWnHGcVZxDnJ+4+LmMuQK5jrD1cu1zM3MrcXty13A3cW9yEPk0eAh8xTw
+ 3OZ5z8vEq83rz1vM28e7wsfJt58vgu883xDfJr8Ivy1/Mn8j/ysBKgFlAS+BAoEegRVB
+ HsEDgvGC9YLPhSiFlIV8hIqE7gutCYsI2wsfE24RXhBhFTESiRWpF3kpShDVFA0RrRR9
+ IoYVUxbzEzsrNiwOiyuI+4iXij+WgCUUJcgSZyVG9mD2qOwJ3FO5Z1KSWlJbMlKyXnJm
+ L/Ne073Je1v2fpQSlHKUypO6L7UtrSDtL10t/UKGQcZYJlmmXeazrLgsSbZU9okcQc5A
+ LkmuVW5VXkLeU75c/qkCUeGAwjGFHoWfikqKoYpXFBeVBJVclcqUJpUZlS2Us5UfqGBU
+ dFSSVDpUNlQVVcNVm1U/qUmq+aldUlvYJ7LPc1/1vjl1fnU39fPq0xq8Gq4a5zSmNfk0
+ 3TQrNWe1BLQ8tGq03mmLaftqX9b+qCOtE6pzQ2dNV1U3QbdbD6VnqJepN6TPoG+rX6I/
+ ZcBv4G1Qb7BiqGAYZ9i9H7PfZH/e/kkjLiOSUZ3RirGScYJxnwm1ibVJicmsqbhpqGn7
+ AfiA8YFTB16aCZkFmrWYA3Mj81PmryxELEIsblliLS0sSy3fWslYxVvdtyZau1hfsv5u
+ o2OTa/PCVtQ2wrbHjtbOya7Obs1ezz7ffvqg1MGEgwMO7A5kh1ZHnKOdY43jt0P6h04f
+ mndScEp3mjgscjj68ENndmd/504XWhc3l2uuGFd710uuW27mbpVu39yN3MvcV0i6pCLS
+ koeWR4HHoqe6Z77nOy91r3yvBW9171Peiz6aPoU+y2Rdcgl51Xe/b4Xvmp+530W/HX97
+ /8YAigDXgLZAhkC/wL4g7qDooJFgieD04OkQ1ZDTISuhJqE1YVDY4bDWcEbk5XAwQjQi
+ LWImUiOyNHI9yi7qWjR9dGD0YIx4TEbMu1iD2Atx6DhSXE88X/zR+JkE7YTziVCie2JP
+ kkBSatL8EcMjtUepjvodfZQsnZyf/DXFPqU9lSv1SOpcmmFafTpNemj65DG1YxXH0cfJ
+ x4cy5DLOZGxnemT2Z0lnFWZtZZOy+0/InCg+sZPjlTOUq5hbfhJ7MvDkRJ5mXm0+fX5s
+ /typA6duFvAWZBZ8Pe1y+mGhfGFFEVVRRNF0sWlx6xnBMyfPbJX4lIyX6pQ2lnGWZZSt
+ nfU4O1quVX6lgqsiq+LHOfK5p+cNz9+sFK4srMJWRVa9rbarvn9B+UJdDXtNVs3Pi4EX
+ p2utavvqlOrqLnFeyq2H6yPqFy87XR5u0GtovSJ55Xwjc2NWE2iKaHp/1fXqRLNJc881
+ 5WtXrgtdL7tBvJF5E7oZc3OlxadlutWhdaTNuK2nXa39xq29ty528HWUdjJ15nZRdaV2
+ 7dyOvf2tO7h7+Y73nbkel54XvQd7n/RZ9g3dNbn74J7Bvd772vdvP1B/0PFQ9WFbv3J/
+ y4DiwM1BhcEbjxQe3RhSHLr5WOlx67DKcPvIvpGuUc3RO2N6Y/eeGD0ZGDcbH5mwnXg6
+ 6TQ5/dTj6cIz/2erzyOfb7448hLzMvMV3avCKc6pytdirxunFac7Z/RmBmetZ1/MkeaW
+ 3oS92ZpPfUt4W/iO513dguxCx6LB4vD7Q+/nl4KXNpfTP9B/KPso+vH6J61PgysHV+ZX
+ Q1d3Pmd/Yfty8av8155vFt+mvgd831zLXGdbr91Q3rj/w/7Hu82oLdxW8U+xn+3bJtsv
+ dwJ2doLdQt1+vQugkBb28gLg80XkPcEBqR2GAaCi+V1T/LJAyhUIsUGwHbQXWoLPopzR
+ Quj3mG5sMS6YwopSn0oRL0W9lyBBo0xrQudKH8FwmtjGOMNMzaLNGsrWwL7EKcbly93E
+ s86nx39SYFZIRviYyCsxBfGTEsuS+nurpLZlnGTb5dkVohXHleVUclSX9xmqn9P4oWWl
+ fUFnQ89Ev8RgYb+8UZxxlyl0QMss1rzJYs6K3lrdxsM2ze6c/bWDtx16HbsPtTk1Hq5x
+ LnM56ZrsFuLuTDL1UPLk9yJ4rXnP+PSTm31L/JL9yQEWgQpBLEFrwWMh9aFJYebhPOGf
+ Iroic6KcoiWif8T0x5bEkeOVE7AJY4kVSf5HdI4KJjOm0KbSpdGn0x0jHKfMQGfsZG5k
+ fc5eOjGb8zx39ORAXk9+26krBVWnzxTmFKUUx52JKUkuLS67cXa4fLZi+dzK+ZXKlapP
+ 1R8vfKhZurhQ+6Zu5tJc/WoD/RXdxsSmlquvm9ev424Qb/K0iLcqtGm2G92y7nDvjO4q
+ vn2ne6EH3UvsY7/Le0/8vtIDnYc6/aL9nwYyB9kGzz/SfLQ81PA4dFhlBBp5NFo+FvJE
+ f5xt/ONE72TRU59nis92nne/iH0p93L5VcNU2Ot909jp0ZmyWa85mbnNN/fmC956vlNd
+ YFh4v9j1PnvJfplvefHD1Y+xn3RW8Cvjqw2fy79c/7r23Wvt+YbWj4LN6Z9y2wU7O7/y
+ LwA1wQ4oBtQDdDrGBMuEfYW7RpFN6U9li9ejliOI0QjRitJJ0SswGBDtGAOZUpmrWPpY
+ l9jpOTQ4yVwl3IM8O3zK/OECVwTfC0uI+IjWii1JSO4Jlbyxd0NaU+ao7H15vIKpYo7S
+ iApR1UItZ1+/BlZTUytSu1bnhR5eX9XA3TBjf73RgPGiKXyAxUzEXM5C1VLVSs5a0IbG
+ 5pvtc7tu++qDmQ6BjtaHlJw4nHYOzzr3udS4prt5uGuROElrHiOe9V5p3s4+SmQ68oLv
+ bb8i/8AA/UD2wA9Bt4NzQhxD+UMXw5rCoyJUI35GdkUlRWvFoGMexJ6Is4gnxo8nFCUe
+ QlbWlSO9RyuSU1ICUx3TDNPlj/Edpz6+ljGbOZh1M/vcieM5obmHT5rmaeYrnNpbIHqa
+ v5CziKWY/gxVCbpkq/Rr2dLZ6fLJipFzw+fHK19XLVWv16Au0tSy1Qlekq7fd9mgwfyK
+ Q6NnU+TV7Obaa33Xp26stkCtdG187XK3DDoOdQZ3pd8u7a6709BT3XuyL/yuzT3Z+/T3
+ Vx88QdamioG0Qb9HlkPKj/mG8cPrI3Ojj8aanxSNJ0yQJk2eyj/jeo55vvziyctbr6qm
+ TryOnw6e8ZsNmAt/kzCf/jbvXenChcWm9+1LvcuPPrz4uL6islr9Recb/vvX9YUfo1uV
+ 2w5/8s8JnYBF4QFUAJoDPYBJxmpg13GdFMcoHajk8DT4BeqHhGs05bQn6FLoYxkiiTGM
+ MUwJzOksuaxn2RrZ+ziecn7kJvAI8urwufKnCFQJ3hVaFKERlRGzFY+TqNjTJ7koRS+t
+ JOMoGydXLn9bYUpxW5lDRUXVSo28L1E9T6NK86pWh/ZdnX7dQb0B/fsGtw2v7a80yjQO
+ NDEx5TX9euCeWZE52ULFEmc5YXXBOsxGy5badtKu2j74oJoD1mHYseSQp9Nep++Hu5zT
+ Xcxcia6TbiXIOsFDmvY45+nqxeP12vucjyuZhzzle9bPwZ/oPxSQEagfBAXdCg4PEQl5
+ Gno8TCnsXXhhhF7E58hzUWZRm9F1MXaxcGxj3KF4THxTwqFETGJTkvMRxiMjRwuTPVOU
+ U2lS59M60wuO+R3XzmDJ+JB5J6sg2+uEUg5VznRu68n8vNB861MKBWwF26ffFPYXNRaf
+ OhNZ4lCqWsaO7Jbj5TcqSs+dOJ9emVqVVn3swrGatIsJtQF1By/p16tdVm8wueLWGN9U
+ fPV686Nr89c3b9K3CLfua7Ns976V2HG681JXx+373f13Hvbc7b3T13m39d61+w0PLj6s
+ 6D8zkD+Y/Sh9KOVx2nDeSO3ow7HVca4Jo8nIp5XPhp5vvBR8ZT2V+3p6hjzH+ubbO8xi
+ 4nLv6ql1wd38/+aWdvcErCIANQjvYXcEAEtEU2sJgFABQnG0AWBBAMBGBcB+aQCmXwJQ
+ mejf+wcE0AgDR4dUnAJACqgjzMYhhEtIBPmgBtwCI2ARqRfZIXnIHPKDjkEXoF5oFoZh
+ AVgfqfSy4Eb4CfwDqef2o0JQJag+1CdkDhqiI9BV6DEMCiOPVGQlmCEsCquCDcbWYmdx
+ nLiDuALcKAU9hSXFKYpxSjZKF8oayo9UylQpVMN4bnwgvpuakdqX+g6BgxBFGKdRpDlD
+ s0PrTTtKp013jV6cvoZBhKGRqEYcZHRh/Mp0glmceYAlmJWFtZcthJ2ffYLjBOd+LizX
+ Pe5MHkteTt4PfH38VQJZgrFCAcIeIi6izmKu4p4SAXtiJDP2lku1S0/KvJf9KPdG/olC
+ r+JNpSvKl1TqVC+pNe1rVe/TGNOc19rQodUV0zPQ9zbIMry6/4UxzkTW1P5AqFmKea5F
+ uWWL1QsbSlsNuyhkv/vsKH8o2umOM8HFybXObZnE5aHpae8V4H3cp5n8wU/JPyPgdZBi
+ 8MmQj8j+1hzJFBUe3R/LEuccX5uwk+RzZCbZLeV1mkP6+HGHjK2shZycvLMF7IXGxcEl
+ xWWt5UPnZiq/X6C5KFZnUh/d0N7E3Vx5Q6KlvG2nw6nr1h3e3sy7Gw98+sceyT/OGpl7
+ cmBi6Jnri42pohnluddvUxc2l/iXtz9WrwiuVnxh+1r5XWPt3Ubxps7W1Hbor/UDQjgH
+ PCACLoSBVUL4HntARliFPHARdIEJ8AmiQjgCHcgFSoTKoS5oGsm9MGwMB8OFcBf8FkWH
+ UkV5ovJQt1Ef0JzoA0iFfhX9BsOGMcOkYTqR6lsa64/k/S1OCOeFq8UtUUhRRFB0UmIp
+ LSjPUr6nUqXKonqNl8dn4d9Qa1Kfpf5JcCXcpZGkKaLF0EbSLtGR6Kbp3enfM8QQaYmX
+ GA0ZF5iymGWYn7Oks8qzvmUrZbfhoOMY5SzmcueW4gE847wNfBn83gLGgjJCHMIUwpsi
+ X0W/im1JEPYISGrsdZXKkG6TeS/HKW+hkKU4qEyvYq96Rm1MHdIQ1jTQ8tI+rtOgO64P
+ G8gaeu0/azRpwmxqd6DQbMyCxtLQKsm63WbNTtE++mCnI+aQhVPF4c8uxq7Vbj9Jlsg6
+ 9d5bzieBPODH5R8ScC+IKzgyZCxMPrwoYivKJborljUuMP5eokBS5pH1ZN+UV2kW6b3H
+ lTIasvizS3JYcivyVPM/FLQWFhUnl4SUuZQbn5Ov5KmmubBz8XPd2/qnDQ8aO662Xbtz
+ 43HLq7alWxtdVN28Pap9B+/FPCjtbx8cHnox/HR08EnHxOWnZ5/nvTw2lTQdMxv1Jvpt
+ 3EL0+8PLzB9qPrGskFerPo9/WfvG8l1uzWI9bOPMj0dbuJ+W29V/8o8FBMCCPP0yQAfh
+ l3xAAihAOKT7YBbsQFzQPugwkvvz0D3kLZMBVoVJ8Am4FZ5HEVHaCHNThZpAUyLsYgT6
+ Mnoew4M5hCnGTCCMiz22BDuFE8D54q7htimMKYopFhDG5ATlHJLzAqoVvDm+iZpIHUM9
+ SzAjdNJI01yg5aEto+Omq0Z4iz4GFyKM5NueCcd0izmcRZplhfU6WwK7EQcrxzJnH9c5
+ 7iQeEq8pnwq/uACfII8Qn7CYiKKokZiLeIxE0Z52yVkpBmljmXTZXnmMgqVigzJRJUl1
+ dR9ZfUHTX+u7Troep367oYsR3rjDlGyGMc+yBFZB1q9szex6kD2p9ZCKU7ezmcuMWzSJ
+ 1qPKS967m2ziO+lPClgNOhrCFNoYfiBiJepMjHEcFN+aSEraPpqTwppamS55rDPDJnM9
+ +0pO4EnxvLFTvgVfCiOKvp2JKtkqSy9nrKg5r1Y5Vh1QQ3Wxtm7/pcXL2VfkG99cPX/N
+ /4ZeC38bun2xY6Srs7uhp7Kv5F7Bg7z+3MHcoazhhFHnJ9Lj3yabnwW8EHv5durCtNes
+ +NzqfMe7tEW996vLxz98/mS0kr3a8vnVl+WvG9/mvj9cy1/ft/52I3Vj40fgj7nNg5u3
+ txi3yFtdPxl/kn92bVNsW2wXb7/eEdkJ2mnZzX+Yl5zs7u4BIGodhH6c2tn5IgwALh+A
+ n3k7O5uVOzs/q5BiA/kG0u3/+3vFrjEW4dzLbu2i/3T8D+gdk/4KZW5kc3RyZWFtCmVu
+ ZG9iago2OCAwIG9iago1OTUzCmVuZG9iago1MCAwIG9iagpbIC9JQ0NCYXNlZCA2NyAw
+ IFIgXQplbmRvYmoKNjkgMCBvYmoKPDwgL0xlbmd0aCA3MCAwIFIgL04gMSAvQWx0ZXJu
+ YXRlIC9EZXZpY2VHcmF5IC9GaWx0ZXIgL0ZsYXRlRGVjb2RlID4+CnN0cmVhbQp4AYVS
+ T0gUURz+zTYShIhBhXiIdwoJlSmsrKDadnVZlW1bldKiGGffuqOzM9Ob2TXFkwRdojx1
+ D6JjdOzQoZuXosCsS9cgqSAIPHXo+83s6iiEb3k73/v9/X7fe0RtnabvOylBVHNDlSul
+ p25OTYuDHylFHdROWKYV+OlicYyx67mSv7vX1mfS2LLex7V2+/Y9tZVlYCHqLba3EPoh
+ kWYAH5mfKGWAs8Adlq/YPgE8WA6sGvAjogMPmrkw09GcdKWyLZFT5qIoKq9iO0mu+/m5
+ xr6LtYmD/lyPZtaOvbPqqtFM1LT3RKG8D65EGc9fVPZsNRSnDeOcSEMaKfKu1d8rTMcR
+ kSsQSgZSNWS5n2pOnXXgdRi7XbqT4/j2EKU+yWCoibXpspkdhX0AdirL7BDwBejxsmIP
+ 54F7Yf9bUcOTwCdhP2SHedatH/YXrlPge4Q9NeDOFK7F8dqKH14tAUP3VCNojHNNxNPX
+ OXOkiO8x1BmY90Y5pgsxd5aqEzeAO2EfWapmCrFd+67qJe57AnfT4zvRmzkLXKAcSXKx
+ FdkU0DwJWBR9i7BJDjw+zh5V4HeomMAcuYnczSj3HtURG2ejUoFWeo1Xxk/jufHF+GVs
+ GM+Afqx213t8/+njFXXXtj48+Y163DmuvZ0bVWFWcWUL3f/HMoSP2Sc5psHToVlYa9h2
+ 5A+azEywDCjEfwU+l/qSE1Xc1e7tuEUSzFA+LGwluktUbinU6j2DSqwcK9gAdnCSxCxa
+ HLhTa7o5eHfYInpt+U1XsuuG/vr2evva8h5tyqgpKBPNs0RmlLFbo+TdeNv9ZpERnzg6
+ vue9ilrJ/klFED+FOVoq8hRV9FZQ1sRvZw5+G7Z+XD+l5/VB/TwJPa2f0a/ooxG+DHRJ
+ z8JzUR+jSfCwaSHiEqCKgzPUTlRjjQPiKfHytFtkkf0PQBn9ZgplbmRzdHJlYW0KZW5k
+ b2JqCjcwIDAgb2JqCjcwNAplbmRvYmoKMjYgMCBvYmoKWyAvSUNDQmFzZWQgNjkgMCBS
+ IF0KZW5kb2JqCjcxIDAgb2JqCjw8IC9MZW5ndGggNzIgMCBSIC9OIDMgL0FsdGVybmF0
+ ZSAvRGV2aWNlUkdCIC9GaWx0ZXIgL0ZsYXRlRGVjb2RlID4+CnN0cmVhbQp4AYVUz2sT
+ QRT+Nm6p0CIIWmsOsniQIklZq2hF1Db9EWJrDNsftkWQZDNJ1m426+4mtaWI5OLRKt5F
+ 7aEH/4AeevBkL0qFWkUo3qsoYqEXLfHNbky2perAzn7z3jfvfW923wANctI09YAE5A3H
+ UqIRaWx8Qmr8iACOoglBNCVV2+xOJAZBg3P5e+fYeg+BW1bDe/t3snetmtK2mgeE/UDg
+ R5rZKrDvF3EKWRICiDzfoSnHdAjf49jy7I85Tnl4wbUPKz3EWSJ8QDUtzn9NuFPNJdNA
+ g0g4lPVxUj6c14uU1x0HaW5mxsgQvU+QprvM7qtioZxO9g6QvZ30fk6z3j7CIcILGa0/
+ RriNnvWM1T/iYeGk5sSGPRwYNfT4YBW3Gqn4NcIUXxBNJ6JUcdkuDfGYrv1W8kqCcJA4
+ ymRhgHNaSE/XTG74uocFfSbXE6/id1ZR4XmPE2fe1N3vRdoCrzAOHQwaDJoNSFAQRQRh
+ mLBQQIY8GjE0snI/I6sGG5N7MnUkart0YkSxQXs23D23UaTdPP4oInGUQ7UIkvxB/iqv
+ yU/lefnLXLDYVveUrZuauvLgO8XlmbkaHtfTyONzTV58ldR2k1dHlqx5erya7Bo/7FeX
+ MeaCNY/Ec7D78S1flcyXKYwUxeNV8+pLhHVaMTffn2x/Oz3iLs8utdZzrYmLN1abl2f9
+ akj77qq8k+ZV+U9e9fH8Z83EY+IpMSZ2iuchiZfFLvGS2EurC+JgbccInZWGKdJtkfok
+ 1WBgmrz1L10/W3i9Rn8M9VGUGczSVIn3f8IqZDSduQ5v+o/bx/wX5PeK558oAi9s4MiZ
+ um1Tce8QoWWlbnOuAhe/0X3wtm5ro344/ARYPKsWrVI1nyC8ARx2h3oe6CmY05aWzTlS
+ hyyfk7rpymJSzFDbQ1JS1yXXZUsWs5lVYul22JnTHW4coTlC98SnSmWT+q/xEbD9sFL5
+ +axS2X5OGtaBl/pvwLz9RQplbmRzdHJlYW0KZW5kb2JqCjcyIDAgb2JqCjczNwplbmRv
+ YmoKOCAwIG9iagpbIC9JQ0NCYXNlZCA3MSAwIFIgXQplbmRvYmoKNzMgMCBvYmoKPDwg
+ L0xlbmd0aCA3NCAwIFIgL04gMyAvQWx0ZXJuYXRlIC9EZXZpY2VSR0IgL0ZpbHRlciAv
+ RmxhdGVEZWNvZGUgPj4Kc3RyZWFtCngBhVTPaxNBFP42bqnQIghaaw6yeJAiSVmraEXU
+ Nv0RYmsM2x+2RZBkM0nWbjbr7ia1pYjk4tEq3kXtoQf/gB568GQvSoVaRSjeqyhioRct
+ 8c1uTLal6sDOfvPeN+99b3bfAA1y0jT1gATkDcdSohFpbHxCavyIAI6iCUE0JVXb7E4k
+ BkGDc/l759h6D4FbVsN7+3eyd62a0raaB4T9QOBHmtkqsO8XcQpZEgKIPN+hKcd0CN/j
+ 2PLsjzlOeXjBtQ8rPcRZInxANS3Of024U80l00CDSDiU9XFSPpzXi5TXHQdpbmbGyBC9
+ T5Cmu8zuq2KhnE72DpC9nfR+TrPePsIhwgsZrT9GuI2e9YzVP+Jh4aTmxIY9HBg19Phg
+ Fbcaqfg1whRfEE0nolRx2S4N8Ziu/VbySoJwkDjKZGGAc1pIT9dMbvi6hwV9JtcTr+J3
+ VlHheY8TZ97U3e9F2gKvMA4dDBoMmg1IUBBFBGGYsFBAhjwaMTSycj8jqwYbk3sydSRq
+ u3RiRLFBezbcPbdRpN08/igicZRDtQiS/EH+Kq/JT+V5+ctcsNhW95Stm5q68uA7xeWZ
+ uRoe19PI43NNXnyV1HaTV0eWrHl6vJrsGj/sV5cx5oI1j8RzsPvxLV+VzJcpjBTF41Xz
+ 6kuEdVoxN9+fbH87PeIuzy611nOtiYs3VpuXZ/1qSPvuqryT5lX5T1718fxnzcRj4ikx
+ JnaK5yGJl8Uu8ZLYS6sL4mBtxwidlYYp0m2R+iTVYGCavPUvXT9beL1Gfwz1UZQZzNJU
+ ifd/wipkNJ25Dm/6j9vH/Bfk94rnnygCL2zgyJm6bVNx7xChZaVuc64CF7/RffC2bmuj
+ fjj8BFg8qxatUjWfILwBHHaHeh7oKZjTlpbNOVKHLJ+TuunKYlLMUNtDUlLXJddlSxaz
+ mVVi6XbYmdMdbhyhOUL3xKdKZZP6r/ERsP2wUvn5rFLZfk4a1oGX+m/AvP1FCmVuZHN0
+ cmVhbQplbmRvYmoKNzQgMCBvYmoKNzM3CmVuZG9iagozOSAwIG9iagpbIC9JQ0NCYXNl
+ ZCA3MyAwIFIgXQplbmRvYmoKNCAwIG9iago8PCAvVHlwZSAvUGFnZXMgL01lZGlhQm94
+ IFswIDAgNjEyIDc5Ml0gL0NvdW50IDEgL0tpZHMgWyAzIDAgUiBdID4+CmVuZG9iago3
+ NSAwIG9iago8PCAvVHlwZSAvQ2F0YWxvZyAvT3V0bGluZXMgMiAwIFIgL1BhZ2VzIDQg
+ MCBSIC9WZXJzaW9uIC8xLjQgPj4KZW5kb2JqCjQ5IDAgb2JqCjw8IC9MZW5ndGggNzYg
+ MCBSIC9PcmRlciAxIC9FbmNvZGUgWyAwIDEzNjQgXSAvRnVuY3Rpb25UeXBlIDAgL0Jp
+ dHNQZXJTYW1wbGUKOCAvRGVjb2RlIFsgMCAxIDAgMSAwIDEgXSAvRG9tYWluIFsgMCAx
+ IF0gL1JhbmdlIFsgMCAxIDAgMSAwIDEgXSAvU2l6ZSBbIDEzNjUKXSAvRmlsdGVyIC9G
+ bGF0ZURlY29kZSA+PgpzdHJlYW0KeAGlwoVSQlEAQMG/tru7u7HpBhUDA1uxA+tTjjEy
+ +PDFjZ1NfpC0mPjg+7vi+DvF34gLj71h95WY7egrEl+IGkdeUJwjkiOsPZQj9Kw++Izh
+ E0GZgSfsPhKw7X9E9AP+f30PqLzH99N7j2bPHTrddxje4pa5eovlG1adrtwg9JoVs8vX
+ SL9iOX/pCs2LWXQuZCm8ZEHy/CXmL5gX6LpA6Dkus3PnSD9jLn/2DK2nzOidPuX3CdPy
+ p04wf8yUwMljnB8xaXHiCLmHTPw5foj6DOMZxvSOZvh9wKj8kQNM7jMidngfh3sMWx/a
+ Q+IuQ8aDu6hPM5hmQG9/mu87ivt2KL5Nn/DebRxu0Wu9ZwuJm/QYd2+iOEX3z64UOjtT
+ dG6o79ig+DodwtvXsbtGu+22NUQnafu3NYnKBK35LQl0NidojqtvimMYo0lmYwzLURqd
+ NkQRGqHBbH0ElWHq8+vC6KwNobMmRGGQGsnVQSwHqHZaFUConyqzlX6k+6j8s8KHei/l
+ esu8FHook1zqwbybUoElbr5+Al7liFUKZW5kc3RyZWFtCmVuZG9iago3NiAwIG9iago0
+ MTAKZW5kb2JqCjQ4IDAgb2JqCjw8IC9MZW5ndGggNzcgMCBSIC9PcmRlciAxIC9FbmNv
+ ZGUgWyAwIDEzNjQgXSAvRnVuY3Rpb25UeXBlIDAgL0JpdHNQZXJTYW1wbGUKOCAvRGVj
+ b2RlIFsgMCAxIDAgMSAwIDEgXSAvRG9tYWluIFsgMCAxIF0gL1JhbmdlIFsgMCAxIDAg
+ MSAwIDEgXSAvU2l6ZSBbIDEzNjUKXSAvRmlsdGVyIC9GbGF0ZURlY29kZSA+PgpzdHJl
+ YW0KeAGtwQcCgQAAQNH7X0k0VLQ1jBbtNHUFd+C/t20/+mwfzspZlnWhzMvMmaZ5oozT
+ yBlA7+HN6UFd31HaruU0TdtQ6qbmVFVdUcqq5BSgV/HiPEH5M6dkecZJ0yylJGnCieMk
+ pjziB+cOut1vnCsoukaUMAo5QRAGFD/wOReQd/E4LshxHY4NsmyLYlomyDANytk4c04g
+ /aRzNJCqqZwjSDkqFFmRQZIsUURJ5BxA+8OeI4B2wu5/X6r+RswKZW5kc3RyZWFtCmVu
+ ZG9iago3NyAwIG9iagoxODgKZW5kb2JqCjQ3IDAgb2JqCjw8IC9MZW5ndGggNzggMCBS
+ IC9PcmRlciAxIC9FbmNvZGUgWyAwIDEzNjQgXSAvRnVuY3Rpb25UeXBlIDAgL0JpdHNQ
+ ZXJTYW1wbGUKOCAvRGVjb2RlIFsgMCAxIDAgMSAwIDEgXSAvRG9tYWluIFsgMCAxIF0g
+ L1JhbmdlIFsgMCAxIDAgMSAwIDEgXSAvU2l6ZSBbIDEzNjUKXSAvRmlsdGVyIC9GbGF0
+ ZURlY29kZSA+PgpzdHJlYW0KeAGlwoVSQlEAQMG/tru7u7HpBhUDA1uxA+tTjjEy+PDF
+ jZ1NfpC0mPjg+7vi+DvF34gLj71h95WY7egrEl+IGkdeUJwjkiOsPZQj9Kw++IzhE0GZ
+ gSfsPhKw7X9E9AP+f30PqLzH99N7j2bPHTrddxje4pa5eovlG1adrtwg9JoVs8vXSL9i
+ OX/pCs2LWXQuZCm8ZEHy/CXmL5gX6LpA6Dkus3PnSD9jLn/2DK2nzOidPuX3CdPyp04w
+ f8yUwMljnB8xaXHiCLmHTPw5foj6DOMZxvSOZvh9wKj8kQNM7jMidngfh3sMWx/aQ+Iu
+ Q8aDu6hPM5hmQG9/mu87ivt2KL5Nn/DebRxu0Wu9ZwuJm/QYd2+iOEX3z64UOjtTdG6o
+ 79ig+DodwtvXsbtGu+22NUQnafu3NYnKBK35LQl0NidojqtvimMYo0lmYwzLURqdNkQR
+ GqHBbH0ElWHq8+vC6KwNobMmRGGQGsnVQSwHqHZaFUConyqzlX6k+6j8s8KHei/lesu8
+ FHook1zqwbybUoElbr5+Al7liFUKZW5kc3RyZWFtCmVuZG9iago3OCAwIG9iago0MTAK
+ ZW5kb2JqCjQ2IDAgb2JqCjw8IC9MZW5ndGggNzkgMCBSIC9PcmRlciAxIC9FbmNvZGUg
+ WyAwIDEzNjQgXSAvRnVuY3Rpb25UeXBlIDAgL0JpdHNQZXJTYW1wbGUKOCAvRGVjb2Rl
+ IFsgMCAxIDAgMSAwIDEgXSAvRG9tYWluIFsgMCAxIF0gL1JhbmdlIFsgMCAxIDAgMSAw
+ IDEgXSAvU2l6ZSBbIDEzNjUKXSAvRmlsdGVyIC9GbGF0ZURlY29kZSA+PgpzdHJlYW0K
+ eAGNwgk3VHEYB+AvJhKJRCKRkpKSkhKJRCIZY8asZgxjZuz7vu9bX+v9vZ3rmNO943/v
+ fZ/z8N8E24zzpXCML01exNhwjC8ko3yhex5l06N8LjnCZ8IRPjN5GmHDYT6VDPOp7kmY
+ TYf4RPA4xMdDskE+NnkUZMMAHwn7+Sj50M+mfXwoeODjA6+4hw9U9z1sOMj7wm7eT95z
+ s1UX713Hnkt914XdAXEndlV3nEjdjx1JB3aubjtgsw/bdrf6oP0j24st1c1epP6NTeEe
+ bPZgw3Y3Nuyud0P7S7YL66prXUj9E2vCnVjrxKrtDqzaXemA9od4O1ZuXG5H6u9YFm7D
+ chuWJFuxZHmxFdpv4i1YNF5ogfpXLEg2Y6EZ85JNmLc814TrXzAn2Yg549lGqH/GrPAn
+ zEg2YMbydAOuf8S0cD2mdafqof4BU8LvMSlZh0nzE3X4/x0mhGsxoTteC/W3GBd+g4Rw
+ DRKKlKihuP5rigtXU1w3Vk2mX1FM8iWNCVfRmMloFRm+oKhkJUV1RyvJ9HMalR15RqIV
+ NGIyUkGGTykiXE6R5OFyMl1Gw4LhMgo/ES+lsGqolAwfU0i4hELJQyVktZiG7AaLKfhI
+ vIiCqoEiMnxIAeFCCiT7C8lqAfnt+grI90A8n3yq3nxKfZ+8knnkverJI5u55LE7mEva
+ e7I5NKjqzqHUd8ktnE3ubHLZziKX3YEs0t4Rz6SBG52ZlPo2OYUzyJlB/ZLp1G/ZkU7a
+ W+Jp5Ej7B4pzCpwKZW5kc3RyZWFtCmVuZG9iago3OSAwIG9iago1NzIKZW5kb2JqCjQ1
+ IDAgb2JqCjw8IC9MZW5ndGggODAgMCBSIC9PcmRlciAxIC9FbmNvZGUgWyAwIDEzNjQg
+ XSAvRnVuY3Rpb25UeXBlIDAgL0JpdHNQZXJTYW1wbGUKOCAvRGVjb2RlIFsgMCAxIDAg
+ MSAwIDEgXSAvRG9tYWluIFsgMCAxIF0gL1JhbmdlIFsgMCAxIDAgMSAwIDEgXSAvU2l6
+ ZSBbIDEzNjUKXSAvRmlsdGVyIC9GbGF0ZURlY29kZSA+PgpzdHJlYW0KeAGtwQcCgQAA
+ QNH7X0k0VLQ1jBbtNHUFd+C/t20/+mwfzspZlnWhzMvMmaZ5oozTyBlA7+HN6UFd31Ha
+ ruU0TdtQ6qbmVFVdUcqq5BSgV/HiPEH5M6dkecZJ0yylJGnCieMkpjziB+cOut1vnCso
+ ukaUMAo5QRAGFD/wOReQd/E4LshxHY4NsmyLYlomyDANytk4c04g/aRzNJCqqZwjSDkq
+ FFmRQZIsUURJ5BxA+8OeI4B2wu5/X6r+RswKZW5kc3RyZWFtCmVuZG9iago4MCAwIG9i
+ agoxODgKZW5kb2JqCjQ0IDAgb2JqCjw8IC9MZW5ndGggODEgMCBSIC9PcmRlciAxIC9F
+ bmNvZGUgWyAwIDEzNjQgXSAvRnVuY3Rpb25UeXBlIDAgL0JpdHNQZXJTYW1wbGUKOCAv
+ RGVjb2RlIFsgMCAxIDAgMSAwIDEgXSAvRG9tYWluIFsgMCAxIF0gL1JhbmdlIFsgMCAx
+ IDAgMSAwIDEgXSAvU2l6ZSBbIDEzNjUKXSAvRmlsdGVyIC9GbGF0ZURlY29kZSA+Pgpz
+ dHJlYW0KeAGNwgk3VHEYB+AvJhKJRCKRkpKSkhKJRCIZY8asZgxjZuz7vu9bX+v9vZ3r
+ mNO943/vfZ/z8N8E24zzpXCML01exNhwjC8ko3yhex5l06N8LjnCZ8IRPjN5GmHDYT6V
+ DPOp7kmYTYf4RPA4xMdDskE+NnkUZMMAHwn7+Sj50M+mfXwoeODjA6+4hw9U9z1sOMj7
+ wm7eT95zs1UX713Hnkt914XdAXEndlV3nEjdjx1JB3aubjtgsw/bdrf6oP0j24st1c1e
+ pP6NTeEebPZgw3Y3Nuyud0P7S7YL66prXUj9E2vCnVjrxKrtDqzaXemA9od4O1ZuXG5H
+ 6u9YFm7DchuWJFuxZHmxFdpv4i1YNF5ogfpXLEg2Y6EZ85JNmLc814TrXzAn2Yg549lG
+ qH/GrPAnzEg2YMbydAOuf8S0cD2mdafqof4BU8LvMSlZh0nzE3X4/x0mhGsxoTteC/W3
+ GBd+g4RwDRKKlKihuP5rigtXU1w3Vk2mX1FM8iWNCVfRmMloFRm+oKhkJUV1RyvJ9HMa
+ lR15RqIVNGIyUkGGTykiXE6R5OFyMl1Gw4LhMgo/ES+lsGqolAwfU0i4hELJQyVktZiG
+ 7AaLKfhIvIiCqoEiMnxIAeFCCiT7C8lqAfnt+grI90A8n3yq3nxKfZ+8knnkverJI5u5
+ 5LE7mEvae7I5NKjqzqHUd8ktnE3ubHLZziKX3YEs0t4Rz6SBG52ZlPo2OYUzyJlB/ZLp
+ 1G/ZkU7aW+Jp5Ej7B4pzCpwKZW5kc3RyZWFtCmVuZG9iago4MSAwIG9iago1NzIKZW5k
+ b2JqCjQzIDAgb2JqCjw8IC9MZW5ndGggODIgMCBSIC9PcmRlciAxIC9FbmNvZGUgWyAw
+ IDEzNjQgXSAvRnVuY3Rpb25UeXBlIDAgL0JpdHNQZXJTYW1wbGUKOCAvRGVjb2RlIFsg
+ MCAxIDAgMSAwIDEgXSAvRG9tYWluIFsgMCAxIF0gL1JhbmdlIFsgMCAxIDAgMSAwIDEg
+ XSAvU2l6ZSBbIDEzNjUKXSAvRmlsdGVyIC9GbGF0ZURlY29kZSA+PgpzdHJlYW0KeAGl
+ woVSQlEAQMG/tru7u7HpBhUDA1uxA+tTjjEy+PDFjZ1NfpC0mPjg+7vi+DvF34gLj71h
+ 95WY7egrEl+IGkdeUJwjkiOsPZQj9Kw++IzhE0GZgSfsPhKw7X9E9AP+f30PqLzH99N7
+ j2bPHTrddxje4pa5eovlG1adrtwg9JoVs8vXSL9iOX/pCs2LWXQuZCm8ZEHy/CXmL5gX
+ 6LpA6Dkus3PnSD9jLn/2DK2nzOidPuX3CdPyp04wf8yUwMljnB8xaXHiCLmHTPw5foj6
+ DOMZxvSOZvh9wKj8kQNM7jMidngfh3sMWx/aQ+IuQ8aDu6hPM5hmQG9/mu87ivt2KL5N
+ n/DebRxu0Wu9ZwuJm/QYd2+iOEX3z64UOjtTdG6o79ig+DodwtvXsbtGu+22NUQnafu3
+ NYnKBK35LQl0NidojqtvimMYo0lmYwzLURqdNkQRGqHBbH0ElWHq8+vC6KwNobMmRGGQ
+ GsnVQSwHqHZaFUConyqzlX6k+6j8s8KHei/lesu8FHook1zqwbybUoElbr5+Al7liFUK
+ ZW5kc3RyZWFtCmVuZG9iago4MiAwIG9iago0MTAKZW5kb2JqCjQyIDAgb2JqCjw8IC9M
+ ZW5ndGggODMgMCBSIC9PcmRlciAxIC9FbmNvZGUgWyAwIDEzNjQgXSAvRnVuY3Rpb25U
+ eXBlIDAgL0JpdHNQZXJTYW1wbGUKOCAvRGVjb2RlIFsgMCAxIDAgMSAwIDEgXSAvRG9t
+ YWluIFsgMCAxIF0gL1JhbmdlIFsgMCAxIDAgMSAwIDEgXSAvU2l6ZSBbIDEzNjUKXSAv
+ RmlsdGVyIC9GbGF0ZURlY29kZSA+PgpzdHJlYW0KeAGtwQcCgQAAQNH7X0k0VLQ1jBbt
+ NHUFd+C/t20/+mwfzspZlnWhzMvMmaZ5oozTyBlA7+HN6UFd31HaruU0TdtQ6qbmVFVd
+ Ucqq5BSgV/HiPEH5M6dkecZJ0yylJGnCieMkpjziB+cOut1vnCsoukaUMAo5QRAGFD/w
+ OReQd/E4LshxHY4NsmyLYlomyDANytk4c04g/aRzNJCqqZwjSDkqFFmRQZIsUURJ5BxA
+ +8OeI4B2wu5/X6r+RswKZW5kc3RyZWFtCmVuZG9iago4MyAwIG9iagoxODgKZW5kb2Jq
+ CjQxIDAgb2JqCjw8IC9MZW5ndGggODQgMCBSIC9PcmRlciAxIC9FbmNvZGUgWyAwIDEz
+ NjQgXSAvRnVuY3Rpb25UeXBlIDAgL0JpdHNQZXJTYW1wbGUKOCAvRGVjb2RlIFsgMCAx
+ IDAgMSAwIDEgXSAvRG9tYWluIFsgMCAxIF0gL1JhbmdlIFsgMCAxIDAgMSAwIDEgXSAv
+ U2l6ZSBbIDEzNjUKXSAvRmlsdGVyIC9GbGF0ZURlY29kZSA+PgpzdHJlYW0KeAGlwoVS
+ QlEAQMG/tru7u7HpBhUDA1uxA+tTjjEy+PDFjZ1NfpC0mPjg+7vi+DvF34gLj71h95WY
+ 7egrEl+IGkdeUJwjkiOsPZQj9Kw++IzhE0GZgSfsPhKw7X9E9AP+f30PqLzH99N7j2bP
+ HTrddxje4pa5eovlG1adrtwg9JoVs8vXSL9iOX/pCs2LWXQuZCm8ZEHy/CXmL5gX6LpA
+ 6Dkus3PnSD9jLn/2DK2nzOidPuX3CdPyp04wf8yUwMljnB8xaXHiCLmHTPw5foj6DOMZ
+ xvSOZvh9wKj8kQNM7jMidngfh3sMWx/aQ+IuQ8aDu6hPM5hmQG9/mu87ivt2KL5Nn/De
+ bRxu0Wu9ZwuJm/QYd2+iOEX3z64UOjtTdG6o79ig+DodwtvXsbtGu+22NUQnafu3NYnK
+ BK35LQl0NidojqtvimMYo0lmYwzLURqdNkQRGqHBbH0ElWHq8+vC6KwNobMmRGGQGsnV
+ QSwHqHZaFUConyqzlX6k+6j8s8KHei/lesu8FHook1zqwbybUoElbr5+Al7liFUKZW5k
+ c3RyZWFtCmVuZG9iago4NCAwIG9iago0MTAKZW5kb2JqCjQwIDAgb2JqCjw8IC9MZW5n
+ dGggODUgMCBSIC9PcmRlciAxIC9FbmNvZGUgWyAwIDEzNjQgXSAvRnVuY3Rpb25UeXBl
+ IDAgL0JpdHNQZXJTYW1wbGUKOCAvRGVjb2RlIFsgMCAxIDAgMSAwIDEgXSAvRG9tYWlu
+ IFsgMCAxIF0gL1JhbmdlIFsgMCAxIDAgMSAwIDEgXSAvU2l6ZSBbIDEzNjUKXSAvRmls
+ dGVyIC9GbGF0ZURlY29kZSA+PgpzdHJlYW0KeAG1wolWAVEAANDvMvvqS7NFlsggknUG
+ oZTKki1LKcIXdOrkOKMx5s28d88tbeylY5WNHfjarhgtKmtVeS0euRJleIsrUfVLLCK6
+ FItLsQC5UFj+XggFrfmFAOGnkDc29ymA/RByFmY/BL1zIauXz87BZub87jufQfeNz7zx
+ 1yjO+OvD0zPecC49+3fKpUFeTTmAE+7K2tSE0z7mUggmx9zPV81s8hXGEZvcvhyxMA/Z
+ S92JIWv+gE0Ajg/YbSY+0N1n4pbH+ozGHhNDU+ox0gvKXUb6S0tdOgp3h47qvujQJrfp
+ C/CRNm1oi44ApyKt/eEWpfGZCqN5/kQh/Eidq4ceKWibZOjYYJM084EMmhp4II+/JwOQ
+ +u/J/Q3SbyjhbwA/uyNQvSXOtPpuCQjrhM9Yb50wFvfWt2u41+zTGq63ip9C7aniuze4
+ B90K7qng7oMxd8XsMuY+0FXGrC5hLsOdJQysgjktdCjYts2hqMs2B+wnsu1v0XYC8hsK
+ r7WjCmVuZHN0cmVhbQplbmRvYmoKODUgMCBvYmoKMzg0CmVuZG9iagoyIDAgb2JqCjw8
+ IC9MYXN0IDg2IDAgUiAvRmlyc3QgODcgMCBSID4+CmVuZG9iago4NyAwIG9iago8PCAv
+ UGFyZW50IDg4IDAgUiAvQ291bnQgMCAvRGVzdCBbIDMgMCBSIC9YWVogMCA3MzMgMCBd
+ IC9UaXRsZSAoQ2FudmFzIDEpCj4+CmVuZG9iago4OCAwIG9iago8PCA+PgplbmRvYmoK
+ ODYgMCBvYmoKPDwgL1BhcmVudCA4OCAwIFIgL0NvdW50IDAgL0Rlc3QgWyAzIDAgUiAv
+ WFlaIDAgNzMzIDAgXSAvVGl0bGUgKENhbnZhcyAxKQo+PgplbmRvYmoKODkgMCBvYmoK
+ PDwgL0xlbmd0aCA5MCAwIFIgL0xlbmd0aDEgMTMwODAgL0ZpbHRlciAvRmxhdGVEZWNv
+ ZGUgPj4Kc3RyZWFtCngBvXsLeFNV1uje55mcJG0eTfPoI0mTNH2n7zZQ6GnpC9pAaSm2
+ SKUFyhQGsCjyHBABLRTfMwoiIz7QQRw0FAeDDFwugw6CzEXBX1TUcUTEweqMU0EtOblr
+ n4QKvX7z+X13vjmnK/t59l5nrbXXXmud3cW33dGFNGgNolHjtM6eOUi+cnMRoi7OWtDZ
+ EykbuiF9c9aSxfZImU1DiL5nTs8vFkTKigBCgusX85dHn49bg1BCYndX5+xIO7oKaXE3
+ VETKuBBSV/eCxcsiZf0ZSH8z/9ZZ0fY40t6woHNZdH50Dsr2hZ0LuiL9cxWQpvXcevvi
+ SNm7DdL5Pbd1RfvjVsDv/yAMtW40DynRfKRAFNLCPR0h/qLgQgy0knaAiuyWJ2fEln2L
+ dGRYhJ725Kwh6euOP35/5dxVj2q1sgb6KeX+pAGe4dKldITUGNo/UK0ebiGt5HIHUVNm
+ ENUBjAUoBMjI3KMQX8UPorj2QVGJbQxS2c5avjqEc4D+F+TfAM4R1RqknLWuzDZr3bq6
+ 9AolrkclDEY2XI1cclrV73rBFsRj+11OSMZEEqq/JAlKSFSWuGyhkpm2qyVBBRYTbN+5
+ fm27AnDZVW771pVnewv6nSqptZ2sgPZ+24mMIAXJcVeQwWKs7ZjrLtsfStJtL5eMtvV7
+ oK7ftqcCkn22HSV32Z5ZL9c8nSEnT7mCeGu/7UmS7LNth/EfXSc3PBJ5cG0k6VkvT3Tr
+ XjlZuDdIvbDPtsCVapsJD2JRZWt3zbdNd/lsUyqC2N1v85PH9tkaPCdt9WTqfpsYmag4
+ MnqRS8Y4PzJtluuALS0yQwrpLRpsdleDLQnGz3ryUVuW6xZbRUYQ73ylLi3DVed5tDiI
+ B+U5SAKIkmRhJJnlOYh/h2pROp6G3PixvXXpgDN+sN+2DpKte+vSStxB+qKot+311HnW
+ AxQDuAFagniKmMVv5mfzLXwBn8mn86m8g0/mE/g4hV6hVcQo1ApBoVBwCkZBKZAiLhj+
+ q5hJpCiO05KEY8gvI+e1FMnDD/wiCisoNAEFOXR3/JJyc7l+rM5XU/UTPx1yZUdV5o+X
+ +cdsphknBR6tb24N7EpqC+STTDip7br2/59sVyU8Xd+0fG/T8ktTq7uc1R3O6i6AjsCm
+ Jd3mwJqZdvueS8tJgz1Ap3bMnNVN0s6uwHJnV1XgkrPKvqdJfm5E81TS3OSs2oOmVk9p
+ 3TNV7KrqbxKbqp2dVW17G6vrJt4w18bhueqqf2KuajJYHZmrUX5uxFwTSXMjmWsimWsi
+ matRbJTnysysnttcidjDSMceQdnsZpTEVKIkhMLvA3xAUqk5/DV7CgnhUHiABs2FUwh8
+ PITj0EuIR6+g1aBt3ka7sBI50QDOR+/hJJyBziIJfYD+hqxoE3oSfqvRRXwZtMwXOA36
+ FKO16Am0PdyDelA53Bcxi4yoFH0RXhk+Fv4eVaI+dBTz2ICTwvuRF/XCvRVtw2pqZngP
+ MqMGtBS0+lr0Bno/3B/+O4xfjD7DOuxlRoc/BAFjocaHNqJd6BXswE6cgW8Ofwb1ZsBx
+ OtoV9oeXwHNfQy8vmohWwmyfYBtOxZl4K/6IHgivCd8P75YIbS1oFtwL0F1oC9qGdsu9
+ ZjKJrBHGr0L10HY/ehNdRN+Awk3HlXgZ9Q79d/ofzGhma/go4NEC83Wg7ZgGqrhwC56N
+ e/Bu/DL+E75MlVCdtI9+h+lhngLcWtAG9BQ6iP6MTqMP0SU0gH5AIcwATmPxJLwS/xae
+ +xtVQLVTq6h7qfepr+k8+iOGZzaxd7MHwkz4nfAPgHMyykCjYaVPRq2oC+45aCG6A92J
+ 1mMebUZ70J8A24/Rx1jAWuzFebgWT8E341/i5eghvAO/is/h8/gC/gKwM1A2ykl5qSUw
+ 31pqI7Wb6qf2UwO0jl5Mr6IP0x/Rlxkj084chvtjNptdzCVy9fxk6TfSx+Hs8IPhrcCX
+ eLhdKB1lo7GYASouQOuBkxuBZtvQDvQCehH1o/7wEPaho+gtwOsT9DW6AhxLhNuB83Ep
+ bsSTAcP5eAG+E28BDHfhfYDlAXwAvYvfxUNwS8hCKals6maqk1oO91a0hTot00dNO+g0
+ Opuup5vD/6R303vobxg3M41ZxKxk+pgtzHY2kR3D3sROY3vYR9h97An2f9iv2UEuievl
+ dnAvc6d5BV/Ib+ElnAK42LEbvYwOgdQ9SvdA2YXG4fXA1anoTZDeAfQaGkLfo8PodzgJ
+ STThZmr4KRQMbwBuHkR/oH+FytBD1K+pCeFyeietxPnhKzBWLvDr2o3EjPQ0T6rb5Uxx
+ 2G3JSYkJVovZFG+MM+h12tgYjVolKBU8xzI0hVFWtbOmwx5I7Qgwqc66umxSdnZCRed1
+ FR0BO1TV3NgnYCfPdULTDT1F6DlnRE8x0lMc7om19jJUlp1lr3baAyernPYgnja5FfL3
+ VTnb7IEBOe+X8w/KeQ3kHQ54wF5t7q6yB3CHvTpQs6S7r7qjKjsL7xdhMxCys9B+hESk
+ IgMH0LjOVaBc0TjSozpgdVZVByxOyEMb7a7unB1onNxaXZXgcLRlZwXwuFnOmQHkrAzE
+ ZkYfJ8+BEnQ3tcLc2VlzA4A/2qSe7Zy9KSiimR0k1zm9NUB3tgWoDjKHLjNgclYFTCs+
+ M/9YvJarvve6xgDlruns6qsJiB2bgOik2EFKnfdCqb7ZDsNSd7e1BvDdgBxBQsY98haR
+ bcLdMc8eUDornd198zqA5qixtd8qWqudHVVtAdTU2m8RLXIhO2u/efVoBxBlf3ZFdgVJ
+ RzvMqyPp5+si9W8fJql59dG/QlrfNEwXTOZ2jgc0A/ZZMAnQAnAtJT9dpahvVimQD642
+ DG85F/AZF6BAlGh3gHWP7wysaY6i0dldFUVuXlW/0mKV96XKNujf0acdBQyE/lqnve9b
+ BJx1Dnx5Y01ntIZza79FpJHwf1iEArjzWn4J2T/dsCV1m53dhH1LZFZD2Wmuvq4CymTf
+ ygaDM6s+iJSNrXswvr8tiMN3B1FV0n7YYOgZt0BzJhG4uVUwHRSysqAiwwE5wKAGJqoh
+ kmHvs/eNn91nr7F3g0gxbjmFhq6+Ni8QrLkVyIKmtDoCYlvCcLarrW0UjJNDxoFHoHtf
+ G4wwLzoCpHKVNwSdvFn18Fapja2TWwNrqhICYlUbEB2E+HBja+AwyG9bG/TKHcYUMF41
+ 1xzFOQ9wzs2A9vzIKGDWrIEh2vr6yJjNrU5H4HBfX0IfWXWRMljIIyvEaEUQkS6EwkG8
+ phGehcTpSJBJ7nA6AK02QtMCEOBrAgRm/b+ncNEw3vBkMWBbJFO45D9E4dKfQ2Hfz6Lw
+ qGFMb6DwaMB5FKFw2X+PwmNuoPDYf0/h8mG8AUkRsC2XKVzxH6Jw5c+h8LifReGqYUxv
+ oHA14FxFKFzz36Nw7Q0Urvv3FB4/jDcgOQGwHS9TuP4/ROGGn0Nh/8+i8MRhTG+g8CTA
+ eSKhcON/j8KTb6Bw07+ncPMw3oDkFMC2WaZwy3+IwlN/DoVv+lkUbh3G9AYKtwHOrYTC
+ 04YpLCYE0PV6eM0ItYv+44r55utIzv4ZbaV84D7vQu0ARsivgbpCdip6lvkUbeN8qIWk
+ UPcM1JG8A1IvczsaDfmVkNZCWg6plzwP+UqAXhhnI4AS6tfySWgNqYu2raKT0Fqor4z2
+ XwV5K8wTQ1IAI9hwkXgTBI0QBzYyQnY0jTj5N1wUxOGuXRAV+BkXG+3DgWcTCV+RCuV1
+ TwpIBXMiiDL91BWDYiEqpkN6ZEBxgGc8MoEPiJAFPL8E8O8Q+LrJyAbYOlAK+IYueZBC
+ VIh+hf6IPgK/4wl8imqillEX6Q10kBGYF1mOXcz+hZvJHeMr+Xv5wxD32KqsVD6svCjU
+ CA+q4lUdqpfVZvVU9WXN/eDVbUUIfIwj8OY8Gis6WC4JbHeGT6KRwDJJNE1ZlRyfhJFF
+ odzlmF8GgY2Jg2X+UNlE7eUyvzZUhsrLQmUE8nILdA6dB2Ar80zw6kn2yA9jg0zT0IsE
+ ZYzapVlUF/s+vGeNmO6hU7VLqaXaXqpXyzG6WEOcxRATy7CGhcofvOx2lmKtxjjjO47K
+ /fj3CKbUTrzsX3Q1pPP5fNrzqLw8Lxe36w3F5djE8ZwuzhRvw85UT2pR+9q65todm/Kb
+ 7Xmrxzz/dMtsugBnPXf7TEr69WXp1NFnQxd7Pnr3hxDBxwj4+GV8CkWzXqc0GE0mq16j
+ MCjphZoflJbrpx8cJFPrfRC9qLrgl+dHJnB5aC4WO4tL9LpCT6oXF+CNk+7YNLG69vT6
+ wjaCwLssF5S+kb6STktvvNja+dUWjHH+0edCn/fA/GsAiZcgDkGjVNGA02iBhflxD7Iw
+ bI/jzgid/SF5RlTuH8jLNTh0jjXYK72FM6T/ITSlQQoQuxN4RyEiZefEX3ZT2MOmCaVc
+ ibKO6xaWCRuYDdxW+hFmC7eLfpbZyQVxUDiGjwln6bOCEfMcRyGFUgk/AuZZKk4Q3Hoo
+ xrGsWw9tvCKDxMEEFTh0nFKgWYVKA1iqBIZjgziuX0lTkOwTLOquO24zZy6ZqB00+0M+
+ H/zpfBYZd7MXlZvK/OVlZXqfzwtiwvbmZK7S1oPJyRxOCDBH23pzzNEKGiroo2066Al/
+ vdqyMh6A8Bq1Y4cKHG4HOMwOTHnxkuALeDolSP0zQp/MkQ5Rr4J/XYUn/zCWEAgogtGz
+ QBsKcirkJZHgV2HZK1E9RII5bRDhU+hVecXWQ4MKaElSGuJE9Zm5eRgIfe1mPro6SL0Z
+ KqRzh55hfMxB6c9hJN0tXYGBYQ6IezN72MMwcIlo4jMYRklnIEqp4JZgq4pWuJUWQRXE
+ iXsdTS/I6yaybPxEgkN6nzcUYWpkrm2MMZRE9YaWS39hD0shaXcYhR4FzraE32NfYi/K
+ q/9usf6Y4gPFD9bvHUw6lebwGerNbcYtjtctR5K+UyoNgj7ljC0mIzZWz1Q4bbReIVSY
+ lE6D3qDX0BAVK3EmpPw+Vmt18yUJFpc7iO/c69i9PILZAKxn/8lBnW9Apzf5vGO8hHED
+ 5eVlAwRRLdRCVZQVsNKcKZROG1+QX1ziKHLonB5Yhk67J1WnLSl22JEJMyudGxra+z/7
+ 7onHXzdJL1Bz3rS11a7olz448KfXXsNV2IJbLKFl9OXNZQ7pX7BG/vG3vQ9dvvpFcG5m
+ /Yk38Uw85+xZ6dN38DdEziN03gUkZ1G6GIsoqoJV0FaeciMLx99I34naC7BaQqAgyHLR
+ ObbhQur9oW/YI0O10hUYi0LPgFwsgrEEiGq0ihl2Z4LZyHoMqRkYwiIZ6ZQnSZFkTzFw
+ phSuxJRwk9aahTzuNEtmVhAnAyOn3sDIo6GjIK2gG0ALlsuU8ulMPiCTzpFfUlwEasFZ
+ HG9KxsY4jk+GUAxoKpPRAfTz4hzslDHEp3B7d+H0tvzZH/xuVG7pvBVzWhTqLGl3DKfG
+ FDVrg3REOk2dZo5Ii80Zv7onxxqqqSrdcNPcExnpmx+f1eXyJbjzksdWbLzvltAheCsi
+ L++zMezXKAcih8+I8xSxEA1PtagssSaHKXWOukszN+WzbFW6Nt2YZk31jDKWWvcbjxvP
+ Gd/OumS4FP+94Yf477NjY5BOlWK2uU0Kd0qMijHnnMk0n0ms8MbRTEWm0mt+1KszTVI8
+ mmbNsxXrbkLFOZbcPJk+u6P0GRiUBWqACJQsSGUDAyBEJh8m9ILVDRCVpngTyFGEWF5M
+ lHghcuQzJkIlZwpnlJU79DHGIZCsIoxXxqTX71tQdZcobtx2ofURbMemL/B4hXRWMb/u
+ l0vvr8n+tfS7lvXSCemC9FdpHzUZ/7kr/2ZzzqrxaZ5kZ+GYOe+9jrkrl+4udXdMneSx
+ Osekjet+7bj0LeYvMGkgaw5Y0yeAkjwqFdWYy+ApRqEEpYeCuLWfcoPeaxWVHOyGhx1E
+ 58Fu6B8MRfQ02RnIPgjcl2/mhFQrHZeq2SPS0NA45iBE4TBwBbGjYXwOLRXhPRm3Hjbs
+ fIzdeqjiaBY+M1E0pVDAlBTCQazrp2Ebwbp9jIX/f7RsVMcS6SsjGpbt9V/TrhQoU+on
+ tCugB3oUbnoIi5JS+lCKweOxSHZrWCVPwRqh0ejwR0wpMwPFQAx5FHpAnDSaKipejjdi
+ 5mwyTv3XhYzPnTEaFqLYBmsmxAKZ1JzUnAxSwSSoUhLis0bZ+AxBlZWvGmXwI3/OqKKM
+ sanWMqs/IVvhL7KMLvsjtgCd6/CLZG8HAkal5bzOd/Kzz6J6J3QSZMRENgIQGZOcz4xK
+ TAyOxaBwjHGyAvIUE+EBWeE53gF5Rz4IC9gEyRiWWg6WVVMKSFVJcYmB+iihJFec5qmc
+ PGr64/TuSSlj2qd1ZSQL0oCydhE27N20iaITE6XjGoEe7Z+++Df/+/GWZ3sovc6oVGtN
+ nqbxFfMf+FqItZaMK8h3lz8w/cHa2tckdeGE0jRNhmOUW8wuev7xN6blGfEZICOsxZXh
+ T5ltsD/okR1Vim6lXRWjVyOLS8+rBLuLVRnXU9aUJJtg03hUFkfKFkfjxKh6GTxP9PGA
+ rIIHynWR5YL0xjjKmeJJ9RiJgMG7FugjSgbenVCDfv5f/3i3tynPJ32BE4sr/EvdK5J9
+ jz0+KvlXdzLTpOPfSlJ/sb1xI3s4NNiQln91cf9DixsevK9+6b3BCL614feZQuA7sTkX
+ itWPxe+Mp3oT8Xhjq75bv0xYrg8a/2w4ZlSYKY5JeptxJVv5+BhBrX1F7YpTJWuLY22o
+ ONmUZLUrik0Wm73XURd9H1kZ6HyhQVkZDBA7DnYWOSU8XQT7u7zcyWsQdQDbCjDYYaeK
+ tKgAlAGmtQpHbteDRYmJBffNnqLETmHKPdL30vffYf0/T2LWLCVQB8bkVT7QsHrZ+A3z
+ p65dfACXfg+7TGnwC7xD5kU5yHQX8EILbzdJzLqoBuvHmERpaWRyaXlOSHIJKiNtNdg4
+ G+1hrDZrscaSbNviqKuOyihhSGjwPCiuH7kC4pmXi9pRvIks+KIY7ExBBOVrbJG5Qq3Y
+ CmtOujRm2+L/JQ1h/O4rq7vGNq26Y+lyZvpNfkrxg7i5sxUXfYNNWLx628sPHJtaePDe
+ zX+AdegNn2NGAT842fp/QRxfo+iN24wfA/sLK1lOy1rr2RrtePs9+O7YXptAx9MmQ7zB
+ VKdoiG8wjbdOj59ummY9hz9gvkj63H7Frp2Aa7Qb2HVaBsy2R8SCSTEzYm6NoWNiEjhX
+ ioM36bMSVPE0lUIXm1amJHeo16gptdVF2WIeSbY4XUCKa9JJhLPdr/OdH/BGyHEyYie0
+ g0WDFrXjRe0I1iLscLD5wc07ojpe5iqQSKdFozE+tSAGH+BX3rzh/VrRoKJC8Vzn6ObW
+ kmQTdqqm3Xv1lHQE2z6Loxf/at6iOy7NWdi5pv6+HZXp+Qm5nbO3YzVsoAnw2R4usOVh
+ sW1i3wLf6a4KL5RolAWrz4YmgUU3AwAUE9SYoKdKPoOgB4uNA+0mgJ9lgtsKORs8pZE9
+ MCXyQJsNPJWHobcF/DELjgEOdMC3qqjCPw8WbtmZwah1Xk78ofKB9sEBIg2ww+dgYLyx
+ wOgEqXAWFRDdU0DlZ6WaF2UeOCCd375t9NgB9i2avkjTRXZ72RtXH6JvfaPmpcqZgEOl
+ VMncAjzXwE6Ri6aJ2r5kUICsK9fL6zm3xpUexOWiPdGeZY7NpWx6m9uTm2Ww5ieuT8hW
+ FmdZ8vKvE9nIJkzW3XnQqqGT5QM+YtHp5K3XdU1ryktOD4wCSy4OVl2Ky3ONYWOIngVb
+ r6hQX1BCHexbt/BRX7J91KOqMd0iNtaukJ57S/ouBherE3IWbC1MSfe2bHh76JuPbv77
+ 5mcff/q++oUzJvTRt1kyb//t0OXTvwzueCY/3vOLym01Nc4K7Ln6L1xPR/jXC3vuLexB
+ 4ES56GYpD9Ua0x3DxJn0SO0y8VpeUBSzVotB69FZzJZDjsbokpSdUKIkgfigI+XdQba2
+ gOzE9ALrgSxL3VhcQI97tig7Tvow2bNg0R3SeZw49plpzC01dWPueji0htrcWtyw+d5Q
+ P3swdGVGPcGJgm+ACO9iTwBHeDRaTGlADXg6mg6fO/eANHG8INsEnAfzYAr0X0NJdoyJ
+ kwiWgOy0EcdFB7stwC7pY9ACMjDw6VhaOgRhCAoppTr8kjyPAY0m51ZeBdYzqAU8FQ14
+ KuhUJMXngkiI5o3nUBBpwa0xeInXgqBzxGvByRh0ZxG8chxwLdWDX5I+xUnSNHOcIiMT
+ J609pClIJXN/P5vC6aOZ3UMTn30CvH24MHzpQ8wC4IEK/UPsF6ka9gz1GcXEKgRlC7uR
+ fUBxv/I19rjiPf5jxTmlSsGZOS/tZdLYbK6ELuUa6DqunW7j5tFzuWXMBmYz/Qj/PP0S
+ s4vbye+DsMTr9BuMtZ6bwE9lNzDrFEfZY4r36PeYD/n3FSpWqWRYllOp4HwGD1n4fihQ
+ dpo+oQd/SgmeJ8NRSoGhOYEX4OSPVYMFD1LZVbkqUcWoLGpNr6PxU7Iur7bL/tVXQHsw
+ h2TDweQjBhEj+5sr2o4iPRgTPl9sr1ZBXEsQGNBUi9rBVcAOJZhEvM6xFpvxLNwprcP3
+ SjuloSXSRfbg1Qt4qzQjNBu/vVJ6ntBqDeCxjZkGX42PVPhRCXARjpHAbzyAG2AuRHXm
+ gVZZDukKSDdC2gfpY5A+BunzAPsBPgdqx0B/B3yBpkHjaCC+kw36hvy6Qe5sMGoSWA8K
+ 0E/eqKbi4CSBEsfCEzrkR3GQSwbrIgl0VjLoKrD6sRPGa4TzDFFT4qgW9NLgtUhCWRlQ
+ xx+xxSPmFCgsuI10dM3Arnht+USyDiMxNMCoMpGUfeBeX45WoKRzcalzlmSbpE/iXHNX
+ ZJhAsI1F3ub1q/xj7aXNrfOZaaU1vuaSeaHJ1L6xaQ0zC8eHllIbO7MmTcpuC/Uw4vYW
+ l1hS0NiRnQ3vT9Z/J+g8Ev2qF7NZbMRuXIJbVd0qDuu1nNIFm0gMI5jYYlMsZbXoYjyx
+ N2qCo2R3jvgawPuBcl9UG/zku3jovnelc6aMJQ8VJ4IuMJTktfbOZabvORlKoTZPzZmy
+ sqIr1A8oTnFXktUFOhnsom1MF3CLROf8YpqJxgr1BvUGLW3SmGPnaGjWZY7jVa4Yldms
+ oIpNVquiWGexWIN4yd7hbTPiEel8UX8IqH8bum1RVA3LloILOcDFAf/HjoyYunTPPatW
+ 9fauonKkL6XP4f4Sx4FJY8FxodNv9O/YsWfPjh39c6QXcMs/vsTTpOe+pESg5SqpmdkK
+ sqkBqZggppsMCiHRSrnsvJUTXAaVJUahMWuKtdYUzpZgM3ssP2l3yrs6cf9hr9BFjBzZ
+ wI5aZ0V6soXLlihRsLKA0Itvvwssza6ypqWrkrBSCr25dqo3W7qAdTmFM9ZR24/8euKy
+ Q/7s4GOUDzyzr8E3e7vCVR06xn79VG36eCBzRAdRQ8x02Hkn7Ec0rt1LxWrA96kVLQZe
+ w6kFO5VLiRRNInVUjMqjhiBdEM/e62icc03Wz0RCdO1E/wLuZyBuRowzMEWIiTyMLPWh
+ ypCQofn9aIf0CdZW5jWuYaZjLJ2jqZ7ydaErTOWhBWnjCE4U8P4DOJPRiTLBglgtTlJq
+ uVSLhlYyDpWqXhivqnVU2evS36UVSSl2tcDEZzLx1qwsPc9kpamysmKNgj0p3p/CG7N5
+ v9uao0ZJ/ths5M+0ZOdcZx0PQuhAtvfl+IvsHEeEJHRSe1IOKNzSfgtux7IZJVv8btlR
+ hmV5g6MsL2RQ/fZU8JNnKZOLHpgyKy1NCu9vaBh4902MDdKnnMW7qH1SRkZ4V8uUf16V
+ wt/CAZXpDXZffn6uxTImp7pqzeb3njlWYh81ypMXbypNm9y08umT7+2kYSGAnRX+O7WM
+ 7YZ1OmGfNivWps7SvYoXIQZPF+N5NJ3DnBlYE8sNMkoPehj4ZA7imL2ODsKeM2XnQ2WD
+ ZYQ/X4GjDJHAgXKwSyBQU0TixsRYivhzRp6DIIDOuAVb9+xJuUmTFNN7fEIuveAEzpVO
+ nQgdHufA+B2W9+fNobYTeQ9fZFpAd5CIeYOYI8Rb4zPiS+On8l08Z4Udg4uP0Qgs+CdW
+ jeCxmlXWRFxstiQk/mhGkHWp9/lDZ2SaE89Eji9jEleWIxNEbMC254l5T1Bz46fiPbc9
+ XAxHgKRLjD1+3Kop30zx4i+ZytCt7d7mJeJcavLQoa1svqEs68WOA9RDSUA7K+i4m+Ds
+ GoeeECd5uCncbO5Z7g9wVobDWqoWmlZQi+mlDFeLN6BedjP7O/YV9hj9Ob6ClbSdYTx6
+ 2CMpO8YeOU5AkTgBR1OCgpKjBOpIlEAtRwkIvS3XB2Mt2tfN18UIoiEC2BCHY6+QJ7vB
+ ImK9y+EBA+3G+dJSCF0vx+KnTOXQIaby6jl4jxjY+xzwHmrkI6dqwRJhwRJRAJBAKw0g
+ gFVCTrgh0CIkynotp47miK2SQGaRI7oGqhc7ntuF06Wj0gcv7JbOSn/B+btgsq9p3dAh
+ 2nr1AuSjcUBCw0YGjuFgWtysAFVM8YyBsQq0h3IxqVyGUMz4hGpmvNDCtAmPMI8JTzIv
+ CS8zr/AHhKPMceFt5gPhM+YKY2JoM8PSHj1FYYY1MzTr0YOdKyjNgkrp0fMKhaAyC0oV
+ kBojzPACgzgWIuAqJWzESh5sFRoLAkNxcD6UxMMVzyOIgKs1z0ckPUr5SGzG7zUf1R6V
+ vx6QoLgcKYQ9mERrIBim7c1UrIJY+Io27WtmLdubuUpxfWm4je3Vmn/sSVzORbi9AEwW
+ oCP8qrAVL5a24fZ9/bhZ2gr53/7xIJVGmaWjuCw0EDqNa6X9wBOjVAv0myF/a3pP7PEI
+ U4U5wiPCDuG0AEYX5rhEXqfJ5u2aMXyepp5v58kOvJRfrtGYYos1vcoNqi2qoIqLi1Mr
+ NJRdrfboVSqB4ymbQuGB7wYkqxGMaqATxyuRjcoy2LSxcXw80ChGo1IHsXovNAiQimrD
+ wwpLlzF+mGaD/vPmq0AfAsNhrXL/+dB5MFjkrwcgThg+HrBgzTUtW/FaQVR4SZ5EFb3X
+ BNiG44tLxmJPRMqoiCW8x5XRYLVkMlIPHvPVJ/CVoG/+6oOpOTl47VsUJeh189XMbVfP
+ 0a6hU9LxRzDNxRHdL19hckrxpy43VNJgE6jBEnOhNLDIMsBKKwL7rATiZlVggdXAOcc6
+ NB4OEdfDiVA/nNZshHOPTagZzlJORTfBCcg2+Ap5MzkVD5JGpI1cHPFnW6vHNba0ZtZ1
+ zV/StXjurM7sylvnzya9rl3w7QHtBCChm2MAZwEuAnwHneBLJDYDpAGUAtQBtAJ0AywD
+ 2ACwBWAnQBDgGMBZgIsA38GLKwDMAGkApQB1AK0A3QDLADYAbAHYCRAEOAZwNhy9AAc0
+ nMdghdxYThtRTh9Rll36656vGNFePaJcM6JcO6LcMKLcNKLcPKI8ZUR56ohy54jyzBHl
+ WSPKwLQb6CHL0nXvJ//PxnXlX4zo3z2iPHdEed6I8i9HlOX/Eblu/IUj2m8dUZb/h+O6
+ /reNaL99RHnxiPIdI8pLRpSXjiiDPN1An+Wk/H8B4eKsgwplbmRzdHJlYW0KZW5kb2Jq
+ CjkwIDAgb2JqCjg2NDAKZW5kb2JqCjkxIDAgb2JqCjw8IC9UeXBlIC9Gb250RGVzY3Jp
+ cHRvciAvQXNjZW50IDc3MCAvQ2FwSGVpZ2h0IDcyMCAvRGVzY2VudCAtMjMwIC9GbGFn
+ cyAzMgovRm9udEJCb3ggWy0xMDE4IC00ODEgMTQzNiAxMTU5XSAvRm9udE5hbWUgL1hF
+ Q1BVWCtIZWx2ZXRpY2EtQm9sZCAvSXRhbGljQW5nbGUKMCAvU3RlbVYgMCAvTWF4V2lk
+ dGggMTUwMCAvWEhlaWdodCA1NDkgL0ZvbnRGaWxlMiA4OSAwIFIgPj4KZW5kb2JqCjky
+ IDAgb2JqClsgMjc4IDAgMCAwIDAgMCAwIDAgMzMzIDMzMyAwIDAgMCAwIDI3OCAwIDAg
+ MCAwIDAgMCAwIDAgMCAwIDAgMCAwIDAgMCAwIDAKMCA3MjIgMCAwIDAgNjY3IDYxMSA3
+ NzggMCAwIDAgMCA2MTEgMCAwIDAgMCAwIDcyMiA2NjcgNjExIDAgNjY3IDAgMCAwIDAg
+ MAowIDAgMCAwIDAgNTU2IDYxMSA1NTYgNjExIDU1NiAzMzMgNjExIDYxMSAyNzggMjc4
+ IDU1NiAwIDg4OSA2MTEgNjExIDYxMSAwCjM4OSA1NTYgMzMzIDYxMSA1NTYgNzc4IDU1
+ NiA1NTYgXQplbmRvYmoKMjcgMCBvYmoKPDwgL1R5cGUgL0ZvbnQgL1N1YnR5cGUgL1Ry
+ dWVUeXBlIC9CYXNlRm9udCAvWEVDUFVYK0hlbHZldGljYS1Cb2xkIC9Gb250RGVzY3Jp
+ cHRvcgo5MSAwIFIgL1dpZHRocyA5MiAwIFIgL0ZpcnN0Q2hhciAzMiAvTGFzdENoYXIg
+ MTIxIC9FbmNvZGluZyAvTWFjUm9tYW5FbmNvZGluZwo+PgplbmRvYmoKOTMgMCBvYmoK
+ KE1hYyBPUyBYIDEwLjYuOCBRdWFydHogUERGQ29udGV4dCkKZW5kb2JqCjk0IDAgb2Jq
+ CihEOjIwMTExMTA3MTgzOTIwWjAwJzAwJykKZW5kb2JqCjEgMCBvYmoKPDwgL1Byb2R1
+ Y2VyIDkzIDAgUiAvQ3JlYXRpb25EYXRlIDk0IDAgUiAvTW9kRGF0ZSA5NCAwIFIgPj4K
+ ZW5kb2JqCnhyZWYKMCA5NQowMDAwMDAwMDAwIDY1NTM1IGYgCjAwMDAwNjI3NjQgMDAw
+ MDAgbiAKMDAwMDA1Mjk3OSAwMDAwMCBuIAowMDAwMDA0MzU1IDAwMDAwIG4gCjAwMDAw
+ NDY3MzQgMDAwMDAgbiAKMDAwMDAwMDAyMiAwMDAwMCBuIAowMDAwMDA0MzM1IDAwMDAw
+ IG4gCjAwMDAwMDQ0NTkgMDAwMDAgbiAKMDAwMDA0NTgwMSAwMDAwMCBuIAowMDAwMDE1
+ MDg0IDAwMDAwIG4gCjAwMDAwMTg1NDUgMDAwMDAgbiAKMDAwMDAxMjQ4MCAwMDAwMCBu
+ IAowMDAwMDEzMzM1IDAwMDAwIG4gCjAwMDAwMDY0MjIgMDAwMDAgbiAKMDAwMDAxMjQ1
+ OSAwMDAwMCBuIAowMDAwMDE5OTk1IDAwMDAwIG4gCjAwMDAwMjE0OTEgMDAwMDAgbiAK
+ MDAwMDAxOTA4OSAwMDAwMCBuIAowMDAwMDE5OTc1IDAwMDAwIG4gCjAwMDAwMTMzNTUg
+ MDAwMDAgbiAKMDAwMDAxNDQ5MyAwMDAwMCBuIAowMDAwMDE0NTEzIDAwMDAwIG4gCjAw
+ MDAwMTUwNjQgMDAwMDAgbiAKMDAwMDAxODU2NiAwMDAwMCBuIAowMDAwMDE5MDY5IDAw
+ MDAwIG4gCjAwMDAwMDUxODkgMDAwMDAgbiAKMDAwMDA0NDkwNCAwMDAwMCBuIAowMDAw
+ MDYyNDkwIDAwMDAwIG4gCjAwMDAwMDUwMzUgMDAwMDAgbiAKMDAwMDAwNDg4MSAwMDAw
+ MCBuIAowMDAwMDA2MTA1IDAwMDAwIG4gCjAwMDAwMDUzNDcgMDAwMDAgbiAKMDAwMDAw
+ NjI2NCAwMDAwMCBuIAowMDAwMDA1OTQ4IDAwMDAwIG4gCjAwMDAwMDU4MDIgMDAwMDAg
+ biAKMDAwMDAwNTUwMSAwMDAwMCBuIAowMDAwMDA1NjQ3IDAwMDAwIG4gCjAwMDAwMzc4
+ NjggMDAwMDAgbiAKMDAwMDAzNzkxNSAwMDAwMCBuIAowMDAwMDQ2Njk3IDAwMDAwIG4g
+ CjAwMDAwNTIzNjAgMDAwMDAgbiAKMDAwMDA1MTcxNSAwMDAwMCBuIAowMDAwMDUxMjky
+ IDAwMDAwIG4gCjAwMDAwNTA2NDcgMDAwMDAgbiAKMDAwMDA0OTg0MCAwMDAwMCBuIAow
+ MDAwMDQ5NDE3IDAwMDAwIG4gCjAwMDAwNDg2MTAgMDAwMDAgbiAKMDAwMDA0Nzk2NSAw
+ MDAwMCBuIAowMDAwMDQ3NTQyIDAwMDAwIG4gCjAwMDAwNDY4OTcgMDAwMDAgbiAKMDAw
+ MDA0NDAzOSAwMDAwMCBuIAowMDAwMDMzMDgyIDAwMDAwIG4gCjAwMDAwMzc4NDcgMDAw
+ MDAgbiAKMDAwMDAyMTUxMiAwMDAwMCBuIAowMDAwMDIyOTA4IDAwMDAwIG4gCjAwMDAw
+ MjcyMzIgMDAwMDAgbiAKMDAwMDAyODkwMCAwMDAwMCBuIAowMDAwMDI4OTIxIDAwMDAw
+ IG4gCjAwMDAwMzAwMzcgMDAwMDAgbiAKMDAwMDAzMDA1NyAwMDAwMCBuIAowMDAwMDMz
+ MDYxIDAwMDAwIG4gCjAwMDAwMjQzODUgMDAwMDAgbiAKMDAwMDAyNTQxOCAwMDAwMCBu
+ IAowMDAwMDIyOTI5IDAwMDAwIG4gCjAwMDAwMjQzNjQgMDAwMDAgbiAKMDAwMDAyNTQz
+ OCAwMDAwMCBuIAowMDAwMDI3MjExIDAwMDAwIG4gCjAwMDAwMzc5NjIgMDAwMDAgbiAK
+ MDAwMDA0NDAxOCAwMDAwMCBuIAowMDAwMDQ0MDc2IDAwMDAwIG4gCjAwMDAwNDQ4ODQg
+ MDAwMDAgbiAKMDAwMDA0NDk0MSAwMDAwMCBuIAowMDAwMDQ1NzgxIDAwMDAwIG4gCjAw
+ MDAwNDU4MzcgMDAwMDAgbiAKMDAwMDA0NjY3NyAwMDAwMCBuIAowMDAwMDQ2ODE3IDAw
+ MDAwIG4gCjAwMDAwNDc1MjIgMDAwMDAgbiAKMDAwMDA0Nzk0NSAwMDAwMCBuIAowMDAw
+ MDQ4NTkwIDAwMDAwIG4gCjAwMDAwNDkzOTcgMDAwMDAgbiAKMDAwMDA0OTgyMCAwMDAw
+ MCBuIAowMDAwMDUwNjI3IDAwMDAwIG4gCjAwMDAwNTEyNzIgMDAwMDAgbiAKMDAwMDA1
+ MTY5NSAwMDAwMCBuIAowMDAwMDUyMzQwIDAwMDAwIG4gCjAwMDAwNTI5NTkgMDAwMDAg
+ biAKMDAwMDA1MzE0MiAwMDAwMCBuIAowMDAwMDUzMDI3IDAwMDAwIG4gCjAwMDAwNTMx
+ MjAgMDAwMDAgbiAKMDAwMDA1MzIzNSAwMDAwMCBuIAowMDAwMDYxOTY2IDAwMDAwIG4g
+ CjAwMDAwNjE5ODcgMDAwMDAgbiAKMDAwMDA2MjIxOCAwMDAwMCBuIAowMDAwMDYyNjcw
+ IDAwMDAwIG4gCjAwMDAwNjI3MjIgMDAwMDAgbiAKdHJhaWxlcgo8PCAvU2l6ZSA5NSAv
+ Um9vdCA3NSAwIFIgL0luZm8gMSAwIFIgL0lEIFsgPGYzYTI5Yjg5OTMxMWUxMmY1NDY5
+ NGJlN2ZlNThmMDgyPgo8ZjNhMjliODk5MzExZTEyZjU0Njk0YmU3ZmU1OGYwODI+IF0g
+ Pj4Kc3RhcnR4cmVmCjYyODM5CiUlRU9GCjEgMCBvYmoKPDwvQXV0aG9yIChSb2JlcnQg
+ THkpL0NyZWF0aW9uRGF0ZSAoRDoyMDExMDkxOTE3MTUwMFopL0NyZWF0b3IgKE9tbmlH
+ cmFmZmxlIFByb2Zlc3Npb25hbCA1LjMuMikvTW9kRGF0ZSAoRDoyMDExMTEwNzE4MzUw
+ MFopL1Byb2R1Y2VyIDkzIDAgUiAvVGl0bGUgKHJzX2dyYXBoaWNzKT4+CmVuZG9iagp4
+ cmVmCjEgMQowMDAwMDY0ODk3IDAwMDAwIG4gCnRyYWlsZXIKPDwvSUQgWzxmM2EyOWI4
+ OTkzMTFlMTJmNTQ2OTRiZTdmZTU4ZjA4Mj4gPGYzYTI5Yjg5OTMxMWUxMmY1NDY5NGJl
+ N2ZlNThmMDgyPl0gL0luZm8gMSAwIFIgL1ByZXYgNjI4MzkgL1Jvb3QgNzUgMCBSIC9T
+ aXplIDk1Pj4Kc3RhcnR4cmVmCjY1MDc1CiUlRU9GCg==
+ </data>
+ <key>QuickLookThumbnail</key>
+ <data>
+ TU0AKgAAGLSAP+BP8AQWDQeEQmFQuGQ2HQ+IRGJROKRWLReMRmNRuOR2MQOCR6RSOSSW
+ TSeUSmVSuLSCWS+YTGZTOaTWYS6bTmdTueT2fSKcT+hUOiUWjSug0elUumU2nSB2VGnV
+ OTP6rAALVmqVuuSBv18AA+xQgA2UAQOMWUA2eBSO1WyQxa32iRXO2xN5XkACC+Vy/U5+
+ 4F/uXCAAIYe4Qy7QS3we6QbFgDGwbHwXIwvI5OC5XJWa0ZrEwfLwrM2aDvDUAAO6u/62
+ lYF+v9zbMAA7bRTP5625Fyb3Vay0O/hAAJcWEO3kZ21vfmAB6c8ACfpYnS2vOW93dnic
+ agbvdQS8vLfh3XeWibDB4XbA6KWvNw60Fv5AAr/UAYRywgG/sAOj/O2CQAHzAYAAvAwA
+ BJBIAGZBizqucBwnDAsDvWABuwu8cBQIAcOAAFsPgAHkRI49yzoUeMUAAD0VvNFqfPQ/
+ Datu67vuU6kan1HIAHnHgAHq6ACAKAoARQeIAAzJAAHPJYAAjJwAOydwAAxKiwrG2ZzA
+ AfEtgAA0vS7L59zEAEcn0AAFzQ50egmCgKAAqx/AACs5xu6y7shGrqgA1B4AAD8/xdQK
+ dRgwr9gahEaRKhLc0VOqGUZR87ss0yFUgxzvUbS7GUpRdJRsha0PDP1AUFUqZvQcdUxk
+ 9lNU+j1LUrTFEVk7tN0yylaVxWyKSKva+1NYCX1RVVDRstB8H2gh+H7RrR0nOy4obZ1j
+ U8zEatFa6HWmyKrIIAgBrWBQD2exNehDc9g3SlT0HFdtVtCgxpnSAkyAUBbNpDW7JMpf
+ brRNRDINFfDLYJRtorvfUSsZfaCWi9+CYCtmILXRoFnwerogqflqPAvVzhDdWQpNdl3W
+ KhZsndeh5gIBmJ35l+HtNO+KPdg980yuOFYjnWYX/mWcs7h+B6DgGIAafJ6OiCmNoXXo
+ RafkWopE9EIwlkyFGsdkhneAWW4kx08MxTuIYhhGcYdolPZzhOx33iOzbagwJH9jAUgq
+ fayLNp2oalvqNapCIAAZwaGGqdgDAAdszojtG3bhh+1oKaxmGGAARBUGU9nadIAH6feN
+ ggCoLvubxsSmDoRgAA97dUA4EoTmub5fyOhVukM3aSFYLaZXQAVEEfgb94SLvQr5v3eh
+ ZonRIZ0H7e9sWhgOf7A0HHleTRC86fczAkDAPAAAQBAGAB1nKbwAAQBb2AgCnRgmDDyB
+ SGggbTg9XaH6ee4CDQBnnDwGGNqQd+8F4cBSJPFLA1chI0R0uIHMPtlqiVHKQM4WRl5c
+ 1LscAAOwcw4EmgWA4AAAYBF6J6gqwJmJnoMgdAK0kFoGG8ELVEgkEkBobEPPQN6HQAIF
+ EIGeOhcY4B7PPdi7A+DEWyuyaEzBSjQGvwoUfEhx0Sl/tgUmQUEQCH/AvAzDEhSPH/Q0
+ hvGMhcOYdrFUgM0criBuxDiQ0Bn8TkTMURNHJhxdorQWdq/WOy/Y6xvbynZsAJQFtJBi
+ BqLxCVRAlkZGSRxBz0IXG7Dw/hCxnjiXoOofSQyygCX441Zsf2BL+YWot6Ufx/D8Y3CN
+ IZ75QQWYbBaUjbmix+liBgAw+QAAuA4xsyJz2kyMBKSMtA9ZjOdMDI8n6cH0AIARMg2M
+ knBOEIutN6EE1qkWSigCDS1nozWI8ZGMAAATTlI4Wg/w6AASqY2kKVsyieFonGegbk9Z
+ KKHVattPK2VyKwXwrufJZptpOAjBqfU31OKOoC9Ga5aJgTknMRstE2y0TuPbPtgysoTq
+ CT1QsxJvRyTQH/PUbiZ00vVVySSf1CnenCHfNxWr96WT/pkQucZ0gTkcmZRQttFiJq9G
+ 3UEAANKiEMm2cVAJF6HmwABUEbdQ6ilvHtVNH0x05gVUcnyky94SL0LrRgADVaRUkmnB
+ GbJPFpzGYwVEdiowPkxnARWcYKK6U6KuchxUzKLUdIMMivwABdWBRUiypiA5dEHrY5Zq
+ FIJuIVXaOIwxiAWWTAALuywAAf2ZAAM6zhCGPgAGnaFCbo6XAAB9acAAG7VAAFNa1MDi
+ DDgQMSFa2i76NkMVSOOsc9gFW9g0PdMybx/0IoYni4i8HYVgLQNobI10tJcBcC8GM3bj
+ TYcbP2jRbWFgDAEuEAycZfnQroCiuyca8TQABT4iU461JkR0l5xEzFRPhk9VdJSTKupy
+ ToMW/gAAa3/mbM9LY+L3JmTE3iZ0z6mFowSns1KVAMAAG1hN1q41emrPJfAAAGsOUzus
+ ACxh6MJjaq3BprLrwAmIlGwC65imGRVI7HRsGLWxSzIvC1PoJAID3g1e28d5XEnJnZel
+ IWH6G0pNxdmO9YKPQSpXBSs5HEsUiGzlXEpkRwDzAUAAfYDqC4wNJEYgo/jdtuZqVeTq
+ xl/yvcgrRTLPI9y0bNjZtABB5pSBCA3Hl4Wkgqz9kC8+B8iTvcZkotOTHe0Hw9lDJdxy
+ L6MvuOekQ2NKVluQAAb4817j5AZl8h7aEc4ED+GQJ4AAnBdDXekAy4xtDTGXOQFwNEfF
+ 6HsPQ8Rb33gaSUOF877ALAAHUOWyAFQNPfAOAh147h1aSBkD0IgABxjcdM+lloLQag9g
+ uzVnbMADj0zwA0e2PZj5+BVoA5NhgAX5MiNcdczwCAHkFnLMOcWyEScetV/NCWv75hQ4
+ +DLREdJTAPgQCirFIJL0kejSjpk0PPIUN0eS9x7gJtk3l/GMp1yqAANwaYzDJPiQ1jxz
+ yZh9D5wIBECuEYSJDHIN4bJtQJJuH/mQ4nKcuPbTIPjHgAoSZc51hsEIJsQOlw2B+YYF
+ AMwhIaSGUC4R6uKBEA/HhC6Hgr6tuZxW6L8kLGYPC2QBQD6EbJHKQG9YmP67PEuPOcGw
+ 77bPFeJ7Ah+80A4P5KQFgGpxIXOmkQ1+/YlIWNsd7LR5AItlv5XHcHHjQGGLpxI69JAf
+ BJuUbo1Rmp+BOC8AACQFstHIN25wJwYA52BB3dPYDnDxcUAXVfH3x6rmf6yZ4FwOsgXs
+ ezskRWiNFAcPpKQJQIbh6odCyYLOsXPwJflSAyR29fAS4hWfisaVf4upXsseoqr60LcI
+ tYHh/DrTl3khg6fyd97/b3LZCxtDvUOPAA3FfE8WziWhyYwvU0vfLB4EgLdZQcsgAI9a
+ HqHmT6Ak2IcSHQt0AQAUZaAiAwhCH25+HYHOsgAYAeQC2iGqAACiDKDy9O7E38icUgAi
+ H2cUBMAi6md6oeQ+Ba+Oqm3CvyqY74G8AG3KAKAUmeIOHAGwGiAAA4BG3KSC7EH6405M
+ 3CH45wy8TcIPAESMfMdMBMBeBuziHmHecUAaAgAmIoHkHgraAcfYS0HuYwIETjAUUONM
+ HoHiT6fUtkNM7mIKBKAG/A7w70IUHVDspEGrDy0sIWGuHaXuZS08xqdij6hMU8jw7Qxc
+ jikBEK0a7iIIaWSkBOAm3CUhBURAjKmS4WeQIMmYtKvavym2TKAAHEANBYAiAyPIH05+
+ GAFeE8S6dcfRAWxA8qRUBMBcAAGwGccqdQ+MAsA8BE42GkGSAABUBoB+s2GEFqRsAyBA
+ vJCo/A7AdfGeTkA0re2UPyfUoLDKg3Amw2BApzAAXHAqoLCorbC4nU7AXGB8CcC+Rs7m
+ IIBYARDk/EIXDsHVDxD04aIZD6ZaHWAGoKjoBYHQFoOiAW+E3+fyWw+qK4GqHuQCGwAs
+ 2eLQAsH+SkBQAkYwIWvbBWIYvaVESQAyIQmYvOnG62IMVEGUHoZAAG9aIOHCGyGgTOAb
+ IAfCABB0Gc8wumH9CGhE9YnW5LJ+5OhA5y3C1qT7Jm1+HoHe/A3emfFU3DKQd8HanUfE
+ XoAcAk1+45GGA+8yj8HsHqSMSEmeKsY2HsHkSMBCBWBmMSYWBaAQc47wH6IYsSPQGpLs
+ 8AawHaUOc5ECAAB0HcFmnIAGnUFQF848CKBq3KASW+ILJqG4HK/ABGA0qwIOzITiALMY
+ X+HQHcSMAkAdH6Hgf8G6HNHuAmAeZaBuBQZAHoHuwIAKQ6HwH0bwLeHMHaT6AwAk/gII
+ HSHef8BOA8wiGeHy10GaAmCOYeAyACcVIvIyIVBcQ9EuIUwGwdNuSrMqruOSVFJMISFw
+ HGqwH+AG7E3k7M7caGmq7SKQ+uigNiIKBsAbHuAsAcd4ITLoMFLsGoxKUgGoHWZa0kqS
+ JCB4HOFMQQH4qeDkE+FynIAzCyHkHul0AkAYdeGAGog8Aa+eAAB2BSe+GUG0PyBiBEwi
+ H4KuAgXEAAFsGcpKCQBihqG+HUT6RKCoB0BWAAGKGwsgMCTiHMHcf8BCAuoKHBRcAAAm
+ Aay2G/N4AABuBMhCCyB9BYGaACBSAAGUAsCgYCA6AGcUBSAnOapoOYx5I4IXOmq0whJF
+ OwcUq1O2IQFiG8dGH+560fPU+u+0zgdtTiJQeiBsAec4A2AhPmIQm3LrLu/QIYGmHWUO
+ HIH7IALMB6HCE0l2H4ucpiNBNiY2HgHsl0AwAgXupWJUGWAI80GSA8DAloA6AIraBUAm
+ aSMjS8l2BdFvTCS5THOtE5TMAAtLTSIOGiHM9iAK+0J0503C2Q/SKGKuNUaOLCAVDoIT
+ UAMEtCGmABUGIWGkHUUOHEH4qSIMAUHkg9PAXoIIk9PIzBXCj6aDAgwIKsbwdca9IUif
+ TqzElqZ0HwAYA2YeBCAMraBWAoaSIXOeBfX8IZTEwfVmzHVqvPVwK2HXYSv0qwr4pori
+ JitKPRWdWgt8VaGwHWy2HYH2deYLEQbE7UIijoli50aTCObwAYy9PGIg7YIlZEzAAmAG
+ bqAuz2RrVZX881VgwJVkwjOuvMOSsTYOWk0RPQbQljZc+mILHsKwK0J1Yaw+q1YktEwa
+ pQoAVjaq0LEapWnGyGoIVnauIgycyRU4d7VYBhbNYBVjYFZ5VpZ8cVYTKY560gKUEnbo
+ AAClbvB6A4hDbHawuoIqT0V6PQGlcG82ATY4JbbEyQJEoe0Fa6yfcUJeUhOeBjcpbRZ1
+ bVTLbaAA/Ic43URqHyH4aSLjbkJmGkGjWeBOBQ6EAPdYJ+H2H6wIAYAOQCu6fGpsR6PQ
+ Gjd1cKxQn4I5OeQ5dsuqIu3QqZWi0S30IU0Evpd4MVd8InOeBlelctOoSnYGTeKusS75
+ aCfIAMFCdUYsI1ToI1XI/jIS7a8RIW3wPdJ3W+HYCaNqANXoz4pEGhfteaIeMyiYRrOe
+ tVXpe5bDa+o80+u0LasZcNcPb+TyZhVZekczZzerTJZ6g2Kle3biVkHaASE/WgAZT83v
+ aQ0/Tjac+zERfGI+6YLaH6HKCWh4AO11I0mOPRftJjgRbBcTa/OfZ3eqqRJsHAg874RW
+ e/iCwLFw0qLQBTiRT+O0TaTch0fOosnK6EsTH00fhuABVYBnizeph1gmsS4QhEQ6MiHa
+ ARg2ddT83ybOV2hPhNXhY9ZbPQ7W7QLNfaMkHXfgAaANJCMjOePQGfj9fwIlbeteIhFE
+ GNkMvQp4IImZH0tKs+s5JweAdSq0IOwxc2/LdYXHOfbMBgRCRGVFePgUuKITixi1ghi5
+ bZgoraRjeCIYHWAKFAAAGeGUqe2UYwA8BGQC50bwAuAyUOG23YNUBCtlK+bwAgAkdfC3
+ XO5oHwHsY2lVLkBOBaqwGWGEpCA66icEAaXHCrKgAgmeG4ayw2A8PYASAUSHCOTidcXo
+ GoGanU2KPYAaAcmeHgHa3DPCk8AwA2PYSEvrl6fAHcCYLCAPXpckqoPRkfYoy2tusSwY
+ mdb8Q0l0LEAefBJq0UOuzNYITjeYLRi+QMdG0Fi+T+rfFFlBoem8UdOeqI1llNcxi6Kl
+ lWQ672AHFcGuGig9m4g2HSYw5SZafCLWHYHUYwAgAideAUAaSGHkHewJnKcQAXjwwkGq
+ /AAiAmdeBoB0hCGCFyfO2QSGA4BAPYGQGCsgBeBq102WaS2QXoA5mEtAGY0kBqB4PIG6
+ GycUW+k9mSR8HmTMAznGnWH2TjFQUOBUBhJCAIHfoDjw11VWOboOs7amrBkEWKARdaaC
+ Ugq0LReYIncfgFcRkUKvh4ya0MigaDOev+Bri3pblQsSHGXdlYjkHOAHg21WuDTg7GIb
+ K+TMXs+gigic1rtyAW+hZZttPI2U3DAsmeQ5XAhRWKAOHjjvhcIZeKMEGbupkAIasSWL
+ kwngJLVZtNtROrbXozlTFHtaQ6UgHIH8E41VtorRaGyMJSLfHeTOHs1KAdoGUdukNiQY
+ 49hqIfuwP5u0yPhAJpYfV+S5u9pZvBczvGeNjAfGMjWsE7vW+w7JaIolTtZUzfjheRlE
+ ivDG82HuCUSaAQZAMi0EPQGXxToS0uHgHuXoHaHY/ANtonwDw4w/otENvdtDjVtEurjW
+ c6LaAmAXLkIXVYBtyPu/etvDewTisTidwcIYHmHzHuW+XG4xu3fyIKAMAEy2u5PEINxO
+ MFxS1fv6d6HKH0TcHmJDAqtldYdeli5moBuEZljiUQIA/n+AACAgCAABA4RB4JDYHCoV
+ CIlDITEotFYJDIjFItG4Q/HU5gAGwQ74S/4jCHzKwANpdF4s+JkAHhNQAGJxF39OwA65
+ 8AG9QQAA6JMKNR6REpRAwDTZPKaTUalU4nTqXGY5VKVKKxT61H34/AA/bI/2XZwACLVX
+ qbB3O+wmAHe/4ODAaEAABgOBwA1WYxQAtFKmQAPCSUgA9no8wAEAoFwA4m01QABwSCgA
+ FQyHQA9Xk8QACgYDKGBQNcnU6AADQeEQABbW5m+3AAFw6IAA83g7tKBQBBgEABkPSKAG
+ It1aAAcEbiAgGBAA9HjJquRyqX4xCK5Fn87JEGgNJqPMnwABv56R5JpNpwGIvV586wA2
+ /pvwFwavba9X4t+vypz3oVADtv6jUBKy/itP+g6rwLBiuP0jsIKtCaDrIfp/mVDS0rXB
+ wAHKfS4ncfqDgWBy8L0vh1nMcgAHidx1LGsKhgI3x8MUAB8HuerKssAAHgmCoAHSchwA
+ AAgCNOCgNM4bZpmYzMmR+CMhHcdZzgACgMA2AB5HcdsjtMABwGwaQAB0JDEF+WBSJGEQ
+ TsaCQLAAfR8nuACdn8AAVBmHSFwQioAu8AANAO3jxpmHFFPSmaangm6cqOfVJgAclLKG
+ osE01TdOU7T1Pou/QE1Gsayw0ZUOAQ/aJRACien2usTryBAErYjiKIgib+qVXTtJOhdd
+ 1+hqq1tYKMI9Xrs1xYVboQAZ3HKkdDK6mNE0XRDy0dSD3K/BtQW/cFw3FTb9QvDMNr2v
+ ijnIfNXHSfSDgUu7Qn40CEz07cBwPXllWDfNAWRf6YYFZll37ZJ+z04J+gAfYIA9XzXn
+ jaIOAPMD/K5SZ9ABRQcUZbL2UjceR5JkuTU1cxk5VHt1KMcZ8VcdB9ODeS8BodZcgAE4
+ FHopEFphg1hvfZKIQrBWCqPoKsmqfUhGqC7iv0BB5RaDoEUOoyVnyAAc67j710e9uT7H
+ smy5PcxkbTVNVoQcB7yEc59L4cJsGeAAuAydIABeBjGYGAA2EoVYABAC4JUICYHNWBNV
+ GOa8jBqE2IH2sk8IFxAHgAdR4Z7BgAHcek7ggBdahMDk5nYeUeGOaxvgAEIMLiA4CgGr
+ oGcYAAjhoFFkoQZ59g4ABhgMGyugWeyRA+BVH5+9SXeKo55elH4H8yCnr7N7Pte3lCy7
+ SZGWQCgZvntOZ4gQDIAHadBwgAJR9GCAAWgJFqjmycp2AAbhzt50dVAMAQb4aw438gjA
+ wa4AhBixkKHsPhjZEXbmnGONgcYAAggtBCXkAjtR5j2a2N4dRJoHFiBc4UAA7B4j2AAB
+ kCYDU9gcSERki4zwAu8GaBoxBGAID4WiCABT+WMEDY0mcHSfnuRHiRElTq5hjRNbWhIg
+ Y3h6pzHeAcDR2QbDeE0AAFg9xnKeaUUZZB2VyL8aER1okMwEg3AANAEQYSKkDAoPpaII
+ QFpgKO1oAAO4+RKj9H+QBRomROXSUgbg805jtissIAg+VHueLo7VZZTCHNDYxGiIKoUK
+ FHI9JMhrnpMSbX4c4AA/ACALIuBYfa0QRAMiAhQgcegeSzkDLWW0SFzDFl0+Eo42h6GQ
+ HWAN9KwCHyfjM0mOMxlfRjKTGGYpB2gzIme0KYqwCpEHlVBUEoDn8qSUpLMHkt5xTjbG
+ uYYk54nlGHOPNWo+B/qqIK0VP7A19oBnmsJApSWCISnvPyGU9p/oEWIz4gYCgBMbAsAt
+ O7P49A9odOSiFEVwTmnRIWKBXWfycaNRdCKmmf0ZjFRsrZTEAUeaNSAmEegfUrolS2ly
+ CVzDDplLwo0mWx02KjThk1OikU8m8xulYPqX1DqJQQlAv6kJHSQrZB5UJrywk1U2jFAq
+ p0kqkV+nkmas1Qp8VEq4P6wVFrFWMpY/x2VnqjWOtRXwDVtNWA2F1a65URrLXOu1d68V
+ 5O0t6vVfa/V/nFXWwFg7CWFe1YKw1ibFWLU/Yixlj7IWRpDVSyVlbLWGsdZezVm69EBA
+ AA4BAAADAAAAAQBeAAABAQADAAAAAQBMAAABAgADAAAABAAAGWIBAwADAAAAAQAFAAAB
+ BgADAAAAAQACAAABEQAEAAAAAQAAAAgBEgADAAAAAQABAAABFQADAAAAAQAEAAABFgAD
+ AAAAAQBMAAABFwAEAAAAAQAAGKwBHAADAAAAAQABAAABPQADAAAAAQACAAABUgADAAAA
+ AQABAAABUwADAAAABAAAGWoAAAAAAAgACAAIAAgAAQABAAEAAQ==
+ </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>{{516, 97}, {969, 926}}</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>{{-129, -19}, {834, 772}}</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/rs_graphics.png b/docs/html/images/rs_graphics.png
new file mode 100644
index 0000000..fde58d2
--- /dev/null
+++ b/docs/html/images/rs_graphics.png
Binary files differ
diff --git a/docs/html/images/rs_overview.graffle b/docs/html/images/rs_overview.graffle
new file mode 100644
index 0000000..5613744
--- /dev/null
+++ b/docs/html/images/rs_overview.graffle
@@ -0,0 +1,3012 @@
+<?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.28.0.154505</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-09-07 14:32:49 -0700</string>
+ <key>Creator</key>
+ <string>Robert Ly</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>Class</key>
+ <string>LineGraphic</string>
+ <key>FontInfo</key>
+ <dict>
+ <key>Font</key>
+ <string>DroidSans</string>
+ <key>Size</key>
+ <real>11</real>
+ </dict>
+ <key>Head</key>
+ <dict>
+ <key>ID</key>
+ <integer>214</integer>
+ <key>Info</key>
+ <integer>3</integer>
+ </dict>
+ <key>ID</key>
+ <integer>227</integer>
+ <key>OrthogonalBarAutomatic</key>
+ <false/>
+ <key>OrthogonalBarPoint</key>
+ <string>{0, 0}</string>
+ <key>OrthogonalBarPosition</key>
+ <real>6.25</real>
+ <key>Points</key>
+ <array>
+ <string>{367.375, 325.998}</string>
+ <string>{332.375, 325.998}</string>
+ </array>
+ <key>Style</key>
+ <dict>
+ <key>stroke</key>
+ <dict>
+ <key>Color</key>
+ <dict>
+ <key>a</key>
+ <string>0.7</string>
+ <key>b</key>
+ <string>0</string>
+ <key>g</key>
+ <string>0</string>
+ <key>r</key>
+ <string>0</string>
+ </dict>
+ <key>CornerRadius</key>
+ <real>4</real>
+ <key>HeadArrow</key>
+ <string>0</string>
+ <key>LineType</key>
+ <integer>2</integer>
+ <key>TailArrow</key>
+ <string>0</string>
+ </dict>
+ </dict>
+ <key>Tail</key>
+ <dict>
+ <key>ID</key>
+ <integer>200</integer>
+ </dict>
+ </dict>
+ <dict>
+ <key>Class</key>
+ <string>LineGraphic</string>
+ <key>FontInfo</key>
+ <dict>
+ <key>Font</key>
+ <string>DroidSans</string>
+ <key>Size</key>
+ <real>11</real>
+ </dict>
+ <key>Head</key>
+ <dict>
+ <key>ID</key>
+ <integer>4</integer>
+ </dict>
+ <key>ID</key>
+ <integer>226</integer>
+ <key>OrthogonalBarAutomatic</key>
+ <false/>
+ <key>OrthogonalBarPoint</key>
+ <string>{0, 0}</string>
+ <key>OrthogonalBarPosition</key>
+ <real>4.1290435791015625</real>
+ <key>Points</key>
+ <array>
+ <string>{138.375, 427.17}</string>
+ <string>{138.375, 454.17}</string>
+ </array>
+ <key>Style</key>
+ <dict>
+ <key>stroke</key>
+ <dict>
+ <key>Color</key>
+ <dict>
+ <key>a</key>
+ <string>0.7</string>
+ <key>b</key>
+ <string>0</string>
+ <key>g</key>
+ <string>0</string>
+ <key>r</key>
+ <string>0</string>
+ </dict>
+ <key>CornerRadius</key>
+ <real>4</real>
+ <key>HeadArrow</key>
+ <string>FilledArrow</string>
+ <key>LineType</key>
+ <integer>2</integer>
+ <key>TailArrow</key>
+ <string>0</string>
+ </dict>
+ </dict>
+ <key>Tail</key>
+ <dict>
+ <key>ID</key>
+ <integer>157</integer>
+ <key>Info</key>
+ <integer>5</integer>
+ </dict>
+ </dict>
+ <dict>
+ <key>Bounds</key>
+ <string>{{43.375, 454.17}, {190, 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>4</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.274119</string>
+ <key>g</key>
+ <string>0.950739</string>
+ <key>r</key>
+ <string>0.787494</string>
+ </dict>
+ <key>FillType</key>
+ <integer>2</integer>
+ <key>GradientAngle</key>
+ <real>90</real>
+ <key>GradientColor</key>
+ <dict>
+ <key>b</key>
+ <string>0.223529</string>
+ <key>g</key>
+ <string>0.776471</string>
+ <key>r</key>
+ <string>0.643137</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.165602</string>
+ <key>g</key>
+ <string>0.586124</string>
+ <key>r</key>
+ <string>0.428309</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 Renderscript Graphics and Compute Engine}</string>
+ <key>VerticalPad</key>
+ <integer>0</integer>
+ </dict>
+ </dict>
+ <dict>
+ <key>Bounds</key>
+ <string>{{303.368, 423.5}, {70, 24}}</string>
+ <key>Class</key>
+ <string>ShapedGraphic</string>
+ <key>FitText</key>
+ <string>YES</string>
+ <key>Flow</key>
+ <string>Resize</string>
+ <key>FontInfo</key>
+ <dict>
+ <key>Color</key>
+ <dict>
+ <key>a</key>
+ <string>0.65</string>
+ <key>w</key>
+ <string>0</string>
+ </dict>
+ <key>Font</key>
+ <string>DroidSans</string>
+ <key>Size</key>
+ <real>10</real>
+ </dict>
+ <key>ID</key>
+ <integer>224</integer>
+ <key>Line</key>
+ <dict>
+ <key>ID</key>
+ <integer>223</integer>
+ <key>Position</key>
+ <real>0.61347693204879761</real>
+ <key>RotationType</key>
+ <integer>0</integer>
+ </dict>
+ <key>Magnets</key>
+ <array>
+ <string>{0, 1}</string>
+ <string>{0, -1}</string>
+ <string>{1, 0}</string>
+ <string>{-1, 0}</string>
+ </array>
+ <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>
+ </dict>
+ </dict>
+ <key>Text</key>
+ <dict>
+ <key>RTFD</key>
+ <data>
+ BAtzdHJlYW10eXBlZIHoA4QBQISEhBJOU0F0dHJpYnV0
+ ZWRTdHJpbmcAhIQITlNPYmplY3QAhZKEhIQITlNTdHJp
+ bmcBlIQBKwpSZWFkL1dyaXRlhoQCaUkBCpKEhIQMTlNE
+ aWN0aW9uYXJ5AJSEAWkDkoSWlgdOU0NvbG9yhpKEhIQH
+ TlNDb2xvcgCUhAFjA4QCZmYAg2ZmJj+GkoSWlgZOU0Zv
+ bnSGkoSEhAZOU0ZvbnQelJkchAVbMjhjXQYAAAAUAAAA
+ //5IAGUAbAB2AGUAdABpAGMAYQCEAWYMmwCbAZsAmwCG
+ koSWlhBOU1BhcmFncmFwaFN0eWxlhpKEhIQQTlNQYXJh
+ Z3JhcGhTdHlsZQCUhARDQ0BTAgCEhIQHTlNBcnJheQCU
+ mQyShISECU5TVGV4dFRhYgCUhAJDZgAchpKEpaQAOIaS
+ hKWkAFSGkoSlpABwhpKEpaQAgYwAhpKEpaQAgagAhpKE
+ paQAgcQAhpKEpaQAgeAAhpKEpaQAgfwAhpKEpaQAgRgB
+ hpKEpaQAgTQBhpKEpaQAgVABhoYAhoaG
+ </data>
+ <key>Text</key>
+ <string>{\rtf1\ansi\ansicpg1252\cocoartf1038\cocoasubrtf360
+{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
+{\colortbl;\red255\green255\blue255;\red0\green0\blue0;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc\pardirnatural
+
+\f0\fs24 \cf2 Read/Write}</string>
+ <key>alpha</key>
+ <array>
+ <array>
+ <integer>0</integer>
+ <integer>10</integer>
+ <real>0.64999997615814209</real>
+ </array>
+ </array>
+ </dict>
+ <key>Wrap</key>
+ <string>NO</string>
+ </dict>
+ <dict>
+ <key>Class</key>
+ <string>LineGraphic</string>
+ <key>FontInfo</key>
+ <dict>
+ <key>Font</key>
+ <string>DroidSans</string>
+ <key>Size</key>
+ <real>11</real>
+ </dict>
+ <key>Head</key>
+ <dict>
+ <key>ID</key>
+ <integer>225</integer>
+ <key>Info</key>
+ <integer>7</integer>
+ </dict>
+ <key>ID</key>
+ <integer>223</integer>
+ <key>OrthogonalBarAutomatic</key>
+ <false/>
+ <key>OrthogonalBarPoint</key>
+ <string>{0, 0}</string>
+ <key>OrthogonalBarPosition</key>
+ <real>31</real>
+ <key>Points</key>
+ <array>
+ <string>{413.275, 381.998}</string>
+ <string>{258.125, 435.5}</string>
+ </array>
+ <key>Style</key>
+ <dict>
+ <key>stroke</key>
+ <dict>
+ <key>Color</key>
+ <dict>
+ <key>a</key>
+ <string>0.7</string>
+ <key>b</key>
+ <string>0</string>
+ <key>g</key>
+ <string>0</string>
+ <key>r</key>
+ <string>0</string>
+ </dict>
+ <key>CornerRadius</key>
+ <real>4</real>
+ <key>HeadArrow</key>
+ <string>FilledArrow</string>
+ <key>LineType</key>
+ <integer>2</integer>
+ <key>TailArrow</key>
+ <string>FilledArrow</string>
+ </dict>
+ </dict>
+ <key>Tail</key>
+ <dict>
+ <key>ID</key>
+ <integer>200</integer>
+ <key>Info</key>
+ <integer>16</integer>
+ </dict>
+ </dict>
+ <dict>
+ <key>Bounds</key>
+ <string>{{306.62, 201.5}, {70, 24}}</string>
+ <key>Class</key>
+ <string>ShapedGraphic</string>
+ <key>FitText</key>
+ <string>YES</string>
+ <key>Flow</key>
+ <string>Resize</string>
+ <key>FontInfo</key>
+ <dict>
+ <key>Color</key>
+ <dict>
+ <key>a</key>
+ <string>0.65</string>
+ <key>w</key>
+ <string>0</string>
+ </dict>
+ <key>Font</key>
+ <string>DroidSans</string>
+ <key>Size</key>
+ <real>10</real>
+ </dict>
+ <key>ID</key>
+ <integer>222</integer>
+ <key>Line</key>
+ <dict>
+ <key>ID</key>
+ <integer>221</integer>
+ <key>Position</key>
+ <real>0.60332739353179932</real>
+ <key>RotationType</key>
+ <integer>0</integer>
+ </dict>
+ <key>Magnets</key>
+ <array>
+ <string>{0, 1}</string>
+ <string>{0, -1}</string>
+ <string>{1, 0}</string>
+ <string>{-1, 0}</string>
+ </array>
+ <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>
+ </dict>
+ </dict>
+ <key>Text</key>
+ <dict>
+ <key>RTFD</key>
+ <data>
+ BAtzdHJlYW10eXBlZIHoA4QBQISEhBJOU0F0dHJpYnV0
+ ZWRTdHJpbmcAhIQITlNPYmplY3QAhZKEhIQITlNTdHJp
+ bmcBlIQBKwpSZWFkL1dyaXRlhoQCaUkBCpKEhIQMTlNE
+ aWN0aW9uYXJ5AJSEAWkDkoSWlgdOU0NvbG9yhpKEhIQH
+ TlNDb2xvcgCUhAFjA4QCZmYAg2ZmJj+GkoSWlgZOU0Zv
+ bnSGkoSEhAZOU0ZvbnQelJkchAVbMjhjXQYAAAAUAAAA
+ //5IAGUAbAB2AGUAdABpAGMAYQCEAWYMmwCbAZsAmwCG
+ koSWlhBOU1BhcmFncmFwaFN0eWxlhpKEhIQQTlNQYXJh
+ Z3JhcGhTdHlsZQCUhARDQ0BTAgCEhIQHTlNBcnJheQCU
+ mQyShISECU5TVGV4dFRhYgCUhAJDZgAchpKEpaQAOIaS
+ hKWkAFSGkoSlpABwhpKEpaQAgYwAhpKEpaQAgagAhpKE
+ paQAgcQAhpKEpaQAgeAAhpKEpaQAgfwAhpKEpaQAgRgB
+ hpKEpaQAgTQBhpKEpaQAgVABhoYAhoaG
+ </data>
+ <key>Text</key>
+ <string>{\rtf1\ansi\ansicpg1252\cocoartf1038\cocoasubrtf360
+{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
+{\colortbl;\red255\green255\blue255;\red0\green0\blue0;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc\pardirnatural
+
+\f0\fs24 \cf2 Read/Write}</string>
+ <key>alpha</key>
+ <array>
+ <array>
+ <integer>0</integer>
+ <integer>10</integer>
+ <real>0.64999997615814209</real>
+ </array>
+ </array>
+ </dict>
+ <key>Wrap</key>
+ <string>NO</string>
+ </dict>
+ <dict>
+ <key>Class</key>
+ <string>LineGraphic</string>
+ <key>FontInfo</key>
+ <dict>
+ <key>Font</key>
+ <string>DroidSans</string>
+ <key>Size</key>
+ <real>11</real>
+ </dict>
+ <key>Head</key>
+ <dict>
+ <key>ID</key>
+ <integer>155</integer>
+ <key>Info</key>
+ <integer>7</integer>
+ </dict>
+ <key>ID</key>
+ <integer>221</integer>
+ <key>OrthogonalBarAutomatic</key>
+ <false/>
+ <key>OrthogonalBarPoint</key>
+ <string>{0, 0}</string>
+ <key>OrthogonalBarPosition</key>
+ <real>4.1290435791015625</real>
+ <key>Points</key>
+ <array>
+ <string>{410.256, 272.907}</string>
+ <string>{258.125, 213.5}</string>
+ </array>
+ <key>Style</key>
+ <dict>
+ <key>stroke</key>
+ <dict>
+ <key>Color</key>
+ <dict>
+ <key>a</key>
+ <string>0.7</string>
+ <key>b</key>
+ <string>0</string>
+ <key>g</key>
+ <string>0</string>
+ <key>r</key>
+ <string>0</string>
+ </dict>
+ <key>CornerRadius</key>
+ <real>4</real>
+ <key>HeadArrow</key>
+ <string>FilledArrow</string>
+ <key>LineType</key>
+ <integer>2</integer>
+ <key>TailArrow</key>
+ <string>FilledArrow</string>
+ </dict>
+ </dict>
+ <key>Tail</key>
+ <dict>
+ <key>ID</key>
+ <integer>200</integer>
+ <key>Info</key>
+ <integer>13</integer>
+ </dict>
+ </dict>
+ <dict>
+ <key>Bounds</key>
+ <string>{{278.375, 306.998}, {54, 38}}</string>
+ <key>Class</key>
+ <string>ShapedGraphic</string>
+ <key>FitText</key>
+ <string>YES</string>
+ <key>Flow</key>
+ <string>Resize</string>
+ <key>FontInfo</key>
+ <dict>
+ <key>Color</key>
+ <dict>
+ <key>a</key>
+ <string>0.65</string>
+ <key>w</key>
+ <string>0</string>
+ </dict>
+ <key>Font</key>
+ <string>DroidSans</string>
+ <key>Size</key>
+ <real>10</real>
+ </dict>
+ <key>ID</key>
+ <integer>214</integer>
+ <key>Line</key>
+ <dict>
+ <key>ID</key>
+ <integer>213</integer>
+ <key>Position</key>
+ <real>0.48846337199211121</real>
+ <key>RotationType</key>
+ <integer>0</integer>
+ </dict>
+ <key>Magnets</key>
+ <array>
+ <string>{0, 1}</string>
+ <string>{0, -1}</string>
+ <string>{1, 0}</string>
+ <string>{-1, 0}</string>
+ </array>
+ <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>
+ </dict>
+ </dict>
+ <key>Text</key>
+ <dict>
+ <key>RTFD</key>
+ <data>
+ BAtzdHJlYW10eXBlZIHoA4QBQISEhBJOU0F0dHJpYnV0
+ ZWRTdHJpbmcAhIQITlNPYmplY3QAhZKEhIQITlNTdHJp
+ bmcBlIQBKw5NZW1vcnkKQmluZGluZ4aEAmlJAQ6ShISE
+ DE5TRGljdGlvbmFyeQCUhAFpA5KElpYHTlNDb2xvcoaS
+ hISEB05TQ29sb3IAlIQBYwOEAmZmAINmZiY/hpKElpYG
+ TlNGb250hpKEhIQGTlNGb250HpSZHIQFWzI4Y10GAAAA
+ FAAAAP/+SABlAGwAdgBlAHQAaQBjAGEAhAFmDJsAmwGb
+ AJsAhpKElpYQTlNQYXJhZ3JhcGhTdHlsZYaShISEEE5T
+ UGFyYWdyYXBoU3R5bGUAlIQEQ0NAUwIAhISEB05TQXJy
+ YXkAlJkMkoSEhAlOU1RleHRUYWIAlIQCQ2YAHIaShKWk
+ ADiGkoSlpABUhpKEpaQAcIaShKWkAIGMAIaShKWkAIGo
+ AIaShKWkAIHEAIaShKWkAIHgAIaShKWkAIH8AIaShKWk
+ AIEYAYaShKWkAIE0AYaShKWkAIFQAYaGAIaGhg==
+ </data>
+ <key>Text</key>
+ <string>{\rtf1\ansi\ansicpg1252\cocoartf1038\cocoasubrtf360
+{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
+{\colortbl;\red255\green255\blue255;\red0\green0\blue0;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc\pardirnatural
+
+\f0\fs24 \cf2 Memory\
+Binding}</string>
+ <key>alpha</key>
+ <array>
+ <array>
+ <integer>0</integer>
+ <integer>14</integer>
+ <real>0.64999997615814209</real>
+ </array>
+ </array>
+ </dict>
+ <key>Wrap</key>
+ <string>NO</string>
+ </dict>
+ <dict>
+ <key>Class</key>
+ <string>LineGraphic</string>
+ <key>FontInfo</key>
+ <dict>
+ <key>Font</key>
+ <string>DroidSans</string>
+ <key>Size</key>
+ <real>11</real>
+ </dict>
+ <key>Head</key>
+ <dict>
+ <key>ID</key>
+ <integer>225</integer>
+ <key>Info</key>
+ <integer>11</integer>
+ </dict>
+ <key>ID</key>
+ <integer>213</integer>
+ <key>OrthogonalBarAutomatic</key>
+ <false/>
+ <key>OrthogonalBarPoint</key>
+ <string>{0, 0}</string>
+ <key>OrthogonalBarPosition</key>
+ <real>4.1290435791015625</real>
+ <key>Points</key>
+ <array>
+ <string>{258.125, 263.815}</string>
+ <string>{305.375, 334}</string>
+ <string>{258.125, 393.3}</string>
+ </array>
+ <key>Style</key>
+ <dict>
+ <key>stroke</key>
+ <dict>
+ <key>Color</key>
+ <dict>
+ <key>a</key>
+ <string>0.7</string>
+ <key>b</key>
+ <string>0</string>
+ <key>g</key>
+ <string>0</string>
+ <key>r</key>
+ <string>0</string>
+ </dict>
+ <key>CornerRadius</key>
+ <real>4</real>
+ <key>HeadArrow</key>
+ <string>Ball</string>
+ <key>LineType</key>
+ <integer>2</integer>
+ <key>TailArrow</key>
+ <string>0</string>
+ </dict>
+ </dict>
+ <key>Tail</key>
+ <dict>
+ <key>ID</key>
+ <integer>155</integer>
+ <key>Info</key>
+ <integer>12</integer>
+ </dict>
+ </dict>
+ <dict>
+ <key>Bounds</key>
+ <string>{{328.398, 152.3}, {66, 38}}</string>
+ <key>Class</key>
+ <string>ShapedGraphic</string>
+ <key>FitText</key>
+ <string>Vertical</string>
+ <key>Flow</key>
+ <string>Resize</string>
+ <key>FontInfo</key>
+ <dict>
+ <key>Color</key>
+ <dict>
+ <key>a</key>
+ <string>0.65</string>
+ <key>w</key>
+ <string>0</string>
+ </dict>
+ <key>Font</key>
+ <string>DroidSans</string>
+ <key>Size</key>
+ <real>10</real>
+ </dict>
+ <key>ID</key>
+ <integer>199</integer>
+ <key>Line</key>
+ <dict>
+ <key>ID</key>
+ <integer>198</integer>
+ <key>Position</key>
+ <real>0.34207895398139954</real>
+ <key>RotationType</key>
+ <integer>0</integer>
+ </dict>
+ <key>Magnets</key>
+ <array>
+ <string>{0, 1}</string>
+ <string>{0, -1}</string>
+ <string>{1, 0}</string>
+ <string>{-1, 0}</string>
+ </array>
+ <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>
+ </dict>
+ </dict>
+ <key>Text</key>
+ <dict>
+ <key>RTFD</key>
+ <data>
+ BAtzdHJlYW10eXBlZIHoA4QBQISEhBJOU0F0dHJpYnV0
+ ZWRTdHJpbmcAhIQITlNPYmplY3QAhZKEhIQITlNTdHJp
+ bmcBlIQBKxFNZW1vcnkgQWxsb2NhdGlvboaEAmlJARGS
+ hISEDE5TRGljdGlvbmFyeQCUhAFpA5KElpYHTlNDb2xv
+ coaShISEB05TQ29sb3IAlIQBYwOEAmZmAINmZiY/hpKE
+ lpYGTlNGb250hpKEhIQGTlNGb250HpSZHIQFWzI4Y10G
+ AAAAFAAAAP/+SABlAGwAdgBlAHQAaQBjAGEAhAFmDJsA
+ mwGbAJsAhpKElpYQTlNQYXJhZ3JhcGhTdHlsZYaShISE
+ EE5TUGFyYWdyYXBoU3R5bGUAlIQEQ0NAUwIAhISEB05T
+ QXJyYXkAlJkMkoSEhAlOU1RleHRUYWIAlIQCQ2YAHIaS
+ hKWkADiGkoSlpABUhpKEpaQAcIaShKWkAIGMAIaShKWk
+ AIGoAIaShKWkAIHEAIaShKWkAIHgAIaShKWkAIH8AIaS
+ hKWkAIEYAYaShKWkAIE0AYaShKWkAIFQAYaGAIaGhg==
+ </data>
+ <key>Text</key>
+ <string>{\rtf1\ansi\ansicpg1252\cocoartf1038\cocoasubrtf360
+{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
+{\colortbl;\red255\green255\blue255;\red0\green0\blue0;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc\pardirnatural
+
+\f0\fs24 \cf2 Memory Allocation}</string>
+ <key>alpha</key>
+ <array>
+ <array>
+ <integer>0</integer>
+ <integer>17</integer>
+ <real>0.64999997615814209</real>
+ </array>
+ </array>
+ </dict>
+ </dict>
+ <dict>
+ <key>Class</key>
+ <string>LineGraphic</string>
+ <key>FontInfo</key>
+ <dict>
+ <key>Font</key>
+ <string>DroidSans</string>
+ <key>Size</key>
+ <real>11</real>
+ </dict>
+ <key>Head</key>
+ <dict>
+ <key>ID</key>
+ <integer>200</integer>
+ <key>Info</key>
+ <integer>6</integer>
+ </dict>
+ <key>ID</key>
+ <integer>198</integer>
+ <key>OrthogonalBarAutomatic</key>
+ <false/>
+ <key>OrthogonalBarPoint</key>
+ <string>{0, 0}</string>
+ <key>OrthogonalBarPosition</key>
+ <real>4.1290435791015625</real>
+ <key>Points</key>
+ <array>
+ <string>{258.125, 171.3}</string>
+ <string>{462.375, 269.998}</string>
+ </array>
+ <key>Style</key>
+ <dict>
+ <key>stroke</key>
+ <dict>
+ <key>Color</key>
+ <dict>
+ <key>a</key>
+ <string>0.7</string>
+ <key>b</key>
+ <string>0</string>
+ <key>g</key>
+ <string>0</string>
+ <key>r</key>
+ <string>0</string>
+ </dict>
+ <key>CornerRadius</key>
+ <real>4</real>
+ <key>HeadArrow</key>
+ <string>Ball</string>
+ <key>LineType</key>
+ <integer>2</integer>
+ <key>TailArrow</key>
+ <string>0</string>
+ </dict>
+ </dict>
+ <key>Tail</key>
+ <dict>
+ <key>ID</key>
+ <integer>155</integer>
+ <key>Info</key>
+ <integer>11</integer>
+ </dict>
+ </dict>
+ <dict>
+ <key>Bounds</key>
+ <string>{{367.375, 269.998}, {190, 112}}</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>200</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.628571</string>
+ <key>g</key>
+ <string>0.768599</string>
+ <key>r</key>
+ <string>1</string>
+ </dict>
+ <key>FillType</key>
+ <integer>2</integer>
+ <key>GradientAngle</key>
+ <real>90</real>
+ <key>GradientColor</key>
+ <dict>
+ <key>b</key>
+ <string>0.236788</string>
+ <key>g</key>
+ <string>0.532236</string>
+ <key>r</key>
+ <string>0.990271</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.131021</string>
+ <key>g</key>
+ <string>0.363196</string>
+ <key>r</key>
+ <string>0.725948</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 Memory}</string>
+ <key>VerticalPad</key>
+ <integer>0</integer>
+ </dict>
+ </dict>
+ <dict>
+ <key>Class</key>
+ <string>LineGraphic</string>
+ <key>FontInfo</key>
+ <dict>
+ <key>Font</key>
+ <string>DroidSans</string>
+ <key>Size</key>
+ <real>11</real>
+ </dict>
+ <key>Head</key>
+ <dict>
+ <key>ID</key>
+ <integer>225</integer>
+ </dict>
+ <key>ID</key>
+ <integer>203</integer>
+ <key>OrthogonalBarAutomatic</key>
+ <false/>
+ <key>OrthogonalBarPoint</key>
+ <string>{0, 0}</string>
+ <key>OrthogonalBarPosition</key>
+ <real>4.1290435791015625</real>
+ <key>Points</key>
+ <array>
+ <string>{138.375, 309.5}</string>
+ <string>{138.375, 340}</string>
+ </array>
+ <key>Style</key>
+ <dict>
+ <key>stroke</key>
+ <dict>
+ <key>Color</key>
+ <dict>
+ <key>a</key>
+ <string>0.7</string>
+ <key>b</key>
+ <string>0</string>
+ <key>g</key>
+ <string>0</string>
+ <key>r</key>
+ <string>0</string>
+ </dict>
+ <key>CornerRadius</key>
+ <real>4</real>
+ <key>HeadArrow</key>
+ <string>FilledArrow</string>
+ <key>LineType</key>
+ <integer>2</integer>
+ <key>TailArrow</key>
+ <string>0</string>
+ </dict>
+ </dict>
+ <key>Tail</key>
+ <dict>
+ <key>ID</key>
+ <integer>155</integer>
+ </dict>
+ </dict>
+ <dict>
+ <key>Class</key>
+ <string>LineGraphic</string>
+ <key>FontInfo</key>
+ <dict>
+ <key>Font</key>
+ <string>DroidSans</string>
+ <key>Size</key>
+ <real>11</real>
+ </dict>
+ <key>Head</key>
+ <dict>
+ <key>ID</key>
+ <integer>201</integer>
+ <key>Info</key>
+ <integer>6</integer>
+ </dict>
+ <key>ID</key>
+ <integer>196</integer>
+ <key>OrthogonalBarAutomatic</key>
+ <false/>
+ <key>OrthogonalBarPoint</key>
+ <string>{0, 0}</string>
+ <key>OrthogonalBarPosition</key>
+ <real>4.1290435791015625</real>
+ <key>Points</key>
+ <array>
+ <string>{138.375, 208.17}</string>
+ <string>{138.375, 233.208}</string>
+ </array>
+ <key>Style</key>
+ <dict>
+ <key>stroke</key>
+ <dict>
+ <key>Color</key>
+ <dict>
+ <key>a</key>
+ <string>0.7</string>
+ <key>b</key>
+ <string>0</string>
+ <key>g</key>
+ <string>0</string>
+ <key>r</key>
+ <string>0</string>
+ </dict>
+ <key>CornerRadius</key>
+ <real>4</real>
+ <key>HeadArrow</key>
+ <string>FilledArrow</string>
+ <key>LineType</key>
+ <integer>2</integer>
+ <key>TailArrow</key>
+ <string>0</string>
+ </dict>
+ </dict>
+ <key>Tail</key>
+ <dict>
+ <key>ID</key>
+ <integer>202</integer>
+ <key>Info</key>
+ <integer>5</integer>
+ </dict>
+ </dict>
+ <dict>
+ <key>Bounds</key>
+ <string>{{43.375, 158}, {190, 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>202</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 Android Application Code}</string>
+ <key>VerticalPad</key>
+ <integer>0</integer>
+ </dict>
+ </dict>
+ <dict>
+ <key>Bounds</key>
+ <string>{{43.375, 233.208}, {190, 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>201</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.274119</string>
+ <key>g</key>
+ <string>0.950739</string>
+ <key>r</key>
+ <string>0.787494</string>
+ </dict>
+ <key>FillType</key>
+ <integer>2</integer>
+ <key>GradientAngle</key>
+ <real>90</real>
+ <key>GradientColor</key>
+ <dict>
+ <key>b</key>
+ <string>0.223529</string>
+ <key>g</key>
+ <string>0.776471</string>
+ <key>r</key>
+ <string>0.643137</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.165602</string>
+ <key>g</key>
+ <string>0.586124</string>
+ <key>r</key>
+ <string>0.428309</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 Reflected Layer Classes }</string>
+ <key>VerticalPad</key>
+ <integer>0</integer>
+ </dict>
+ </dict>
+ <dict>
+ <key>Bounds</key>
+ <string>{{43.375, 377}, {190, 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 Renderscript Code}</string>
+ <key>VerticalPad</key>
+ <integer>0</integer>
+ </dict>
+ </dict>
+ <dict>
+ <key>Bounds</key>
+ <string>{{18.625, 118}, {239.5, 191}}</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>Line</key>
+ <dict>
+ <key>ID</key>
+ <integer>196</integer>
+ <key>Position</key>
+ <real>0.21288931369781494</real>
+ <key>RotationType</key>
+ <integer>0</integer>
+ </dict>
+ <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 \
+\
+Android Framework\
+\
+\
+\
+\
+\
+\
+\
+\
+\
+\
+\
+\
+}</string>
+ <key>VerticalPad</key>
+ <integer>0</integer>
+ </dict>
+ </dict>
+ <dict>
+ <key>Bounds</key>
+ <string>{{18.625, 340}, {239.5, 191}}</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>225</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 \
+\
+Renderscript Runtime\
+\
+\
+\
+\
+\
+\
+\
+\
+\
+\
+\
+\
+}</string>
+ <key>VerticalPad</key>
+ <integer>0</integer>
+ </dict>
+ </dict>
+ </array>
+ <key>GridInfo</key>
+ <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-11-29 09:13:03 -0800</string>
+ <key>Modifier</key>
+ <string>Robert Ly</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>coded</string>
+ <string>BAtzdHJlYW10eXBlZIHoA4QBQISEhAdOU1ZhbHVlAISECE5TT2JqZWN0AIWEASqEhAx7X05TU2l6ZT1mZn2WgWQCgRgDhg==</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>
+ JVBERi0xLjMKJcTl8uXrp/Og0MTGCjUgMCBvYmoKPDwgL0xlbmd0aCA2IDAgUiAvRmls
+ dGVyIC9GbGF0ZURlY29kZSA+PgpzdHJlYW0KeAHFWsuOHbcR3fMruBwt1Go+u3spK7YR
+ IwFizwBeBFkII8ljZ8ayZ2QE/tr8Sk6xHuTte++MJAiIBEHNumTxUYf15O/+e/+7n/G3
+ LNUvKfn7t/5H/6t/8eoh+OsHH9rfh2v/fJ6Kp39Dx3f+xT/e3l+//e3DH69v3f3PYBVL
+ aOxiwsg0xbgsqw/rPK3bEv31nX/x17vg//K+zXuyc54jdQ5u33lmzjX4tEzbQozjtk2p
+ M47G+ETfnNMU1i0K30f7lrA+yjfE5FMNtIrVp5zR2RinxxYRY6Qz0ZOQRZAMYphqLD5t
+ yd+5WMoUpHWLM63Tsoat/RjLKj9hQKkbflXC7K+tFefiaWT7zcU5TSlDJMYqzhENnoW+
+ MZIXQI1bH7Zpq2sonpo4DFqaMnHWLhg2NE5/Spe80fpn4k3suMlbcDJb5g3SOvjnBP43
+ urB2Mg2bYECHE+cAOMZMoAxbbMh1QG6HpG+QZNg8JzxCqguGbAuGELwub4J/uAEWj2+B
+ o1sQ/Hf49wvfhleXwH9e0pyqfGy5fQCFi798BSHaVHO7S5iCT9WlPHs0VKxojWJF06SY
+ g0pKxJrpFPTnEldnYvUlbooBQUhpMmax0reJlRqDWKnJ4nLGRMSHKbpYqTHQh89RrFhi
+ Fyv2KlvoYqUNmljRGMWK5p2/hASgcoDDB6gPqJvhLA/ERrf3qysfYtMyz/H/8xqnCm2Q
+ /HP8u4JUvwnTDFFcvfP/9Bc/PCPVFf3FW/349RmkBsKbZ+7wh3vt8aAf1/phP/0sg3+T
+ /z/49uH6PH/ILzrNBx1yp8ywkn/5q+/811eCPLl6NeRpwx/XkaKkES5GU1BUKFqogsVQ
+ UgNUE/74a2gShlGOlUkdPTkWghpGCXhyTNxHcWoEhZEzyoAlowk6lK81ZWbTFboWVSTa
+ VqRZe8CYbakDzdu+FWiuH42izSgD5Ix2N6oT2gbUDhSqahSntvBJjVKwgjaWlUo8qVSU
+ 3RdTKgEnPM8wdR0vRhrUi9EUCwGrheBJ8gyOAAASI9cVTZor8+54SfMCmBHK1BzNG/dR
+ vCQlAHckAJgzpQx4MZoARPlaU2ZWvDhby77Hvj3gRbc0KCav++72ph+N4sUoA16Mdqyn
+ 3Ak9NYIBqmqmM4r+CosblBbOsC55PdBZrumsi5e/vrl///Mb/83967u3/3l//+9n/uqX
+ rixybUYslUpyT7O1IKkUpzmRo1Cqiwk2H9YulSxGwgjNomhrXqcVNo00jJGWKSwJhlL4
+ QQKFO9l8Srj2uh6l3Hr4Q0sg58GGwfVqSwGCiLGztswNLtpDKE+1dYRLhZau3XWvfQk4
+ Jl0hPkmqQ5MVQIbDSQeFHSQ6ibAFX8IUKnmhH60DMHTaQmHX7vImfaIOSCmtRfyJCryA
+ WSpAzBm/gjfh0rKMKEBrRAGaJtMFvk/zAFXIa3MXpZVjbvsl58JIkHmsHQU+R4gPh4Iu
+ jDojGAqMcutMBEYTIZF9aIytzXNDOHsKt2F1pMf+dxuRsJuOAt2rLYGOaTixEQXtAD/G
+ /Rjlu/NACuxv80Cy+yT/g/0Qc0zMyRD/w118tP/hL16pd/Fe/I838j95G270NgT/sFfT
+ Are5KxGlDBBSkoFiW6ec1820S95gDMAFlkNxU+CPRQRIA5QK0FzLCKUMz5U6CZSAFiF0
+ KCllUCjWS4GgjK3Nc8OQ7ShPtvsI2ZHCyWXZc9dreiq7kxxgpT0OFAytPtCmP0/B5AV6
+ dZbY8fImf6KCyRFqfgPkylpDJE0T4DRC0zyuYUiscV4HmChlgImSFAMx5amUgHhTQBFT
+ JS7kYCgFOQFcS1ZYrPzjSuYrDzDBkrmTahwjXDs5fKMMMDGagMAYW1vmVqG7qKvZ99i3
+ dQT20XbUtY7uuSs+PRVdqZzkABPtcexYnAqAFAASA512LCp8MmjDzeddLHTxw9v/dk/i
+ hN+yYz96K7QDpANgSndMEWCZ+jJl9cFIGmJxkOQv/iY66bUqqz/1w4aYEtQxpthuJV6z
+ wRam2YdxMQq4HMZaLAxXYPC75qPWAGdqKk7L0oIrhAUC3EI3sLdgE8l9GgxnQah14D4h
+ Ts+H7pMRACd254wyGE6jCQiNsbV57m44i6xGtB1ie+lxfgR2o5oOqT3ZqxlOOonhxAbo
+ 8gFSkkTcJ1rtzn2qq6UTD0Kok14zlOPgPpWT2k3ZjSGUa3mZz3KffCijYkOriVGcaPpR
+ hR5KC5m6QgtIQ3YUINvGnlG3eREBFHk5sJTCD/rv0H0ygqHAKKMy02EsQ+TymLFaNJu7
+ qyZdjUjdeuza3UrSbgwFtldDAZ2E4JQ+BxRQE8rLPZ29KYN8z0ZFwN+ylATltXOkLCh6
+ VIPt5hg1GN3Aba7xiDM02EtVQprU0f9vRV1pBsc0nKggd2HJHfW6NOtzpL20w+iWWRJo
+ dpSChyF+8e1D8D89jNrfUomWB1NA3PWMZoQxIM8cYTYnOV1EBJ5gt43i4XkIRdzdluCn
+ iVvGDVNHmlqnKUivVvIPXaCEHhRBQTBPFGKJUOmAcnM8zr8D4+/w75ej7ZAF03lQKWjL
+ AkXm6QvVeTqlzyPjkCyj7ahGGOza0cFR4qFwvkQnTzilTCQ7Jpcirmlve/L7qd1mkQxy
+ 2pCpA/B1xVSz2IZzaW3okr5aHXH+TCghbcvCPJTWEf5O16Dnoe2Bv4ygVVIyOy0SotWE
+ /AN5+QWxMWQGv4kpt6Ag00LpAiWVsjSxZpQ2alk39FACORtk95RCWQVQsMdOiYgwEf8a
+ W8SvbZTMjEwEt69tdUq5RTVlbUkDxPPcKVWeOiGcaGw7oc2Mtewpu7bbtYcRufJ+aF7d
+ oWxZF2KHIidp50ba7/h0yRCmCs2MW5EQlRScFrn5IfSSWreBXCuzakFGCpuuU0Z+pB1z
+ K03UjzGBrhXqmglcYtmQUYLcK4RKNYqQwhxDUyyn7oXuIsJn3LYVN0klJRQg2oSpJBV3
+ XCjLDxe/E3AHNrIOQkFyYm2UASNws2vBIo1tWilVTYSGTq/tASPcA0gz0WgnFR78XWZr
+ BJl5wIhQpIet7fwIVOlk9drHtmwL0ZPbnSTOoGNED+5xH38HgRNlDmjvea5rPuWD/90c
+ XysyqL25f+a4/gFXu3vCrPWfMDiWHiZRz3OmwiQgTnndoCR4DUgiE3hHEq5XWTPQr910
+ e/CLp3nDnRCCCwssCfEmH4hvQYT2QcwN8HUKpeaJQurtMaNCFzuWhBRVJTyhJnIHLuAH
+ ImgUyqJATfouxUy9jJIxQ6U+PI58o1qmWhd4/vgAaOE7dMqCNEhLKtk4VDUDirc0zrhT
+ hmXeoDpsBUxBH1tnHwcfc14jfEzoJObeKbwCcLJxsr9rrZ0dlusTef7biusJpy9sUAe1
+ 4nKRA42qPSptTittsPtp53JQaTu1wfioNPi46kYJfhzO4p8n9tXg5VrRbcAjcMj4u//z
+ IBYbFNLRdKfQD1MVCvw3aJyWYxunewlHjSexD5kWKTQLFz90b44729LgtPWrcc6ToEXp
+ jSDcUIIbFLkQSoGWgt9E92GkJL4OQmrpdO4ChM0F+XpKPbcxkBr4Qm8JJaUM2FtrRRhC
+ t8VILm2ogs8bpa9lFhTKuZOuxAgIWGS5RkLAAsTLy4M2DIr2sVtGUKB9LIA56vVIk+OG
+ EAkeEX2mDbe4zNUoWGHGnYSPNQwruJFhwT4jLn1ZcBUT0m5lS3iVAIhXBAEDBdegzGkB
+ pz6OtA68N/RS7p2iK5Bx6MPLpOmYOViRB9CO3BZglN3uzlwxXJyMi+PwxIXN/rqS2YcD
+ hIcMw02zmvapmyZiFsvfHqfsksvDRTtG/umLxnB2rb483rPdZKduNc7g+Jo5LqV/hTiI
+ bw4uDH8gmuGP459+OnmpUOMi24PXGOae50A6DREo4QMmjuA00MgdBA3WwPoFvN+gcuUB
+ rUwR/lZGcAQ1DRihKN6c/Yx4mdkrBTCAdzzTExIhgVOEAzqSxNjoO6ijMImQRP2t2kd3
+ oLFwJVSuBneuBe9+kBOmbeBBy/HQ82FBUzsyQJfb7psuF9eGA5i+A3I/W0zT59KhEi7Z
+ WZJp2ja8BqEzhzEkOeTmD7YHI4TLPQ0VNJFEM2wy+t1RkEfw0p44cZHjMI/JG3KUeeBg
+ CAbooE6NbmEYDA0e7lxTuExXELoPKTe8B0KIiqdhdM4LXpxkKt6xtXv0DiLsrG3wUMU/
+ m6LAk5tthubRRILZIeRXX7958ePJBAU9iTk1xZChoMMnZS+ZD2OL/MS9XS41YXD3njZY
+ OH/XZLogpU4qEP6AiplJMGLsZ9HkREKBEC+j6FoZAboQDhsocGHWVFG6hSsCeW06gpr9
+ RvHPHfjaJrHt75KD+FrKQS8EP8yyi4SHWigjYDmKbJi+1h5g3Z5y3bnz94ftFd9VXkzn
+ nxE0j/wzUnUFuqDz1xG0fDuURHWcFlM3gLazhICJREcHdTOQGrsTQ8/dFzn4hMqHygvq
+ keXVRNi0ns4hUuXLcjT0zF1BuRvJfB9XvPj8hGtCuY82Tp/PfeE7cor/F7kglA+R9GVE
+ GLjihSUSuy0/AuPdCMCYpWmZoplfsu4Z52Wp4IiIBSwAea1k4dLUelACIO4zSlkDV2SV
+ qBMonJiJSqCAgZ0/pQwlAOulqVtlbG2eG8vZU7iN9LP02P/eR/CGAF34jeQR6Y4t/8uH
+ BG0vv7cjG7LAdqpDOYBWHmjDvdgJK86vKdxHvNFETR2gR1DTciHLuVzIuWeaKAF+RrEz
+ IwsBt9TggeC2EQZ4CEWFn/GkswRyWwUNGSmzsAyFTsqjJjxSJj2mJSRKF24IyAx0ZUY4
+ R50UHkawQqdRICh9YGM0ER3cT2ZsbZlbhe1sNfse+7aOwBHQhkizMTx0x73OKUci8JDW
+ AA+hPJ4A0dQnAvUm+BMxIHCJdBY9mvo/vvP8VqJIq1NafKlVg5seZ0Jz+/6IYyxK4hd3
+ YUO1aqDFgXOR8v6Q6HbswoWMR3pQNBQo72oo8CSslqrZIUsX6eL19Wqv4XIlw118rYuE
+ Y9/2pVURpR84JU8mmEi+uh17ITSQEpIhBxUNoB5v54cSBwgI/UBwp5wL8g0P6hlU4scD
+ YUuqw/4h5dxeLks1gwnNYOvKbNDjDoZ2R/qbVmRz4I7wErFVjvCN0FP3NojNNb84H8K2
+ FijRcWkeMuEBFeVMicLGRClIC+DcSImPFE6rGaUd1/f/A1RDIwEKZW5kc3RyZWFtCmVu
+ ZG9iago2IDAgb2JqCjM4ODcKZW5kb2JqCjMgMCBvYmoKPDwgL1R5cGUgL1BhZ2UgL1Bh
+ cmVudCA0IDAgUiAvUmVzb3VyY2VzIDcgMCBSIC9Db250ZW50cyA1IDAgUiAvTWVkaWFC
+ b3ggWzAgMCA1NzYgNzMzXQo+PgplbmRvYmoKNyAwIG9iago8PCAvUHJvY1NldCBbIC9Q
+ REYgL1RleHQgL0ltYWdlQiAvSW1hZ2VDIC9JbWFnZUkgXSAvQ29sb3JTcGFjZSA8PCAv
+ Q3MxIDggMCBSCi9DczIgMTYgMCBSID4+IC9FeHRHU3RhdGUgPDwgL0dzMSAyNSAwIFIg
+ L0dzMiAyNiAwIFIgL0dzMyAyNyAwIFIgL0dzNCAyOCAwIFIKPj4gL0ZvbnQgPDwgL0Yy
+ LjAgMjMgMCBSIC9GMS4wIDE3IDAgUiA+PiAvWE9iamVjdCA8PCAvSW0zIDEzIDAgUiAv
+ SW0xIDkgMCBSCi9JbTIgMTEgMCBSID4+IC9TaGFkaW5nIDw8IC9TaDEgMTUgMCBSIC9T
+ aDMgMTkgMCBSIC9TaDcgMjQgMCBSIC9TaDIgMTggMCBSCi9TaDUgMjEgMCBSIC9TaDYg
+ MjIgMCBSIC9TaDQgMjAgMCBSID4+ID4+CmVuZG9iagoxNSAwIG9iago8PCAvQ29sb3JT
+ cGFjZSA4IDAgUiAvU2hhZGluZ1R5cGUgMiAvQ29vcmRzIFsgMTIwLjI1IC05NiAxMjAu
+ MjUgOTYuMDAwMDUgXQovRG9tYWluIFsgMCAxIF0gL0V4dGVuZCBbIGZhbHNlIGZhbHNl
+ IF0gL0Z1bmN0aW9uIDI5IDAgUiA+PgplbmRvYmoKMTkgMCBvYmoKPDwgL0NvbG9yU3Bh
+ Y2UgOCAwIFIgL1NoYWRpbmdUeXBlIDIgL0Nvb3JkcyBbIDk1LjUgLTI1LjU4NDg1IDk1
+ LjQ5OTk4IDI1LjU4NDg5Cl0gL0RvbWFpbiBbIDAgMSBdIC9FeHRlbmQgWyBmYWxzZSBm
+ YWxzZSBdIC9GdW5jdGlvbiAzMCAwIFIgPj4KZW5kb2JqCjI0IDAgb2JqCjw8IC9Db2xv
+ clNwYWNlIDggMCBSIC9TaGFkaW5nVHlwZSAyIC9Db29yZHMgWyA5NS41IC0yNS41ODQ4
+ NSA5NS40OTk5OCAyNS41ODQ4OQpdIC9Eb21haW4gWyAwIDEgXSAvRXh0ZW5kIFsgZmFs
+ c2UgZmFsc2UgXSAvRnVuY3Rpb24gMzEgMCBSID4+CmVuZG9iagoxOCAwIG9iago8PCAv
+ Q29sb3JTcGFjZSA4IDAgUiAvU2hhZGluZ1R5cGUgMiAvQ29vcmRzIFsgMTIwLjI1IC05
+ NiAxMjAuMjUgOTYuMDAwMDUgXQovRG9tYWluIFsgMCAxIF0gL0V4dGVuZCBbIGZhbHNl
+ IGZhbHNlIF0gL0Z1bmN0aW9uIDMyIDAgUiA+PgplbmRvYmoKMjEgMCBvYmoKPDwgL0Nv
+ bG9yU3BhY2UgOCAwIFIgL1NoYWRpbmdUeXBlIDIgL0Nvb3JkcyBbIDk1LjUgLTI1LjU4
+ NDg1IDk1LjQ5OTk4IDI1LjU4NDg5Cl0gL0RvbWFpbiBbIDAgMSBdIC9FeHRlbmQgWyBm
+ YWxzZSBmYWxzZSBdIC9GdW5jdGlvbiAzMyAwIFIgPj4KZW5kb2JqCjIyIDAgb2JqCjw8
+ IC9Db2xvclNwYWNlIDggMCBSIC9TaGFkaW5nVHlwZSAyIC9Db29yZHMgWyA5NS41IC01
+ Ni41IDk1LjQ5OTk4IDU2LjUwMDA0Cl0gL0RvbWFpbiBbIDAgMSBdIC9FeHRlbmQgWyBm
+ YWxzZSBmYWxzZSBdIC9GdW5jdGlvbiAzNCAwIFIgPj4KZW5kb2JqCjIwIDAgb2JqCjw8
+ IC9Db2xvclNwYWNlIDggMCBSIC9TaGFkaW5nVHlwZSAyIC9Db29yZHMgWyA5NS41IC0y
+ NS41ODQ4NSA5NS40OTk5OCAyNS41ODQ4OQpdIC9Eb21haW4gWyAwIDEgXSAvRXh0ZW5k
+ IFsgZmFsc2UgZmFsc2UgXSAvRnVuY3Rpb24gMzUgMCBSID4+CmVuZG9iagoxMyAwIG9i
+ ago8PCAvTGVuZ3RoIDE0IDAgUiAvVHlwZSAvWE9iamVjdCAvU3VidHlwZSAvSW1hZ2Ug
+ L1dpZHRoIDQwMiAvSGVpZ2h0IDI0NiAvSW50ZXJwb2xhdGUKdHJ1ZSAvQ29sb3JTcGFj
+ ZSAzNiAwIFIgL0ludGVudCAvUGVyY2VwdHVhbCAvU01hc2sgMzcgMCBSIC9CaXRzUGVy
+ Q29tcG9uZW50CjggL0ZpbHRlciAvRmxhdGVEZWNvZGUgPj4Kc3RyZWFtCngB7dCBAAAA
+ AMOg+VMf5IVQYcCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMG
+ DBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCA
+ AQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgw
+ YMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMG
+ DBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCA
+ AQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgw
+ YMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMG
+ DBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCA
+ AQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgw
+ YMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMG
+ DBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCA
+ AQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgw
+ YMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMG
+ DBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCA
+ AQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgw
+ YMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMG
+ DBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCA
+ AQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgw
+ YMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMG
+ DBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCA
+ AQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgw
+ YMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMG
+ DBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCA
+ AQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgw
+ YMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMG
+ DBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMvAwOHIAABCmVuZHN0cmVhbQplbmRvYmoK
+ MTQgMCBvYmoKMTMxNgplbmRvYmoKOSAwIG9iago8PCAvTGVuZ3RoIDEwIDAgUiAvVHlw
+ ZSAvWE9iamVjdCAvU3VidHlwZSAvSW1hZ2UgL1dpZHRoIDUwMiAvSGVpZ2h0IDQ2MiAv
+ SW50ZXJwb2xhdGUKdHJ1ZSAvQ29sb3JTcGFjZSAzNiAwIFIgL0ludGVudCAvUGVyY2Vw
+ dHVhbCAvU01hc2sgMzkgMCBSIC9CaXRzUGVyQ29tcG9uZW50CjggL0ZpbHRlciAvRmxh
+ dGVEZWNvZGUgPj4Kc3RyZWFtCngB7dABDQAAAMKg909tDwcRKAwYMGDAgAEDBgwYMGDA
+ gAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwY
+ MGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAED
+ BgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDA
+ gAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwY
+ MGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAED
+ BgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDA
+ gAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwY
+ MGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAED
+ BgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDA
+ gAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwY
+ MGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAED
+ BgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDA
+ gAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwY
+ MGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAED
+ BgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDA
+ gAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwY
+ MGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAED
+ BgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDA
+ gAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwY
+ MGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAED
+ BgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDA
+ gAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwY
+ MGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAED
+ BgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDA
+ gAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwY
+ MGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAED
+ BgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDA
+ gAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwY
+ MGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAED
+ BgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDA
+ gAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwY
+ MGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAED
+ BgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDA
+ gAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwY
+ MGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAED
+ BgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDA
+ gAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwY
+ MGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAED
+ BgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDA
+ gAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwY
+ MGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAED
+ BgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDA
+ gAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwY
+ MGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAED
+ BgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDA
+ gAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwY
+ MGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAED
+ BgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDA
+ gAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwY
+ MGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAED
+ BgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDA
+ gAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwY
+ MGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAED
+ BgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDA
+ gAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwY
+ MGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAED
+ BgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDA
+ gAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwY
+ MGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAEDBgwYMGDAgAED
+ BgwYMGDAgAEDPwMDnnIAAQplbmRzdHJlYW0KZW5kb2JqCjEwIDAgb2JqCjMwNTcKZW5k
+ b2JqCjExIDAgb2JqCjw8IC9MZW5ndGggMTIgMCBSIC9UeXBlIC9YT2JqZWN0IC9TdWJ0
+ eXBlIC9JbWFnZSAvV2lkdGggNDAyIC9IZWlnaHQgMTIyIC9JbnRlcnBvbGF0ZQp0cnVl
+ IC9Db2xvclNwYWNlIDM2IDAgUiAvSW50ZW50IC9QZXJjZXB0dWFsIC9TTWFzayA0MSAw
+ IFIgL0JpdHNQZXJDb21wb25lbnQKOCAvRmlsdGVyIC9GbGF0ZURlY29kZSA+PgpzdHJl
+ YW0KeAHt0DEBAAAAwqD1T20JT4hAYcCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCA
+ AQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgw
+ YMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMG
+ DBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCA
+ AQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgw
+ YMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMG
+ DBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCA
+ AQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgw
+ YMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMG
+ DBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCA
+ AQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgw
+ YMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMG
+ DBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYMCAAQMGDBgwYOAz
+ MD7aAAEKZW5kc3RyZWFtCmVuZG9iagoxMiAwIG9iago2NjUKZW5kb2JqCjQxIDAgb2Jq
+ Cjw8IC9MZW5ndGggNDIgMCBSIC9UeXBlIC9YT2JqZWN0IC9TdWJ0eXBlIC9JbWFnZSAv
+ V2lkdGggNDAyIC9IZWlnaHQgMTIyIC9Db2xvclNwYWNlCi9EZXZpY2VHcmF5IC9JbnRl
+ cnBvbGF0ZSB0cnVlIC9CaXRzUGVyQ29tcG9uZW50IDggL0ZpbHRlciAvRmxhdGVEZWNv
+ ZGUgPj4Kc3RyZWFtCngB7ZdrU9pqFIVJQi7cBVSEgnpKKVYhnUPrHRipIJeDApUA/f9/
+ pKEzbcHL9ot915zp2p9g1pCVeR72SwgEOCRAAiRAAiRAAiRAAmoIaLpucJQS0HVNe06u
+ phumZTshjkoCjm0GjaedaIbpRGKJZIqjkEByIx4N20H9CSe6YUUS6UwuX9jlqCNQeJPd
+ TsVC5uM10Qw7ms7tlw4rrvuRo4qAWz06KBYyG2Hz4ZZohhXdLLx3j8/rjSZHHYHG5Wnt
+ qJhL+krWf991M5IuHNQuW51ur89RR6B3026euu+yCefBuWU4iez7WqPz391oPOGoIzAe
+ 3fa/nFf/2YquL4kWjKT33cvOcDL1vBlHHQHPux8NWicHOX9JVo8t3YplSsetwcSbzxeL
+ xTeOGgI+6/lsOurW3b10OLj6BKzbidzheeduuvRBI2p0/GhZKvk6uPpU9I+tVSOGk8xX
+ 6t2Rxw1RaOOnkvvh9UkpE1s3EkoW3EZv7HFBVBv5tpjf37ZPyzsxa21HQqldt9mf+EaU
+ 39FfXzif3nXOytn4IyMfaQTz5VgaOT94xsgMc09/d+svI6v/2g3/1FruCI0Avhw0AoAu
+ VtKIiAcQ0ggAulhJIyIeQEgjAOhiJY2IeAAhjQCgi5U0IuIBhDQCgC5W0oiIBxDSCAC6
+ WEkjIh5ASCMA6GIljYh4ACGNAKCLlTQi4gGENAKALlbSiIgHENIIALpYSSMiHkBIIwDo
+ YiWNiHgAIY0AoIuVNCLiAYQ0AoAuVtKIiAcQ0ggAulhJIyIeQEgjAOhiJY2IeAAhjQCg
+ i5U0IuIBhDQCgC5W0oiIBxDSCAC6WEkjIh5ASCMA6GIljYh4ACGNAKCLlTQi4gGENAKA
+ LlbSiIgHENIIALpYSSMiHkBIIwDoYiWNiHgAIY0AoIuVNCLiAYQ0AoAuVtKIiAcQ0ggA
+ ulhJIyIeQEgjAOhiJY2IeAAhjQCgi5U0IuIBhDQCgC5W0oiIBxDSCAC6WEkjIh5ASCMA
+ 6GIljYh4ACGNAKCLlTQi4gGENAKALlbSiIgHENIIALpYSSMiHkBIIwDoYiWNiHgAIY0A
+ oIuVNCLiAYQ0AoAuVtKIiAcQ0ggAulhJIyIeQEgjAOhiJY2IeAAhjQCgi5WiEW8hfpbh
+ nyDwy4gW+D1GKLXrNvsTGvkTyF+45tLIWTkbt9aNJAtuozf2FgtuyQsAXztezO9v26fl
+ ndi6ESeZr9S7I29OJa9N/IXrLXwjw+uTUiZmru6IbidyH847t1MaeQHga8e+kNnXwdWn
+ 4lZk3YgVy5Q+twYTb04nrw1duJ5/Is1n07uburuXCgdXd0QLhtN77kV7OJl6/sw4agj4
+ rKf3o37r+CCXcIzfT1r+K8NOZEu1entwOxqPJxxFBMbj0d2w1zqr7m9GTH3NiG6GU4Vy
+ 7eKqfdPt9TmKCPR63Zvr5olb3PFXZPXQCgQ0w4pu5kvVz2eXjUaTo4pAo35x+u/h2+xG
+ 6MGKLJXY0VR2792Ho0rV5agiUK0clt/mtxNhU19fEf8E87ckHE9vZ9/kCxx1BPK5na1k
+ zN+QR0KWSkw7HItvJP1JcRQQWJJOJuLRkBV8SoivRDeClu04IY46Ao5tmc/4+PHopWm6
+ bnAUEtB1XXviwFp7EOYbEiABEiABEiCB/y+B75ER7IQKZW5kc3RyZWFtCmVuZG9iago0
+ MiAwIG9iagoxMjQzCmVuZG9iagozOSAwIG9iago8PCAvTGVuZ3RoIDQwIDAgUiAvVHlw
+ ZSAvWE9iamVjdCAvU3VidHlwZSAvSW1hZ2UgL1dpZHRoIDUwMiAvSGVpZ2h0IDQ2MiAv
+ Q29sb3JTcGFjZQovRGV2aWNlR3JheSAvSW50ZXJwb2xhdGUgdHJ1ZSAvQml0c1BlckNv
+ bXBvbmVudCA4IC9GaWx0ZXIgL0ZsYXRlRGVjb2RlID4+CnN0cmVhbQp4Ae3YW1fV9R5G
+ cVmLxUlAkRS1TSdDGR5opFvJPLQ1yEMiKiD0/t/Ihho1wnK696Wz+bvp4ltj9MyPf7RO
+ nOhVoAIVqEAFKlCBClSgAhWoQAUqUIEKVKACFahABSpQgQpUoAIVqEAFKlCBClSgAhWo
+ QAUqUIEKVKACFahABSpQgQpUoAIVqEAFKlCBClSgAhWoQAUqUIEKVKACFfjfCowNBsOe
+ rcBgMDb2Xv+xwXA0MTk13ZMVmJocjQ/f4z42HE2dnDu1cKbnKrBwen52ZnJ88Hfug+HE
+ yVOLSxf/tfxZT1Vg+dML587MTY/+5nMfG07OLl78YuXq9bW1b3qiAms3rq1eWl46PTP6
+ y9c+NpyY/WT58trtu/cfPOypCjy4t37z2qWLC4fs7/yZbjA6ubi8evPeo80nT5/1VAWe
+ /rTxcH3t6wunpt79GT+cOnXh8s0Hmz+/3H71uqcq8Gp769njuze+PDv7zsc+Nn5y8Yu1
+ e5svXu/u7b3tqQrs7e1sP390Z/Xi4cd+7Ef8YGJuaeX2o+ev9/b3Dw4OfulpChxy7r/d
+ 3X5yf+3zxZnxY//1Npg8dfHq3c2Xu0fmqWvIfx1yxP7m+X9uXTr8EX9MfTi18K/r959s
+ 7/Wlu8R/Z9958eOdlaW5d9SnF5bXHjx9tdeHLlT/5WB/Z2tj/cr5uYnj3/r0mc/WHj57
+ fahuXP2P37S/+3LzuysX5v+q/k3q2l8dR+p3V9+n/la7+5897A/1Y/93bnj4E/7oW0/d
+ +asjdacrr0qd+zivqTtdeVXq3Md5Td3pyqtS5z7Oa+pOV16VOvdxXlN3uvKq1LmP85q6
+ 05VXpc59nNfUna68KnXu47ym7nTlValzH+c1dacrr0qd+zivqTtdeVXq3Md5Td3pyqtS
+ 5z7Oa+pOV16VOvdxXlN3uvKq1LmP85q605VXpc59nNfUna68KnXu47ym7nTlValzH+c1
+ dacrr0qd+zivqTtdeVXq3Md5Td3pyqtS5z7Oa+pOV16VOvdxXlN3uvKq1LmP85q605VX
+ pc59nNfUna68KnXu47ym7nTlValzH+c1dacrr0qd+zivqTtdeVXq3Md5Td3pyqtS5z7O
+ a+pOV16VOvdxXlN3uvKq1LmP85q605VXpc59nNfUna68KnXu47ym7nTlValzH+c1dacr
+ r0qd+zivqTtdeVXq3Md5Td3pyqtS5z7Oa+pOV16VOvdxXlN3uvKq1LmP85q605VXpc59
+ nNfUna68KnXu47ym7nTlValzH+c1dacrr0qd+zivqTtdeVXq3Md5Td3pyqtS5z7Oa+pO
+ V16VOvdxXlN3uvKq1LmP85q605VXpc59nNfUna68KnXu47ym7nTlValzH+c1dacrr0qd
+ +zivqTtdeVXq3Md5Td3pyqtS5z7Oa+pOV16VOvdxXlN3uvKq1LmP85q605VXpc59nNfU
+ na68KnXu47ym7nTlValzH+c1dacrr0qd+zivqTtdeVXq3Md5Td3pyqtS5z7Oa+pOV16V
+ OvdxXlN3uvKq1LmP85q605VXpc59nNfUna68KnXu47ym7nTlValzH+c1dacrr0qd+ziv
+ qTtdeVXq3Md5Td3pyqtS5z7Oa+pOV16VOvdxXlN3uvKq1LmP85q605VXpc59nNfUna68
+ KnXu47ym7nTlValzH+c1dacrr0qd+zivqTtdeVXq3Md5Td3pyqtS5z7Oa+pOV16VOvdx
+ XlN3uvKq1LmP85q605VXpc59nNfUna68KnXu47ym7nTlValzH+c1dacrr0qd+zivqTtd
+ eVXq3Md5Td3pyqtS5z7Oa+pOV16VOvdxXlN3uvKq1LmP85q605VXpc59nNfUna68KnXu
+ 47ym7nTlValzH+c1dacrr0qd+zivqTtdeVXq3Md5Td3pyqtS5z7Oa+pOV16VOvdxXlN3
+ uvKq1LmP85q605VXpc59nNfUna68KnXu47ym7nTlValzH+c1dacrr0qd+zivqTtdeVXq
+ 3Md5Td3pyqtS5z7Oa+pOV16VOvdxXlN3uvKq1LmP85q605VXpc59nNfUna68KnXu47ym
+ 7nTlValzH+c1dacrr0qd+zivqTtdeVXq3Md5Td3pyqtS5z7Oa+pOV16VOvdxXlN3uvKq
+ 1LmP85q605VXpc59nNfUna68KnXu47ym7nTlValzH+c1dacrr0qd+zivqTtdeVXq3Md5
+ Td3pyqtS5z7Oa+pOV16VOvdxXlN3uvKq1LmP85q605VXpc59nNfUna68KnXu47ym7nTl
+ ValzH+c1dacrr0qd+zivqTtdeVXq3Md5Td3pyqtS5z7Oa+pOV16VOvdxXlN3uvKq1LmP
+ 85q605VXpc59nNfUna68KnXu47ym7nTlValzH+c1dacrr0qd+zivqTtdeVXq3Md5Td3p
+ yqtS5z7Oa+pOV16VOvdxXlN3uvKq1LmP85q605VXpc59nNfUna68KnXu47ym7nTlValz
+ H+c1dacrr0qd+zivqTtdeVXq3Md5Td3pyqtS5z7Oa+pOV16VOvdxXlN3uvKq1LmP85q6
+ 05VXpc59nNfUna68KnXu47ym7nTlValzH+c1dacrr0qd+zivqTtdeVXq3Md5Td3pyqtS
+ 5z7Oa+pOV16VOvdxXlN3uvKq1LmP85q605VXpc59nNfUna68KnXu47ym7nTlValzH+c1
+ dacrr0qd+zivqTtdeVXq3Md5Td3pyqtS5z7Oa+pOV16VOvdxXlN3uvKq1LmP85q605VX
+ pc59nNfUna68KnXu47ym7nTlValzH+c1dacrr0qd+zivqTtdeVXq3Md5Td3pyqtS5z7O
+ a+pOV16VOvdxXlN3uvKq1LmP85q605VXpc59nNfUna68KnXu47ym7nTlValzH+c1dacr
+ r0qd+zivqTtdeVXq3Md5Td3pyqtS5z7Oa+pOV16VOvdxXlN3uvKq1LmP85q605VXpc59
+ nNfUna68KnXu47ym7nTlValzH+c1dacrr0qd+zivqTtdeVXq3Md5Td3pyqtS5z7Oa+pO
+ V16VOvdxXlN3uvKqP9THTvzpDafPfPbNw2ev9w74n+76cRZ4v/pa6h8n6Qf/rQ8O9ne3
+ Nr67cn5+4p1vfWH5xoOnr/YO+tg/GPGj+xsO1Xe2NtYvL80dVx9Mnf702r2ftnf3Y//o
+ UD/wL3xw+N6+efH49sq52dGxb30wOX9hdX1ja+dt7B+I+NGdD9H3914/++Hbrz45OX5M
+ fWw0e+7SzR+ebe++3e/ZCrzde7O1+f315YXp4Z/+BH/ixNj4zJnla+uPn2+/2dntuQrs
+ 7Lze+unBrZXz85ODY+onBhNzS5fW7j568vOLrZc9U4GtrRfPNh/+++ry4szx39aPPvbp
+ 0xe/vnHn/qMfNzZ7pgIbG49/+P7W1c/Pzk0Oj/22fvjdD0YzCxe+XF27dWf9bs9U4Lv1
+ 299eX1k+Oz91/M9yRz/sx4ajmVNnP/380sqV1Z6pwJXLK18tnz8zNzX+zu/qv7IPRlOz
+ pxbPLp2/0DMVOL907pMz8zOT44N3f77/xj4+MTUzOzffcxWYmz05PTn6y+/pR+ZHb2ww
+ HB9N9GwFRqPD7/zvPvTf2A/hD9+gpypwZPq7b3+tQAUqUIEKVKACFahABSpQgQpUoAIV
+ qEAFKlCBClSgAhWoQAUqUIEKVKACFahABSpQgQpUoAIVqEAFKlCBClSgAhWoQAUqUIEK
+ VKACFahABSpQgQpUoAIVqMD/WeC/aJaU4QplbmRzdHJlYW0KZW5kb2JqCjQwIDAgb2Jq
+ CjI3ODkKZW5kb2JqCjM3IDAgb2JqCjw8IC9MZW5ndGggMzggMCBSIC9UeXBlIC9YT2Jq
+ ZWN0IC9TdWJ0eXBlIC9JbWFnZSAvV2lkdGggNDAyIC9IZWlnaHQgMjQ2IC9Db2xvclNw
+ YWNlCi9EZXZpY2VHcmF5IC9JbnRlcnBvbGF0ZSB0cnVlIC9CaXRzUGVyQ29tcG9uZW50
+ IDggL0ZpbHRlciAvRmxhdGVEZWNvZGUgPj4Kc3RyZWFtCngB7ZdrU5J7HEXl4Y6Aoilq
+ 0c1QxwtNepTMS0eDvCQiAkLf/4scqKnAavemnj1zWr83vdhTq1nLP9TEBIcBDGAAAxjA
+ AAYwEI6BSBBEuVANBEEk8rO4kSAaTyRTaS5MA6lkPBb9cZNINJ6azE0VZrgQDRSm89lM
+ Mhb8oEkQTUxOzRaXHpUec+EZKD1cnJ/JpePfP5NINJmdXXpaXt+sVF5yYRmobG2sLZeK
+ 05n4/VcSiSayD0orld39w6NjLjwDRwfV7Y3lpcIgyfj3exCfnC2tbR+c1M/OL7jwDJy/
+ rx1XKy8Wp1L3PreiqanFle2j+ofr5k2LC8/ATbNxcbq/9WwuO/5IIrHJ2aeVg/pVq9Pt
+ 3nHhGeh2283Lk721pcEjGf3YChK5Ynn35LLV7fX6/f5HLhwDA9e9u07z7LDyZDYTG/0X
+ cJCcWlrfr193hj0oEk6OT5RhktvLf3eWBx9bo0WiqcKjzcOzZpcXEmKNL0naV+/2ysXc
+ eJF0oVQ5Or/p8kDCLvKx32s3atXVhVxi7I2kZx5Xji9agyKh/43+emCvc11/vbqY/67I
+ S4p4fjiGRfbXflLkzvN3+rupX4uM/q89OvjUGr4Rihh+OChikC6RFJF6DCNFDNIlkiJS
+ j2GkiEG6RFJE6jGMFDFIl0iKSD2GkSIG6RJJEanHMFLEIF0iKSL1GEaKGKRLJEWkHsNI
+ EYN0iaSI1GMYKWKQLpEUkXoMI0UM0iWSIlKPYaSIQbpEUkTqMYwUMUiXSIpIPYaRIgbp
+ EkkRqccwUsQgXSIpIvUYRooYpEskRaQew0gRg3SJpIjUYxgpYpAukRSRegwjRQzSJZIi
+ Uo9hpIhBukRSROoxjBQxSJdIikg9hpEiBukSSRGpxzBSxCBdIiki9RhGihikSyRFpB7D
+ SBGDdImkiNRjGClikC6RFJF6DCNFDNIlkiJSj2GkiEG6RFJE6jGMFDFIl0iKSD2GkSIG
+ 6RJJEanHMFLEIF0iKSL1GEaKGKRLJEWkHsNIEYN0iaSI1GMYKWKQLpEUkXoMI0UM0iWS
+ IlKPYaSIQbpEUkTqMYwUMUiXSIpIPYaRIgbpEkkRqccwUsQgXSIpIvUYRooYpEskRaQe
+ w0gRg3SJpIjUYxgpYpAukRSRegwjRQzSJZIiUo9hpIhBukRSROoxjBQxSJdIikg9hpEi
+ BukSSRGpxzBSxCBdIiki9RhGihikSyRFpB7DSBGDdImkiNRjGClikC6RFJF6DCNFDNIl
+ kiJSj2GkiEG6RFJE6jGMFDFIl0iKSD2GkSIG6RJJEanHMFLEIF0iKSL1GEaKGKRLJEWk
+ HsNIEYN0iaSI1GMYKWKQLpEUkXoMI0UM0iWSIlKPYaSIQbpEUkTqMYwUMUiXSIpIPYaR
+ IgbpEkkRqccwUsQgXSIpIvUYRooYpEskRaQew0gRg3SJpIjUYxgpYpAukRSRegwjRQzS
+ JZIiUo9hpIhBukRSROoxjBQxSJdIikg9hpEiBukSSRGpxzBSxCBdIiki9RhGihikSyRF
+ pB7DSBGDdImkiNRjGClikC6RFJF6DCNFDNIlkiJSj2GkiEG6RFJE6jGMFDFIl0iKSD2G
+ kSIG6RJJEanHMFLEIF0iKSL1GEaKGKRLJEWkHsNIEYN0iaSI1GMYKWKQLpEUkXoMI0UM
+ 0iWSIlKPYaSIQbpEUkTqMYwUMUiXSIpIPYaRIgbpEkkRqccwUsQgXSIpIvUYRooYpEsk
+ RaQew0gRg3SJpIjUYxgpYpAukRSRegwjRQzSJZIiUo9hpIhBukRSROoxjBQxSJdIikg9
+ hpEiBukSSRGpxzBSxCBdIiki9RhGihikSyRFpB7DSBGDdImkiNRjGClikC6RFJF6DCNF
+ DNIlkiJSj2GkiEG6RFJE6jGMFDFIl0iKSD2GkSIG6RJJEanHMFLEIF0ivxaJTHy7aHrm
+ 8cvji1a3L38v458w8NMiFYr8Cd+/+jP7/V6nUXu9upBPjL+RQmnr6Pym2+eR/Erhb94H
+ RdqNWnWlmBsrEqSmH24cvG92eiT5zcb1H9cf3N3t1elueT4bH30jQTK/uFatNdp3JNEK
+ f/M6CNLrti7evnr+YDI2WiQSz84vb7+9aHbuelyoBu66t436m81SIR399i+tiYlILDNT
+ 2qieXjZv2x0uRAPtdqvx/minvJBPBqNFJoJErrhc2T85+3DVuOZCM9BoXF3Uj/9ZL81m
+ xr5Gho8kPb30Ymvv8ORdrc6FZqBWO337Zmf9yVwuGR39Ghk8lyCeKSw+W6vs7FX3udAM
+ vK7uvtosl+byqbHv9eHnVyQaz0zNPXyyXF5d40IzsLpSfl5amMmlYuPfIp+SBPFUdmp2
+ rriwyIVmYKE4/2Amn0nGgnufWZ+TxBKpTDaX50I0kMtOppPx+98hwx7DiwTRWDzBhWog
+ Hh+8jx88kM9JBlEGF3DhGRgK/yKfXzGAAQxgAAMY+P8Z+A/zFAiFCmVuZHN0cmVhbQpl
+ bmRvYmoKMzggMCBvYmoKMTg0MQplbmRvYmoKMjUgMCBvYmoKPDwgL1R5cGUgL0V4dEdT
+ dGF0ZSAvQ0EgMC43ID4+CmVuZG9iagoyNiAwIG9iago8PCAvVHlwZSAvRXh0R1N0YXRl
+ IC9jYSAwLjcgPj4KZW5kb2JqCjI3IDAgb2JqCjw8IC9UeXBlIC9FeHRHU3RhdGUgL2Nh
+ IDAuNjUgPj4KZW5kb2JqCjI4IDAgb2JqCjw8IC9UeXBlIC9FeHRHU3RhdGUgL2NhIDEg
+ Pj4KZW5kb2JqCjQzIDAgb2JqCjw8IC9MZW5ndGggNDQgMCBSIC9OIDMgL0FsdGVybmF0
+ ZSAvRGV2aWNlUkdCIC9GaWx0ZXIgL0ZsYXRlRGVjb2RlID4+CnN0cmVhbQp4AdVZZ1gU
+ zbLumU3AsqQl5xxFcpacJEgOgkha0pJzDkpSgiCIgICggAgighgIAiJgAkSCgBEJoiCo
+ YAIE4Q7q933nPuecf/fPneeZnnerqqtrp3q6p94BgG3ZLTjYH6YDICAwPNTKUIf3oIMj
+ L+4FoAQ0gBGIAUo3UliwtoWFKfivx/cJAO0qxyR3ff1Xs/+soPfwDCMBAFkganePMFIA
+ gq8DAOuQgkPDAUCtI/LhqPBgBKMfIJgxFAkQwS93sfdvvLKL3X9hDPqXjY2VLgAYVgAo
+ qN3cQr0BIAgict5Ikjfih6AHAJYh0IMcCADxIII1SD5uHgCwFSM2ewICgnZxH4JF3f/F
+ j/e/YDc39799url5/41//xekJzKwHjks2N8t5teP/8smwD8CuV+/DgakpQ70N9vNDTNy
+ Lni46ZkgV07k3A72/5UzxAZi9wy0tUZku3hPoLuZ+R+s4RVqYIVgpC9kERyus4uRewZ5
+ BYdb2PyRJ8b66JohmBqRF3iG6f/l55yvm/FuzmgQeXNohJUtggUR3B0Waa2PYGRGQW9i
+ fWzs/9h89fDU+yOHYS+ygdFvG5iBHG60OxYjknN+vyCT3RiQsWBFYAL8gSeIAKFIGwgk
+ gSnQBXp/WkngBdwQTSSiCwN+4C2CA5AeQUifIATz/rHT/TeJwa9+3ki//+2RF5AQ24i/
+ x/w9Gi8y5l8+ycADwX/J3ZAxdnW70YW5kJP/GfMvi11/v6KRrpdelN76Kya0MFoWrYDW
+ QaujNdAqgBfNjGYHkmh5tDJaG62JVkN0KsAAvEE8e/8V467/gGavyOKgGFU7H0S7+9/d
+ /9ICu1/W5L9//1sEgDy03LL8VwQAhHtGI88BALpBwTGhZG+fcF5t5Mn13MNrFEjau4dX
+ VlpGZlf9/+bYXbN+B/vF6tdaBDE//kcW0AiAMhmZj87/yNxPAtAuiTz79f/IhAuRtcEX
+ gAFBUkRo5G9/6N0LBlABWmSGsgFuIABEkfssCxSBGtAC+sAYmAMb4ACckfnjg8zBUBAF
+ 4sFRkA6ywElwGpSAClAFakEDaAYtoAPcAffAABgG4+AFmAbzYAmsgO9gE4IgHESAiBAb
+ xAMJQRKQLKQMaUD6kClkBTlArpA3FAhFQPFQCpQF5UMl0HmoDroKtUF3oIfQCPQMmoEW
+ oc/QDxgFU8OMMBcsDEvByrA2bALbwIdhbzgEjoVT4Ry4GK6EL8M34TvwADwOT8NL8DcU
+ QOFRzCg+lCRKGaWLMkc5orxQoahEVCaqEFWJuoJqR91HjaGmUcuoDTQWTUTzoiWRebof
+ bYsmoUPQiehsdAm6Fn0T3YceQ8+gV9DbGAKGEyOBUcUYYQ5ivDFRmHRMIaYGcwNzFzOO
+ mcd8x2KxzFgRrBJ2P9YB64uNw2Zjz2Ibsd3YEewc9hsOh2PDSeDUceY4N1w4Lh13BncZ
+ dxs3ipvHrVPgKXgoZCkMKBwpAimSKQopLlF0UYxSvKPYpKSjFKJUpTSn9KCMocylrKZs
+ p3xMOU+5SUVPJUKlTmVD5Ut1lKqY6grVXaqXVF/weDw/XgVviSfjj+CL8U34B/gZ/AY1
+ A7U4tS61E3UEdQ71Repu6mfUXwgEgjBBi+BICCfkEOoIvYQpwjoNkWYvjRGNB00STSnN
+ TZpRmo+0lLRCtNq0zrSxtIW012gf0y7TUdIJ0+nSudEl0pXStdFN0n2jJ9LL0JvTB9Bn
+ 01+if0i/wIBjEGbQZ/BgSGWoYuhlmCOiiAJEXSKJmEKsJt4lzjNiGUUYjRh9GbMYGxiH
+ GFeYGJjkmeyYoplKmTqZpplRzMLMRsz+zLnMzcwTzD9YuFi0WTxZMliusIyyrLFysGqx
+ erJmsjayjrP+YONl02fzY8tja2F7xY5mF2e3ZI9iL2e/y77MwcihxkHiyORo5njOCXOK
+ c1pxxnFWcQ5yfuPi5jLkCuY6w9XLtczNzK3F7ctdwN3FvchD5NHgIfMU8Nzmec/LxKvN
+ 689bzNvHu8LHybefL4LvPN8Q3ya/CL8tfzJ/I/8rASoBZQEvgQKBHoEVQR7BA4LxgvWC
+ z4UohZSFfISKhO4LrQmLCNsLHxNuEV4QYRUxEokVqRd5KUoQ1RQNEa0UfSKGFVMW8xM7
+ KzYsDosriPuIl4o/loAlFCXIEmclRvZg9qjsCdxTuWdSklpSWzJSsl5yZi/zXtO9yXtb
+ 9n6UEpRylMqTui+1La0g7S9dLf1ChkHGWCZZpl3ms6y4LEm2VPaJHEHOQC5JrlVuVV5C
+ 3lO+XP6pAlHhgMIxhR6Fn4pKiqGKVxQXlQSVXJXKlCaVGZUtlLOVH6hgVHRUklQ6VDZU
+ FVXDVZtVP6lJqvmpXVJb2Ceyz3Nf9b45dX51N/Xz6tMavBquGuc0pjX5NN00KzVntQS0
+ PLRqtN5pi2n7al/W/qgjrROqc0NnTVdVN0G3Ww+lZ6iXqTekz6Bvq1+iP2XAb+BtUG+w
+ YqhgGGfYvR+z32R/3v5JIy4jklGd0YqxknGCcZ8JtYm1SYnJrKm4aahp+wH4gPGBUwde
+ mgmZBZq1mANzI/NT5q8sRCxCLG5ZYi0tLEst31rJWMVb3bcmWrtYX7L+bqNjk2vzwlbU
+ NsK2x47Wzsmuzm7NXs8+3376oNTBhIMDDuwOZIdWR5yjnWON47dD+odOH5p3UnBKd5o4
+ LHI4+vBDZ3Znf+dOF1oXN5drrhhXe9dLrltu5m6Vbt/cjdzL3FdIuqQi0pKHlkeBx6Kn
+ ume+5zsvda98rwVvde9T3os+mj6FPstkXXIJedV3v2+F75qfud9Fvx1/e//GAIoA14C2
+ QIZAv8C+IO6g6KCRYIng9ODpENWQ0yEroSahNWFQ2OGw1nBG5OVwMEI0Ii1iJlIjsjRy
+ Pcou6lo0fXRg9GCMeExGzLtYg9gLceg4UlxPPF/80fiZBO2E84lQontiT5JAUmrS/BHD
+ I7VHqY76HX2ULJ2cn/w1xT6lPZUr9UjqXJphWn06TXpo+uQxtWMVx9HHyceHMuQyzmRs
+ Z3pk9mdJZxVmbWWTsvtPyJwoPrGT45UzlKuYW34SezLw5ESeZl5tPn1+bP7cqQOnbhbw
+ FmQWfD3tcvphoXxhRRFVUUTRdLFpcesZwTMnz2yV+JSMl+qUNpZxlmWUrZ31ODtarlV+
+ pYKrIqvixznyuafnDc/frBSuLKzCVkVWva22q75/QflCXQ17TVbNz4uBF6drrWr76pTq
+ 6i5xXsqth+sj6hcvO10ebtBraL0ieeV8I3NjVhNoimh6f9X16kSzSXPPNeVrV64LXS+7
+ QbyReRO6GXNzpcWnZbrVoXWkzbitp12t/catvbcudvB1lHYydeZ2UXWldu3cjr39rTu4
+ e/mO9525HpeeF70He5/0WfYN3TW5++Cewb3e+9r3bz9Qf9DxUPVhW79yf8uA4sDNQYXB
+ G48UHt0YUhy6+VjpceuwynD7yL6RrlHN0TtjemP3nhg9GRg3Gx+ZsJ14Ouk0Of3U4+nC
+ M/9nq88jn2++OPIS8zLzFd2rwinOqcrXYq8bpxWnO2f0ZgZnrWdfzJHmlt6EvdmaT31L
+ eFv4judd3YLsQseiweLw+0Pv55eClzaX0z/Qfyj7KPrx+ietT4MrB1fmV0NXdz5nf2H7
+ cvGr/Neebxbfpr4HfN9cy1xnW6/dUN64/8P+x7vNqC3cVvFPsZ/t2ybbL3cCdnaC3ULd
+ fr0LoJAW9vIC4PNF5D3BAakdhgGgovldU/yyQMoVCLFBsB20F1qCz6Kc0ULo95hubDEu
+ mMKKUp9KES9FvZcgQaNMa0LnSh/BcJrYxjjDTM2izRrK1sC+xCnG5cvdxLPOp8d/UmBW
+ SEb4mMgrMQXxkxLLkvp7q6S2ZZxk2+XZFaIVx5XlVHJUl/cZqp/T+KFlpX1BZ0PPRL/E
+ YGG/vFGccZcpdEDLLNa8yWLOit5a3cbDNs3unP21g7cdeh27D7U5NR6ucS5zOema7Bbi
+ 7kwy9VDy5PcieK15z/j0k5t9S/yS/ckBFoEKQSxBa8FjIfWhSWHm4TzhnyK6InOinKIl
+ on/E9MeWxJHjlROwCWOJFUn+R3SOCiYzptCm0qXRp9MdIxynzEBn7GRuZH3OXjoxm/M8
+ d/TkQF5PftupKwVVp88U5hSlFMediSlJLi0uu3F2uHy2YvncyvmVypWqT9UfL3yoWbq4
+ UPumbubSXP1qA/0V3cbEpparr5vXr+NuEG/ytIi3KrRpthvdsu5w74zuKr59p3uhB91L
+ 7GO/y3tP/L7SA52HOv2i/Z8GMgfZBs8/0ny0PNTwOHRYZQQaeTRaPhbyRH+cbfzjRO9k
+ 0VOfZ4rPdp53v4h9Kfdy+VXDVNjrfdPY6dGZslmvOZm5zTf35gveer5TXWBYeL/Y9T57
+ yX6Zb3nxw9WPsZ90VvAr46sNn8u/XP+69t1r7fmG1o+CzemfctsFOzu/8i8ANcEOKAbU
+ A3Q6xgTLhH2Fu0aRTelPZYvXo5YjiNEI0YrSSdErMBgQ7RgDmVKZq1j6WJfY6Tk0OMlc
+ JdyDPDt8yvzhAlcE3wtLiPiI1ootSUjuCZW8sXdDWlPmqOx9ebyCqWKO0ogKUdVCLWdf
+ vwZWU1MrUrtW54UeXl/VwN0wY3+90YDxoil8gMVMxFzOQtVS1UrOWtCGxuab7XO7bvvq
+ g5kOgY7Wh5ScOJx2Ds8697nUuKa7ebhrkThJax4jnvVead7OPkpkOvKC722/Iv/AAP1A
+ 9sAPQbeDc0IcQ/lDF8OawqMiVCN+RnZFJUVrxaBjHsSeiLOIJ8aPJxQlHkJW1pUjvUcr
+ klNSAlMd0wzT5Y/xHac+vpYxmzmYdTP73InjOaG5h0+a5mnmK5zaWyB6mr+Qs4ilmP4M
+ VQm6ZKv0a9nS2enyyYqRc8PnxytfVy1Vr9egLtLUstUJXpKu33fZoMH8ikOjZ1Pk1ezm
+ 2mt916durLZArXRtfO1ytww6DnUGd6XfLu2uu9PQU917si/8rs092fv091cfPEHWpoqB
+ tEG/R5ZDyo/5hvHD6yNzo4/Gmp8UjSdMkCZNnso/43qOeb784snLW6+qpk68jp8OnvGb
+ DZgLf5Mwn/42713pwoXFpvftS73Ljz68+Li+orJa/UXnG/771/WFH6NbldsOf/LPCZ2A
+ ReEBVACaAz2AScZqYNdxnRTHKB2o5PA0+AXqh4RrNOW0J+hS6GMZIokxjDFMCczpLLms
+ Z9ka2fs4nnJ+5CbwCPLq8LnypwhUCd4VWhShEZURsxWPk6jY0ye5KEUvrSTjKBsnVy5/
+ W2FKcVuZQ0VF1UqNvC9RPU+jSvOqVof2XZ1+3UG9Af37BrcNr+2vNMo0DjQxMeU1/Xrg
+ nlmROdlCxRJnOWF1wTrMRsuW2nbSrto++KCaA9Zh2LHkkKfTXqfvh7uc013MXImuk24l
+ yDrBQ5r2OOfp6sXj9dr7nI8rmYc85XvWz8Gf6D8UkBGoHwQF3QoODxEJeRp6PEwp7F14
+ YYRexOfIc1FmUZvRdTF2sXBsY9yheEx8U8KhRExiU5LzEcYjI0cLkz1TlFNpUufTOtML
+ jvkd185gyfiQeSerINvrhFIOVc50buvJ/LzQfOtTCgVsBdun3xT2FzUWnzoTWeJQqlrG
+ juyW4+U3KkrPnTifXplalVZ97MKxmrSLCbUBdQcv6derXVZvMLni1hjfVHz1evOja/PX
+ N2/Stwi37muzbPe+ldhxuvNSV8ft+939dx723O2909d5t/XetfsNDy4+rOg/M5A/mP0o
+ fSjlcdpw3kjt6MOx1XGuCaPJyKeVz4aeb7wUfGU9lft6eoY8x/rm2zvMYuJy7+qpdcHd
+ /P/mlnb3BKwiADUI72F3BABLRFNrCYBQAUJxtAFgQQDARgXAfmkApl8CUJno3/sHBNAI
+ A0eHVJwCQAqoI8zGIYRLSAT5oAbcAiNgEakX2SF5yBzyg45BF6BeaBaGYQFYH6n0suBG
+ +An8A6nn9qNCUCWoPtQnZA4aoiPQVegxDAojj1RkJZghLAqrgg3G1mJncZy4g7gC3CgF
+ PYUlxSmKcUo2ShfKGsqPVMpUKVTDeG58IL6bmpHal/oOgYMQRRinUaQ5Q7ND6007SqdN
+ d41enL6GQYShkahGHGR0YfzKdIJZnHmAJZiVhbWXLYSdn32C4wTnfi4s1z3uTB5LXk7e
+ D3x9/FUCWYKxQgHCHiIuos5iruKeEgF7YiQz9pZLtUtPyryX/Sj3Rv6JQq/iTaUrypdU
+ 6lQvqTXta1Xv0xjTnNfa0KHVFdMz0Pc2yDK8uv+FMc5E1tT+QKhZinmuRblli9ULG0pb
+ DbsoZL/77Ch/KNrpjjPBxcm1zm2ZxOWh6WnvFeB93KeZ/MFPyT8j4HWQYvDJkI/I/tYc
+ yRQVHt0fyxLnHF+bsJPkc2Qm2S3ldZpD+vhxh4ytrIWcnLyzBeyFxsXBJcVlreVD52Yq
+ v1+guShWZ1If3dDexN1ceUOipbxtp8Op69Yd3t7MuxsPfPrHHsk/zhqZe3JgYuiZ64uN
+ qaIZ5bnXb1MXNpf4l7c/Vq8IrlZ8Yfta+V1j7d1G8abO1tR26K/1A0I4BzwgAi6EgVVC
+ +B57QEZYhTxwEXSBCfAJokI4Ah3IBUqEyqEuaBrJvTBsDAfDhXAX/BZFh1JFeaLyULdR
+ H9Cc6ANIhX4V/QbDhjHDpGE6kepbGuuP5P0tTgjnhavFLVFIUURQdFJiKS0oz1K+p1Kl
+ yqJ6jZfHZ+HfUGtSn6X+SXAl3KWRpCmixdBG0i7Rkeim6d3p3zPEEGmJlxgNGReYsphl
+ mJ+zpLPKs75lK2W34aDjGOUs5nLnluIBPOO8DXwZ/N4CxoIyQhzCFMKbIl9Fv4ptSRD2
+ CEhq7HWVypBuk3kvxylvoZClOKhMr2KvekZtTB3SENY00PLSPq7ToDuuDxvIGnrtP2s0
+ acJsaneg0GzMgsbS0CrJut1mzU7RPvpgpyPmkIVTxeHPLsau1W4/SZbIOvXeW84ngTzg
+ x+UfEnAviCs4MmQsTD68KGIryiW6K5Y1LjD+XqJAUuaR9WTflFdpFum9x5UyGrL4s0ty
+ WHIr8lTzPxS0FhYVJ5eElLmUG5+Tr+Spprmwc/Fz3dv6pw0PGjuutl27c+Nxy6u2pVsb
+ XVTdvD2qfQfvxTwo7W8fHB56Mfx0dPBJx8Tlp2ef5708NpU0HTMb9Sb6bdxC9PvDy8wf
+ aj6xrJBXqz6Pf1n7xvJdbs1iPWzjzI9HW7ifltvVf/KPBQTAgjz9MkAH4Zd8QAIoQDik
+ +2AW7EBc0D7oMJL789A95C2TAVaFSfAJuBWeRxFR2ghzU4WaQFMi7GIE+jJ6HsODOYQp
+ xkwgjIs9tgQ7hRPA+eKu4bYpjCmKKRYQxuQE5RyS8wKqFbw5vomaSB1DPUswI3TSSNNc
+ oOWhLaPjpqtGeIs+BhcijOTbngnHdIs5nEWaZYX1OlsCuxEHK8cyZx/XOe4kHhKvKZ8K
+ v7gAnyCPEJ+wmIiiqJGYi3iMRNGedslZKQZpY5l02V55jIKlYoMyUSVJdXUfWX1B01/r
+ u066Hqd+u6GLEd64w5RshjHPsgRWQdavbM3sepA9qfWQilO3s5nLjFs0idajykveu5ts
+ 4jvpTwpYDToawhTaGH4gYiXqTIxxHBTfmkhK2j6ak8KaWpkueawzwyZzPftKTuBJ8byx
+ U74FXwojir6diSrZKksvZ6yoOa9WOVYdUEN1sbZu/6XFy9lX5BvfXD1/zf+GXgt/G7p9
+ sWOkq7O7oaeyr+RewYO8/tzB3KGs4YRR5yfS498mm58FvBB7+XbqwrTXrPjc6nzHu7RF
+ vfery8c/fP5ktJK92vL51Zflrxvf5r4/XMtf37f+diN1Y+NH4I+5zYObt7cYt8hbXT8Z
+ f5J/dm1TbFtsF2+/3hHZCdpp2c1/mJec7O7uASBqHYR+nNrZ+SIMAC4fgJ95OzublTs7
+ P6uQYgP5BtLt//t7xa4xFuHcy27tov90/A/oHZP+CmVuZHN0cmVhbQplbmRvYmoKNDQg
+ MCBvYmoKNTk1MwplbmRvYmoKMzYgMCBvYmoKWyAvSUNDQmFzZWQgNDMgMCBSIF0KZW5k
+ b2JqCjQ1IDAgb2JqCjw8IC9MZW5ndGggNDYgMCBSIC9OIDMgL0FsdGVybmF0ZSAvRGV2
+ aWNlUkdCIC9GaWx0ZXIgL0ZsYXRlRGVjb2RlID4+CnN0cmVhbQp4AYVUz2sTQRT+Nm6p
+ 0CIIWmsOsniQIklZq2hF1Db9EWJrDNsftkWQZDNJ1m426+4mtaWI5OLRKt5F7aEH/4Ae
+ evBkL0qFWkUo3qsoYqEXLfHNbky2perAzn7z3jfvfW923wANctI09YAE5A3HUqIRaWx8
+ Qmr8iACOoglBNCVV2+xOJAZBg3P5e+fYeg+BW1bDe/t3snetmtK2mgeE/UDgR5rZKrDv
+ F3EKWRICiDzfoSnHdAjf49jy7I85Tnl4wbUPKz3EWSJ8QDUtzn9NuFPNJdNAg0g4lPVx
+ Uj6c14uU1x0HaW5mxsgQvU+QprvM7qtioZxO9g6QvZ30fk6z3j7CIcILGa0/RriNnvWM
+ 1T/iYeGk5sSGPRwYNfT4YBW3Gqn4NcIUXxBNJ6JUcdkuDfGYrv1W8kqCcJA4ymRhgHNa
+ SE/XTG74uocFfSbXE6/id1ZR4XmPE2fe1N3vRdoCrzAOHQwaDJoNSFAQRQRhmLBQQIY8
+ GjE0snI/I6sGG5N7MnUkart0YkSxQXs23D23UaTdPP4oInGUQ7UIkvxB/iqvyU/lefnL
+ XLDYVveUrZuauvLgO8XlmbkaHtfTyONzTV58ldR2k1dHlqx5erya7Bo/7FeXMeaCNY/E
+ c7D78S1flcyXKYwUxeNV8+pLhHVaMTffn2x/Oz3iLs8utdZzrYmLN1abl2f9akj77qq8
+ k+ZV+U9e9fH8Z83EY+IpMSZ2iuchiZfFLvGS2EurC+JgbccInZWGKdJtkfok1WBgmrz1
+ L10/W3i9Rn8M9VGUGczSVIn3f8IqZDSduQ5v+o/bx/wX5PeK558oAi9s4MiZum1Tce8Q
+ oWWlbnOuAhe/0X3wtm5ro344/ARYPKsWrVI1nyC8ARx2h3oe6CmY05aWzTlShyyfk7rp
+ ymJSzFDbQ1JS1yXXZUsWs5lVYul22JnTHW4coTlC98SnSmWT+q/xEbD9sFL5+axS2X5O
+ GtaBl/pvwLz9RQplbmRzdHJlYW0KZW5kb2JqCjQ2IDAgb2JqCjczNwplbmRvYmoKOCAw
+ IG9iagpbIC9JQ0NCYXNlZCA0NSAwIFIgXQplbmRvYmoKNDcgMCBvYmoKPDwgL0xlbmd0
+ aCA0OCAwIFIgL04gMSAvQWx0ZXJuYXRlIC9EZXZpY2VHcmF5IC9GaWx0ZXIgL0ZsYXRl
+ RGVjb2RlID4+CnN0cmVhbQp4AYVST0gUURz+zTYShIhBhXiIdwoJlSmsrKDadnVZlW1b
+ ldKiGGffuqOzM9Ob2TXFkwRdojx1D6JjdOzQoZuXosCsS9cgqSAIPHXo+83s6iiEb3k7
+ 3/v9/X7fe0RtnabvOylBVHNDlSulp25OTYuDHylFHdROWKYV+OlicYyx67mSv7vX1mfS
+ 2LLex7V2+/Y9tZVlYCHqLba3EPohkWYAH5mfKGWAs8Adlq/YPgE8WA6sGvAjogMPmrkw
+ 09GcdKWyLZFT5qIoKq9iO0mu+/m5xr6LtYmD/lyPZtaOvbPqqtFM1LT3RKG8D65EGc9f
+ VPZsNRSnDeOcSEMaKfKu1d8rTMcRkSsQSgZSNWS5n2pOnXXgdRi7XbqT4/j2EKU+yWCo
+ ibXpspkdhX0AdirL7BDwBejxsmIP54F7Yf9bUcOTwCdhP2SHedatH/YXrlPge4Q9NeDO
+ FK7F8dqKH14tAUP3VCNojHNNxNPXOXOkiO8x1BmY90Y5pgsxd5aqEzeAO2EfWapmCrFd
+ +67qJe57AnfT4zvRmzkLXKAcSXKxFdkU0DwJWBR9i7BJDjw+zh5V4HeomMAcuYnczSj3
+ HtURG2ejUoFWeo1Xxk/jufHF+GVsGM+Afqx213t8/+njFXXXtj48+Y163DmuvZ0bVWFW
+ cWUL3f/HMoSP2Sc5psHToVlYa9h25A+azEywDCjEfwU+l/qSE1Xc1e7tuEUSzFA+LGwl
+ uktUbinU6j2DSqwcK9gAdnCSxCxaHLhTa7o5eHfYInpt+U1XsuuG/vr2evva8h5tyqgp
+ KBPNs0RmlLFbo+TdeNv9ZpERnzg6vue9ilrJ/klFED+FOVoq8hRV9FZQ1sRvZw5+G7Z+
+ XD+l5/VB/TwJPa2f0a/ooxG+DHRJz8JzUR+jSfCwaSHiEqCKgzPUTlRjjQPiKfHytFtk
+ kf0PQBn9ZgplbmRzdHJlYW0KZW5kb2JqCjQ4IDAgb2JqCjcwNAplbmRvYmoKMTYgMCBv
+ YmoKWyAvSUNDQmFzZWQgNDcgMCBSIF0KZW5kb2JqCjQgMCBvYmoKPDwgL1R5cGUgL1Bh
+ Z2VzIC9NZWRpYUJveCBbMCAwIDYxMiA3OTJdIC9Db3VudCAxIC9LaWRzIFsgMyAwIFIg
+ XSA+PgplbmRvYmoKNDkgMCBvYmoKPDwgL1R5cGUgL0NhdGFsb2cgL091dGxpbmVzIDIg
+ MCBSIC9QYWdlcyA0IDAgUiAvVmVyc2lvbiAvMS40ID4+CmVuZG9iagozNSAwIG9iago8
+ PCAvTGVuZ3RoIDUwIDAgUiAvT3JkZXIgMSAvRW5jb2RlIFsgMCAxMzY0IF0gL0Z1bmN0
+ aW9uVHlwZSAwIC9CaXRzUGVyU2FtcGxlCjggL0RlY29kZSBbIDAgMSAwIDEgMCAxIF0g
+ L0RvbWFpbiBbIDAgMSBdIC9SYW5nZSBbIDAgMSAwIDEgMCAxIF0gL1NpemUgWyAxMzY1
+ Cl0gL0ZpbHRlciAvRmxhdGVEZWNvZGUgPj4Kc3RyZWFtCngBtcKJVgFRAADQ7zL76kuz
+ RZbIIJJ1BqGUypItSynCF3Tq5DijMebNvHfPLW3spWOVjR342q4YLSprVXktHrkSZXiL
+ K1H1SywiuhSLS7EAuVBY/l4IBa35hQDhp5A3NvcpgP0QchZmPwS9cyGrl8/OwWbm/O47
+ n0H3jc+88dcozvjrw9Mz3nAuPft3yqVBXk05gBPuytrUhNM+5lIIJsfcz1fNbPIVxhGb
+ 3L4csTAP2UvdiSFr/oBNAI4P2G0mPtDdZ+KWx/qMxh4TQ1PqMdILyl1G+ktLXToKd4eO
+ 6r7o0Ca36QvwkTZtaIuOAKcirf3hFqXxmQqjef5EIfxInauHHilom2To2GCTNPOBDJoa
+ eCCPvycDkPrvyf0N0m8o4W8AP7sjUL0lzrT6bgkI64TPWG+dMBb31rdruNfs0xqut4qf
+ Qu2p4rs3uAfdCu6p4O6DMXfF7DLmPtBVxqwuYS7DnSUMrII5LXQo2LbNoajLNgfsJ7Lt
+ b9F2AvIbCq+1owplbmRzdHJlYW0KZW5kb2JqCjUwIDAgb2JqCjM4NAplbmRvYmoKMzQg
+ MCBvYmoKPDwgL0xlbmd0aCA1MSAwIFIgL09yZGVyIDEgL0VuY29kZSBbIDAgMTM2NCBd
+ IC9GdW5jdGlvblR5cGUgMCAvQml0c1BlclNhbXBsZQo4IC9EZWNvZGUgWyAwIDEgMCAx
+ IDAgMSBdIC9Eb21haW4gWyAwIDEgXSAvUmFuZ2UgWyAwIDEgMCAxIDAgMSBdIC9TaXpl
+ IFsgMTM2NQpdIC9GaWx0ZXIgL0ZsYXRlRGVjb2RlID4+CnN0cmVhbQp4AY3CCTdUcRgH
+ 4C8mEolEIpGSkpKSEolEIhljxqxmDGNm7Pu+71tf6/29neuY073jf+99n/Pw3wTbjPOl
+ cIwvTV7E2HCMLySjfKF7HmXTo3wuOcJnwhE+M3kaYcNhPpUM86nuSZhNh/hE8DjEx0Oy
+ QT42eRRkwwAfCfv5KPnQz6Z9fCh44OMDr7iHD1T3PWw4yPvCbt5P3nOzVRfvXceeS33X
+ hd0BcSd2VXecSN2PHUkHdq5uO2CzD9t2t/qg/SPbiy3VzV6k/o1N4R5s9mDDdjc27K53
+ Q/tLtgvrqmtdSP0Ta8KdWOvEqu0OrNpd6YD2h3g7Vm5cbkfq71gWbsNyG5YkW7FkebEV
+ 2m/iLVg0XmiB+lcsSDZjoRnzkk2YtzzXhOtfMCfZiDnj2Uaof8as8CfMSDZgxvJ0A65/
+ xLRwPaZ1p+qh/gFTwu8xKVmHSfMTdfj/HSaEazGhO14L9bcYF36DhHANEoqUqKG4/muK
+ C1dTXDdWTaZfUUzyJY0JV9GYyWgVGb6gqGQlRXVHK8n0cxqVHXlGohU0YjJSQYZPKSJc
+ TpHk4XIyXUbDguEyCj8RL6WwaqiUDB9TSLiEQslDJWS1mIbsBosp+Ei8iIKqgSIyfEgB
+ 4UIKJPsLyWoB+e36Csj3QDyffKrefEp9n7ySeeS96skjm7nksTuYS9p7sjk0qOrOodR3
+ yS2cTe5sctnOIpfdgSzS3hHPpIEbnZmU+jY5hTPImUH9kunUb9mRTtpb4mnkSPsHinMK
+ nAplbmRzdHJlYW0KZW5kb2JqCjUxIDAgb2JqCjU3MgplbmRvYmoKMzMgMCBvYmoKPDwg
+ L0xlbmd0aCA1MiAwIFIgL09yZGVyIDEgL0VuY29kZSBbIDAgMTM2NCBdIC9GdW5jdGlv
+ blR5cGUgMCAvQml0c1BlclNhbXBsZQo4IC9EZWNvZGUgWyAwIDEgMCAxIDAgMSBdIC9E
+ b21haW4gWyAwIDEgXSAvUmFuZ2UgWyAwIDEgMCAxIDAgMSBdIC9TaXplIFsgMTM2NQpd
+ IC9GaWx0ZXIgL0ZsYXRlRGVjb2RlID4+CnN0cmVhbQp4AaXChVJCUQBAwb+2u7u7sekG
+ FQMDW7ED61OOMTL48MWNnU1+kLSY+OD7u+L4O8XfiAuPvWH3lZjt6CsSX4gaR15QnCOS
+ I6w9lCP0rD74jOETQZmBJ+w+ErDtf0T0A/5/fQ+ovMf303uPZs8dOt13GN7ilrl6i+Ub
+ Vp2u3CD0mhWzy9dIv2I5f+kKzYtZdC5kKbxkQfL8JeYvmBfoukDoOS6zc+dIP2Muf/YM
+ rafM6J0+5fcJ0/KnTjB/zJTAyWOcHzFpceIIuYdM/Dl+iPoM4xnG9I5m+H3AqPyRA0zu
+ MyJ2eB+HewxbH9pD4i5DxoO7qE8zmGZAb3+a7zuK+3Yovk2f8N5tHG7Ra71nC4mb9Bh3
+ b6I4RffPrhQ6O1N0bqjv2KD4Oh3C29exu0a77bY1RCdp+7c1icoErfktCXQ2J2iOq2+K
+ YxijSWZjDMtRGp02RBEaocFsfQSVYerz68LorA2hsyZEYZAaydVBLAeodloVQKifKrOV
+ fqT7qPyzwod6L+V6y7wUeiiTXOrBvJtSgSVuvn4CXuWIVQplbmRzdHJlYW0KZW5kb2Jq
+ CjUyIDAgb2JqCjQxMAplbmRvYmoKMzIgMCBvYmoKPDwgL0xlbmd0aCA1MyAwIFIgL09y
+ ZGVyIDEgL0VuY29kZSBbIDAgMTM2NCBdIC9GdW5jdGlvblR5cGUgMCAvQml0c1BlclNh
+ bXBsZQo4IC9EZWNvZGUgWyAwIDEgMCAxIDAgMSBdIC9Eb21haW4gWyAwIDEgXSAvUmFu
+ Z2UgWyAwIDEgMCAxIDAgMSBdIC9TaXplIFsgMTM2NQpdIC9GaWx0ZXIgL0ZsYXRlRGVj
+ b2RlID4+CnN0cmVhbQp4Aa3BBwKBAABA0ftfSTRUtDWMFu00dQV34L+3bT/6bB/OylmW
+ daHMy8yZpnmijNPIGUDv4c3pQV3fUdqu5TRN21DqpuZUVV1RyqrkFKBX8eI8Qfkzp2R5
+ xknTLKUkacKJ4ySmPOIH5w663W+cKyi6RpQwCjlBEAYUP/A5F5B38TguyHEdjg2ybIti
+ WibIMA3K2ThzTiD9pHM0kKqpnCNIOSoUWZFBkixRREnkHED7w54jgHbC7n9fqv5GzApl
+ bmRzdHJlYW0KZW5kb2JqCjUzIDAgb2JqCjE4OAplbmRvYmoKMzEgMCBvYmoKPDwgL0xl
+ bmd0aCA1NCAwIFIgL09yZGVyIDEgL0VuY29kZSBbIDAgMTM2NCBdIC9GdW5jdGlvblR5
+ cGUgMCAvQml0c1BlclNhbXBsZQo4IC9EZWNvZGUgWyAwIDEgMCAxIDAgMSBdIC9Eb21h
+ aW4gWyAwIDEgXSAvUmFuZ2UgWyAwIDEgMCAxIDAgMSBdIC9TaXplIFsgMTM2NQpdIC9G
+ aWx0ZXIgL0ZsYXRlRGVjb2RlID4+CnN0cmVhbQp4AbXCiVYBUQAA0O8y++pLs0WWyCCS
+ dQahlMqSLUspwhd06uQ4ozHmzbx3zy1t7KVjlY0d+NquGC0qa1V5LR65EmV4iytR9Uss
+ IroUi0uxALlQWP5eCAWt+YUA4aeQNzb3KYD9EHIWZj8EvXMhq5fPzsFm5vzuO59B943P
+ vPHXKM7468PTM95wLj37d8qlQV5NOYAT7sra1ITTPuZSCCbH3M9XzWzyFcYRm9y+HLEw
+ D9lL3Ykha/6ATQCOD9htJj7Q3Wfilsf6jMYeE0NT6jHSC8pdRvpLS106CneHjuq+6NAm
+ t+kL8JE2bWiLjgCnIq394Ral8ZkKo3n+RCH8SJ2rhx4paJtk6NhgkzTzgQyaGnggj78n
+ A5D678n9DdJvKOFvAD+7I1C9Jc60+m4JCOuEz1hvnTAW99a3a7jX7NMarreKn0LtqeK7
+ N7gH3QruqeDugzF3xewy5j7QVcasLmEuw50lDKyCOS10KNi2zaGoyzYH7Cey7W/RdgLy
+ GwqvtaMKZW5kc3RyZWFtCmVuZG9iago1NCAwIG9iagozODQKZW5kb2JqCjMwIDAgb2Jq
+ Cjw8IC9MZW5ndGggNTUgMCBSIC9PcmRlciAxIC9FbmNvZGUgWyAwIDEzNjQgXSAvRnVu
+ Y3Rpb25UeXBlIDAgL0JpdHNQZXJTYW1wbGUKOCAvRGVjb2RlIFsgMCAxIDAgMSAwIDEg
+ XSAvRG9tYWluIFsgMCAxIF0gL1JhbmdlIFsgMCAxIDAgMSAwIDEgXSAvU2l6ZSBbIDEz
+ NjUKXSAvRmlsdGVyIC9GbGF0ZURlY29kZSA+PgpzdHJlYW0KeAGlwoVSQlEAQMG/tru7
+ u7HpBhUDA1uxA+tTjjEy+PDFjZ1NfpC0mPjg+7vi+DvF34gLj71h95WY7egrEl+IGkde
+ UJwjkiOsPZQj9Kw++IzhE0GZgSfsPhKw7X9E9AP+f30PqLzH99N7j2bPHTrddxje4pa5
+ eovlG1adrtwg9JoVs8vXSL9iOX/pCs2LWXQuZCm8ZEHy/CXmL5gX6LpA6Dkus3PnSD9j
+ Ln/2DK2nzOidPuX3CdPyp04wf8yUwMljnB8xaXHiCLmHTPw5foj6DOMZxvSOZvh9wKj8
+ kQNM7jMidngfh3sMWx/aQ+IuQ8aDu6hPM5hmQG9/mu87ivt2KL5Nn/DebRxu0Wu9ZwuJ
+ m/QYd2+iOEX3z64UOjtTdG6o79ig+DodwtvXsbtGu+22NUQnafu3NYnKBK35LQl0Nido
+ jqtvimMYo0lmYwzLURqdNkQRGqHBbH0ElWHq8+vC6KwNobMmRGGQGsnVQSwHqHZaFUCo
+ nyqzlX6k+6j8s8KHei/lesu8FHook1zqwbybUoElbr5+Al7liFUKZW5kc3RyZWFtCmVu
+ ZG9iago1NSAwIG9iago0MTAKZW5kb2JqCjI5IDAgb2JqCjw8IC9MZW5ndGggNTYgMCBS
+ IC9PcmRlciAxIC9FbmNvZGUgWyAwIDEzNjQgXSAvRnVuY3Rpb25UeXBlIDAgL0JpdHNQ
+ ZXJTYW1wbGUKOCAvRGVjb2RlIFsgMCAxIDAgMSAwIDEgXSAvRG9tYWluIFsgMCAxIF0g
+ L1JhbmdlIFsgMCAxIDAgMSAwIDEgXSAvU2l6ZSBbIDEzNjUKXSAvRmlsdGVyIC9GbGF0
+ ZURlY29kZSA+PgpzdHJlYW0KeAGtwQcCgQAAQNH7X0k0VLQ1jBbtNHUFd+C/t20/+mwf
+ zspZlnWhzMvMmaZ5oozTyBlA7+HN6UFd31HaruU0TdtQ6qbmVFVdUcqq5BSgV/HiPEH5
+ M6dkecZJ0yylJGnCieMkpjziB+cOut1vnCsoukaUMAo5QRAGFD/wOReQd/E4LshxHY4N
+ smyLYlomyDANytk4c04g/aRzNJCqqZwjSDkqFFmRQZIsUURJ5BxA+8OeI4B2wu5/X6r+
+ RswKZW5kc3RyZWFtCmVuZG9iago1NiAwIG9iagoxODgKZW5kb2JqCjIgMCBvYmoKPDwg
+ L0xhc3QgNTcgMCBSIC9GaXJzdCA1OCAwIFIgPj4KZW5kb2JqCjU4IDAgb2JqCjw8IC9Q
+ YXJlbnQgNTkgMCBSIC9Db3VudCAwIC9EZXN0IFsgMyAwIFIgL1hZWiAwIDczMyAwIF0g
+ L1RpdGxlIChDYW52YXMgMSkKPj4KZW5kb2JqCjU5IDAgb2JqCjw8ID4+CmVuZG9iago1
+ NyAwIG9iago8PCAvUGFyZW50IDU5IDAgUiAvQ291bnQgMCAvRGVzdCBbIDMgMCBSIC9Y
+ WVogMCA3MzMgMCBdIC9UaXRsZSAoQ2FudmFzIDEpCj4+CmVuZG9iago2MCAwIG9iago8
+ PCAvTGVuZ3RoIDYxIDAgUiAvTGVuZ3RoMSAxMDM5MiAvRmlsdGVyIC9GbGF0ZURlY29k
+ ZSA+PgpzdHJlYW0KeAG9Wnl4U9eVP/e+VZstydoXS0KWZHlfwNjYYMXYxiw2ZglYNAbb
+ YDAEJ0DALFOok0AAh5AQwhJI05IFDJQgjBtEKAzNmJJMM03SoSSl6bSZkjbTL/7SmSFt
+ B5A05z0ZB/y1+fJHvr6nc/fl3N8999xz79PqVWvaQQPdwEDjvNYVi0F+/H8CIL0LO1tX
+ JONpIvrvLOxa7U7GuUwAZvniFUs6k3HxOQClc8ny9UP1DZis7+5ob12UzIfb6Jd0YEIy
+ Tkajn9HRuXpdMq7vR3/28ocXDuWnXcF4TmfruqH+4SOMux9q7WxPlve/g37GiocfWT0U
+ 70Z/2opV7UPlSRPy9y4QTDXCw6CAB0EAClp8mwGET5VOYDFXysdnUY5q94LUii9AJw0T
+ YEH907L/E8+Prv61/XZAtUv8P0xQ3Ckv+XwwHgRQE8wfVO0azpHroWOMwqzsKExGqkQa
+ g5SdfZ8FuslheAbp+0gMLCVPwnqk7UjPI7HDoaMYO0ue7GPF0BtkPdjIlJCKdc02WF0W
+ pcr18yjh+190/dLyu3PEirP3MbH2aUBxn5J8n3wPFoGLvAo+sgHqIJMcOB1c7mrBrKOw
+ AqkbiZFdQo72pRe5LpAc8LEE6/ghnSWvu/5QmOv6pDBKSZ/rzUCURe/H6RgLpbouOl90
+ /bNziesC0vFk1rEglnjdddS53LU7PUoO9LmedUYJ1tmV9NY4serrrs7gXteiQjl/2t4o
+ Pd7nKsP8OSGVq6TU4xrjvO7KD0RFgvFc5zRXVuG/uTKwIhZzY6O+kM7lcO52jcOsdGdN
+ YBzSOXKMHIQscrDPN8X1BgZxuKcnB0v3Rsk/na7LLPRFyYZQSV3m3mBdwBec5vIFawMB
+ DM95S9gsfEu4TygSsoVMwS94BLtgEPWiVkwR1aJSFEUhSn7QV+niz5HjUImwHD8t8iIX
+ Ja9hInuOnJATT5wRWZGKIBqiid+i8BIwRMnxfq0UwsDrvBzio+TE6WTSiZCLlUKsnKGl
+ UhgddIESkcIUiJCnojxsMXVVWir1E3RltdV/z2mRc+642X//sRBnZO/UWU2RY85wpEgK
+ JJzhO8UtdwJ/11+9BrPaq7Kzp85cf7prxbLFNe3emhZvTTtSS+TJrg5LpLvN7T61bIWU
+ 4Y4w/pa2hR2S39oeWeFtr44s81a7T3XJ9UZkL5ayu7zVp2BxzeymU4tD7dV9XaGuGm9r
+ dfh0W9Wq5nv62j7c16qqv9FXldTYKqmvNrneiL6apew2qa9mqa9mqa+2UJvclzT4mqWz
+ qh5ZjdLprlk61R3JnBWZPGNeU8TdGq6OksOYWL0GuIug5c5DJtcNNjYfXACJXyJdk/z4
+ /Ynfc5dBG+9M/DdTjpN6ViIar6yAi/AUHISTwEMvhjNhPuyHt8kyXNsPQD9cJemQh7qX
+ hShMg3dIIvE+LIZXsPxqeBP2wClQY51O1GHTYCfxJTZgPIThNticeAkyoBSegPNQhq3u
+ hMHE0cRpzJ0J98MxOI71f0q89BSblngtcR1EmIFtbsac9xPTEidBDzlQBY2YuhkuEB9z
+ LdEBFihH7l6A78Eh+DF8Rh4j/YmORFfivcTHKKoWcMAsfDeSfvIxc5J9IvFC4o+JOCKR
+ CVnYawvshpex/ZP4XkTVWkMeJKvJbrKHhuhjtJ/dwpnjMcQhCJPwrUOtvA0ROAsD8D/w
+ f+RzamG0zGrmUmJM4n9BBVNxlNJI2qEL36347sQxnSM8KSATSSPZSJ4je8i/0yx6P22i
+ a+k6+numgXmAWc/8O/sI28ft4PbzqvgXiXOJy4lfgBmc8C1YBZtwdG/Ce3ADbhIG23IQ
+ HyknVWQ+vt3kID1LDpGztJFcJO/RY+Q35Hfkc3KLclRNjTSbrqa76XH6Jv0Zs5TZwzzP
+ /Ib5gp3AUe4Q9wnvE34Vb4tvj/8sUZ74OPFXVLEieHBmqqABFkArjnYFjIbv4ChO4HsS
+ Z20ALsHb8vs74oBB+CuiAERPbKSI1OPbQKaTxWQpeZG8ge8FmZc/U5wIqqA6aqYOOou2
+ 0U7aTX9Buxk7k8VMYeYxJ/F9i7nK3GJusRybxhrZSexk2MF2sgfwPcz2sn3su1wZN4Fr
+ 4OZw3dx2bgezkHufu8pv4nfyffzn/J9QLU4THhZ24Oy8jTL7Y5TlLx+WZCD3RfAQLCTV
+ pA324mwcIq3Qg9K1iGxDvFZAZqKZ2cRMogUoDRfgn1BaD8BG2M48AIcSHzLH4AOUlOXY
+ ZDccYavAye3D2XkMClCKht5QMCuYGfD7MryjPG5U+Q67zWoxm4yGNL1Oq1GrlApR4DmW
+ oQRyary1Le6IvyXC+r11dblS3NuKCa13JbTgUnZHau8tE3FL9Vox656SISy5eETJULJk
+ aLgk0boroCI3x13jdUf+rdrrjpJ5M5ow/FS1N+yODMrhejn8jBzWYNjjwQruGktHtTtC
+ Wtw1kdqujp6alurcHHI2hHAoc3MkxRECldRwBCa2bkQFCxOlEjURm7e6JmL1YhjzGF9N
+ 66JI44ymmmq7xxPGNEya2YR95OYsjSCf8KR6kXfRk9EQtLVIodYHmiJMazhCW6S2dNkR
+ s7c6Yt7wieXL6J1QzY67MiPUV9va3lMbCbU8ieBK0RYp1roDY1NnubFZuiXcFCFbhpiQ
+ eFyGnErsJvcEX8syd0ThrfJ29CxrQXBhZlOfLWSTlW8EGpv6rCGrHMnNOWvZVO7B0Z/N
+ vS/3Pskv91g2Jf0/PJ5M//lFybdsGvgt+lNnDgNAJAS8k5HPiHuh3IkXmS2VnPZS6FlY
+ ijjhEyY4zKXIz8QIRZlhfBHON7k10j3rDhsd1UnmWpZV9ymsNnkTqgpj+ZYe7TicKSyv
+ 9bp7vsDdusU7+Nm9Ka1DKbxP+wVImdJED8tKhLTeCXdJm6UPR91h8XZI89slzynGvZaa
+ uxIwLkEj8Rwx4Abe2OSJuMOYgNZkztQoKBqbThGyMxwliS1RqHaeRRuVWTAfs3MkUVta
+ jf1jJDcHE7I8GMrLcddiz7WSrLh73D2TF/W4a90dKEysT/Yxo70nnI8IzmpCnGA29hgK
+ 24eD7eHwOGwnX2oHq2DxnjC2sGyoBfTlpPwYFirIwc2U8Tc2zWiKdFfbI6HqMM4Ciu/F
+ xqbIRZTccBhLFQ5zihxvXGoZ4rkIeS7MwvziZCtou3RjE+GeHqnNWU1eT+RiT4+9R1pv
+ yXiUwMiE0FBCFKQiEuRR0t2IddHzeuzyHHi8HmQrLGE6GkX6jkShzf7VCJcM8401xyK3
+ JTLCpd8QwmVfB+FxXwvh8mFO70G4AnkulxAe/49DeMI9CFd+NcKhYb6RyfuQ25CMcNU3
+ hPDEr4Nw9ddCuGaY03sQrkWeaySEJ/3jEK67B+HJX43wlGG+kcmpyO0UGeFp3xDC9V8H
+ 4YavhfD0YU7vQbgReZ4uITzjH4fwzHsQnvXVCM8e5huZvB+5nS0jPOcbQnju10G46Wsh
+ HB7m9B6E5yHPYQnhbw0jHLJH4G493D1C7cI3rpgfuAtytJQ4PVTRMjw4I3FzIB1pH38M
+ 9uEZrF94Cm8zHoGZeNguR78UqQ5pPLkMm5G2Y7nNGJeonB6D7diGGcsasdk790FqPKVc
+ wLgb5knH86946Ffk3cli8HT3tx5uOJEfDgnDoS8D0pWUApR4JsLrJiSNnJUCqXiXpZPD
+ enTT5JDkGOTQaDxtNMF10kFu0E3MFNbA7sWTyjv8av4lfkAICS+IBnGeeEwRwgNFFQD7
+ Hp5tGbwjq0zeW4n5aFwgidoowHtIUhzDzEdRYJEAw8JH8AbWAJiT/Qa2wqFfUFis8+gC
+ SFXszujt/+TO35wYZetv4R1IEkm6TO4nO2QWiJnsw0MYpQ49wwBllNJ9CGPNt1yByorK
+ Cm5rXvZG7QBpJsXES36+P563X2oNr/UgHWd9PLZDZVSuhRrrSBMOlNnG7GP3K48qo4qo
+ ks/E9gSeJ1RUKNBRgsCRHYRh3Qal0qfHNAPH+fRYQKXiGIWS5TmiogQZSRfEKAmHFHi8
+ 4BVKhsNYb0iv0ZjNNu5F8qLSqtYc8uyYj7cn1oYblvpYzNpQ0179+9pqC1SakfH6WEWs
+ QldWSXT6sjL86cry5aFMRSuIvWiPsAPhrXkWHJuUwGACMxDOHiq7VVtRISAVFpDmZmgm
+ KpKGo2c8jJcwO38zuOVjary2J3bue+/QZ+g8uj22lll4cyKJxutkVPchLiyGlCjNmfBY
+ qHSeZp5uGV2mWabbQNd6hMmaOh11iq5U1pWGGAbEdDNVpQdEttC+NLXQa8tSGH2ZJmsw
+ K0oWnPZ0LcYhNtyQxtOg/XP94I1BqIxVDurL8mNl0tgKCyauD+ktNk60+ni/YGGzCWcT
+ swlkE7xSefRRHAEpGlsyZnTA7/Xo7goyHrd0lhN4wZT0g4QObKp9aE3VY/HvkhNnGgqf
+ nrYxvuZf6FpCO0PTg/UrSxeGt8T/I7abafSOffqZIke8LDZv2cQF3x/nit3i0g58a+2T
+ 4fxAdknL0Z2P/ADlDHHgzYhDGvw0FK4mU3EiiYIxESvzAeHSiIMxqOzquaSJuUJ+xVxR
+ /UqtZJWspoY+QdkZdB+lQWWmplRZqplE59IuKvgWaZSU0aOoqtR6hheNKAksixeCB0Ma
+ pYtR8TE1oTGNS48pr6eB1dC1wpLdoJWQu269UVaGP8t1CURJTJIyojeX4ZXaKY06So71
+ U0KVKgz0Ucps5erzNsTYjQNbuaRfWADNq1aSVc0r0zwK4tF5daNLxuCCMBpMRp13H3GS
+ w+RlYjvPxpsvxedxF7jzt/zstZsTmYW57629FWQ/yC359ejb38X1R/E8D9w6xEUBAXgu
+ pBc0k0kdFyZN3FJukWEdJ5rO4eWKFezEEaryetz+Fv1K/RoDo093GRxGxpNuMrB+fYYv
+ HRQKu5Cuon6HXXT7jC6fiSlMXWq3BUW/L6C0ZgavevbcKzw3Bq/gi+u6ojKGAoQLpExn
+ lqVIWiHNKE3ZksiTojviwniKJNnghXTiIigmZqM3j+QTvyxLXmbSjpdXjV8ct12mvb2d
+ 73a2zZnLCYxKn3dDqWbVwqKyDfHyy4xjxbPfLUuPK+mhwvmxzb3F3lXdl2YHaw2etIo5
+ XzxTaI/1oKz48GvASsREjZfRe0QFWSesV6xTbSVPsNwkMpVWM3VsvVil3C5uVb5FLzOX
+ hbdU6ibVEqFDtZ0+wTwhbFc9T/cye4QDqqP0MPOqcEyVijfISlFlFU3KuQKvElklnZBZ
+ k8n5eF4An1qtUrCEUVGG49UcoGJSMYKYgiIlcPwTIZFhbyip4ka3CsgTaqtmJ+oZK8oS
+ 6pmyMhvSkJfUOUmNY65AcSJb6/MGt+YNolj1K/B+RIm3maFUPSGU5RiWFxSiQoma7EBI
+ qWdZBpNBrdq6USteQl3EZYsbtZe2ikh3IlNnrD9NUCFjjdexORR3Rm5QoRCT7eFeSbEF
+ UXtRJi23IWYRByxbpcBGcQBnc1Vz80qU3TQFKcYf8SpQamPESKZ9SKYR47X4pvfjJ+LH
+ 3493o8jezx6X6OZE9s1bE3A2GJiZ+Ei+uUrFO8kK+HWoNKuAKLW4bh2B4jrtUsUyrVAm
+ 6tUKxl4kZCicWrWzPJvmBcvPlNPyoiyfXitwoiMwyuyIkp6Q1+x0CQFnnoo6x6gqhIoK
+ h0EIZvVm2CbYg44pqYFS6/gJPyL78MLuLNkLstqT9J2k9q7HBlBgobJyUHpR++kQbElg
+ 8wbzBiU1iHIsa8LMkrHGUUCsPlKS6gFLut0DJrfBQzyjYCz1gM1p9hCjBx38DpRNtBXS
+ vfOjjz6KSr45w1SMinI8SSGphBd4IymR1KbfOwpVpHcCKZaWgs6AhbCLFOIdFfAHJM8/
+ ZnTJ2DSSsqphQXivp6Oos61wFumfYFQ/vuGpco+yl/vLy+e71ph96nRdVo6/OcukGPuz
+ b+85/8a+nnfn5Uw+vMvo4FM0jvwlZLmYY8l9YNa0rFk/OVhXtz+2zzGKYbao+SpvqG7Z
+ D7fteSWNXJf0B95sMu+xDWADOxwJ5R+xkv2WXvGYhZki6g4aGMbAO22CxonaVbDbzdqA
+ njABqrM5lQGz1YGfe4TTnlUbh9BFbCvqB8vKpP0kiS4GtIMylKPBKvrURqUfUtK0fqLX
+ pWoFK8Y4YDySQDMqk8YPqXp0FBbeT1jCe6Q9R4JVAjbpZsvYgsmMmkOCEjWmhGCxBB0d
+ o4VigV79nfmkdtWmH0wp2PbsisetJ9P/dO7nN4n+ioNtiHyw8PHezu8f+mj72l9cIsW/
+ x2vZcbhcoTRxjRnk3kRrzAlrQ0VjUyalzE05wh61cz7RQFOdWhCdTiFNSZ1mFZeXlqcN
+ 6vQ2lypgs6a7tnpWVd09/Nj164BShT8dWgny0G0Wh0IJhFhUODYHOmClflDaRT8OEH+y
+ xOilgcgCwhsBdaOuWOcdIw0LxozWF//52UMbDx3esO0o6ZlVMP7ES5U/ePh0/Obn/0EW
+ fPrB2z/9l/f+lY4dnT6VOm9O2LOwieTe/COZi+utLnGNteFNsQO/KviIOrR+n/i87YiL
+ 4VJoKmcwpuhTjYaQOmQQgzYyVfU6c5n8hLls/1D8peKq60Pvp+ZPvarLust6+oDIeTJS
+ D5icGWW8IJg8ToegdJpUPmGf44jjjOMDB+szpfocnFWpFnQpgVRngLMFMvKEgNXqD1zx
+ HG5OAhS7LtscV2KyBSUbUvnNw3KC+4d28I4JUgteVElo3BKO5V1+nVavTdMatCyv9o2y
+ Z/jRinf6SbpTYRb8oDKm+IkmxWvzYBKHjmhBudJo0ZGWZXJdymszKzvrUbKyGVaiHSbt
+ PyajJx1X4lhZgHBd8oi2DoVI3pJG8QKh/VdLS/Ta259zz+x7anaB4ZQwvXDm+vtmvhX/
+ I7H8J3GpMqec+HYvR7zspAfvn7F8yksvX2oumVS+K6/RoUXNiIYqqYr719Q+drqHSB+7
+ cU7Gx8uZT3FOXJCLX4nOhOpLDJPFyYomMazYpj5q73UeDRzOPmtX4a5hGhVMGVCOQjXH
+ 8kGnVal3KlPzhLw8zsHkmfJyg5ytQJ0S0EzwBxzW/IK7BPHGYJmEdOz6F4jnHT1XOSjD
+ mxTJHG+mLV2ly/Bp/d50vx8ybejoVCkeSE1Ra3zOUX4SsAdxPar1HhnFoVWIcMrSKkno
+ mGId2nueUf5AMUIpwShrsAwJQZAVnbw6Ue0R+u35xWMOV6yIv33is5QzmsD4x98N+ZmS
+ /Rtfi98iwhuk+pXvXKj17f72m9Nz4u+zVRO8E7feLnqn69rBV+sCFc/O+fXMxr+gUaQh
+ efFDF/sWHPjh+ZMLN9Nc2f7ZjIeQcnl3EaAk5BA+YdEA4BmlAndfxD8oMKh4FMc8bclV
+ WlE/EKsYkI17lLyKynrUTmm41HTFRu/mM/iwWbeucuelfyIQ2I6OdCZhIBjCsySj5LBR
+ bBNPNCx3V5NoBybNwMpkY9v7+5PHGmwD+eN97CTww5ZQuSAKKXyqWTSnmFMDYgCXSp11
+ jmqJSu31KW1Or1VJWbPP4zQ7NWhW8HaHj0lTZmKfuiB+iCZ9tqD0/T2EuiTPh5NjDWRG
+ ieb0l0OLXdfeGLwRG2IGzy14cBnENZW0yiTrHprTio24E0nbj/nOLoTmJ04Xj6anTrLr
+ 5dDmvtDo8MruhpyMipfaP2zIOvdg/bLnz9iCKxYf6Wfz90/PGF+ZUTtn1guzd8bG0k8f
+ bNx5OLaLnussmvriu7G3pH0Fx80MopxbcWeZHyo8w1/mKcsb+IChi18tcAY1NVi0Tg6H
+ aVEpbYLNBuqgwuYgeZagFax23OL5e0Ymq46kNOO4BnVlZSQ5ICIN6a6hSCPAtZxCcDxk
+ 8/FpxzquN+accRZsCgWnlOba+8kR5H/+zO/NfSk2g77cVrFIY6oas3Jp7F1kFme6PPFL
+ 1oP7oRq/jVrhmVDxfnGv9nnTq2yveFh71BQV3xI/YD9J+S+DepzIOy2C2qlXWQWr1UgD
+ qTa7ImC02uxRosBdcUjryRbHlzuivCPk4PWEX5WmQA2lo34imDHEaTCkNKj9QLToiCbc
+ BJkUdGQdJjnS5pehl89eOEe48+lRW1G0RZIb32+3FEx749W9e1/GD9C343/5dfw20f+B
+ X01SD++d/9ztvuPXmWvxz+I34rH4ayT7NhomIS4p4/RZlE8dTA/5A4xfM5aZxLIpopam
+ KHQKdUCUpkinFG1pRNr3wKpPi5IanJpNslKXzkMNWjwBVdZXDsQGUN8MnSNlSZOmBc18
+ aa+WxGv7ceMrD3IWp9au3fYsitHZkoOUucDQk6ti+6X1Zk58ThXcPER+5g81ecqLKSRK
+ KkM+1lRmZvgUpc6GSwG/8AbBmGJMZVwMZW6brFbbbc+SIQsk1lw2IB1EtMklkC8tgFjF
+ oDZ2XV6YuMZ1BklVDdlc/jG4xxb3vn78uN9YqEk3uCYGNs3btYubF//F7lhNaZqK0J0K
+ 8dEl9NJuWdcY45Nl3S1Jxr+GHuoxbrMcsTACb+ZL9XX6Jv0SYS2zVthh2I+3VvuN+0z7
+ zL3Qa9LWwVTjJPPbRraa+wlHt3KH4TA5wvWauYxMzmI0m1BfGdWqVKeYIgmSyY6jxJk5
+ aTZaTqqfNqE8XfEskdDGq4n665bkeWHorJBcEHiOKMI7FjyJVUj443EhpDcawWTq1JvN
+ Fo6QTrxNsuCFhXYjWvPoieiT5pWFBSuJdCNRzDNUoDxan4Ex0oZYMnYCGYvmPcN4Lvsf
+ b6t6ofsFfzA9P0tblK/lJqTEV7+DBzg2f0l8V/yz1+KL+3nxFQ3vsYjPZbANt/czj0nr
+ X34S7fit/2890s0cg/9XQLsEvxGPgXFQDbXyPwim4H8Epsv/YZD+KTAXHsCSBEsm7+x4
+ vB+Dpjl14dn3Z9e1L+9qX710Yatc4k4vUvkOpHVI25BQsPBfGoD/xQBAxQQfIn2K9Fds
+ VkSyIGUilSLVITUhdSCtQ9qGtD8x9GAdGA4TtEDujeePiN83Il41Il4/Ij5zRHzuiLg0
+ yrv7XzgivmhEXMb9Ln6XjMhfOiIufbu/u335P4B31X9oRP7DI+KrRsTl//DdVX+9lP//
+ kHV4XQplbmRzdHJlYW0KZW5kb2JqCjYxIDAgb2JqCjY3NzUKZW5kb2JqCjYyIDAgb2Jq
+ Cjw8IC9UeXBlIC9Gb250RGVzY3JpcHRvciAvQXNjZW50IDc3MCAvQ2FwSGVpZ2h0IDcx
+ NyAvRGVzY2VudCAtMjMwIC9GbGFncyAzMgovRm9udEJCb3ggWy05NTEgLTQ4MSAxNDQ1
+ IDExMjJdIC9Gb250TmFtZSAvWFZIWVRVK0hlbHZldGljYSAvSXRhbGljQW5nbGUgMAov
+ U3RlbVYgMCAvTWF4V2lkdGggMTUwMCAvWEhlaWdodCA2MzcgL0ZvbnRGaWxlMiA2MCAw
+ IFIgPj4KZW5kb2JqCjYzIDAgb2JqClsgMjc4IDAgMCAwIDAgMCAwIDAgMCAwIDAgMCAw
+ IDAgMCAyNzggMCAwIDAgMCAwIDAgMCAwIDAgMCAwIDAgMCAwIDAgMCAwIDY2Nwo2Njcg
+ MCAwIDAgMCAwIDAgMCAwIDAgMCA4MzMgMCAwIDAgMCA3MjIgMCAwIDAgMCA5NDQgMCAw
+ IDAgMCAwIDAgMCAwIDAgNTU2CjAgNTAwIDU1NiA1NTYgMCA1NTYgMCAyMjIgMCAwIDIy
+ MiA4MzMgNTU2IDU1NiAwIDAgMzMzIDAgMjc4IDAgMCAwIDAgNTAwIF0KZW5kb2JqCjIz
+ IDAgb2JqCjw8IC9UeXBlIC9Gb250IC9TdWJ0eXBlIC9UcnVlVHlwZSAvQmFzZUZvbnQg
+ L1hWSFlUVStIZWx2ZXRpY2EgL0ZvbnREZXNjcmlwdG9yCjYyIDAgUiAvV2lkdGhzIDYz
+ IDAgUiAvRmlyc3RDaGFyIDMyIC9MYXN0Q2hhciAxMjEgL0VuY29kaW5nIC9NYWNSb21h
+ bkVuY29kaW5nCj4+CmVuZG9iago2NCAwIG9iago8PCAvTGVuZ3RoIDY1IDAgUiAvTGVu
+ Z3RoMSAxMTg5MiAvRmlsdGVyIC9GbGF0ZURlY29kZSA+PgpzdHJlYW0KeAHdent4U1W2
+ +NrnnZOkTdK82zRJkzZ9pA9KHwQKTUtbCm2gFAotttICZQoDCojIY2AQ1ELBEZ1RELnj
+ qDiDKE4oDgYZuFwGFRXu9YFXBdRxRMXRDup0RKU5+a1zUjrQz28+v+/6zR+/nKyzn2fv
+ tddae6211znLl93aCVpYDzQ0zOpYMh+Un98KQLXOXdyxJF5OqgcgO+auWO6Kl9lMAPqu
+ +Ut+sjheFsIAovcni1YNPm/yApgXdXV2zIu3wwCmJV1YES+TIky9XYuXr4yXDWcwXbno
+ 5rmD7cYLWB63uGPl4PxwHsuumzoWd8b753yBaeaSm29ZPljehmn7kmWdg/1JM+L3P0Cw
+ NhUWggoWgQAU6PBqBeAvil5gsFVuR6jIbfrN7MSyf4BeUIZ71Je3Xs684P7jt5fPD/jU
+ 61Q12E+l9Jcb8BkuS8oC0BBsP6deN9Qit8q/1Ag05kSgFmEcQhFCds5+Ifgc2QbGtv6g
+ ijgZUDvftv3tKMlD+n+s3MMkL6jRgmruxjLn3I0ba7MqVKQOShkCTlINXiWt6vU+6YyQ
+ cb1eDyZj4wnVW+rAEgRVpV5ntHSOc6A0IpBgsvMb7y+dlxG+9pY7/+Ed4XwN+71aOsF5
+ ugLbe52vZEcoTF72RhgSTHSe9N7u/ENplvOZ0jHOXh/W9Tr3V2By0Lm79HbnY3coNY9m
+ K8kj3gjZ2ev8jZwcdD6M4z+wUWm4P/7ghniy5A5lopsPKMlNByLUkwedi70Zzjn4IAmq
+ nW3eRc5Wb8A5vSJC0nudIfmxg85632lnnTx1rzMYn6gkPnqxV8G4MD6t33vYmRmfIU3u
+ HUxyurz1TgeO7//NA06/90ZnRXaE7Hm2NjPbW+t7oCRC+pU55AQRlZOb4slc3xHyO5gA
+ WWQWpJMHD9RmIc5kW69zIyY7D9RmlqZH6ItBg/OAr9Z3B0IJQjpCU4RMD/r57fw8vokf
+ yefwWXwG7+ZT+WTeKBgEnZAgaARREAROYARKAMEYif05mCNLkZHTyQnHyHdGyesoOY83
+ vANFBAomQYSDO80ryq3lhnH6QE3V99zalcr2qpx//qz/zOZYiSP8QN205vBeR0u4UM7E
+ HC3XtP9fsp2V+HRd46oDjas+m1Hd6alu91R3IrSHt6zosobXz3G59n+2Sm5whemM9jlz
+ u+S0ozO8ytNZFf7MU+Xa36g8N6x5htzc6KnaDzOqpzfvnxHsrOptDDZWezqqWg40VNdO
+ vm6uzUNz1VZ/z1zV8mC18lwNynPD5posNzfIc02W55osz9UQbFDmysmpXjCtEthjoGeP
+ Qy67HRxMJTgAYmcRzsmpNC12iX0VxFg01kejZiNpMrx/hRjh98DDs7AOtc3rsJeowAN9
+ pBDeIQ6SDW+DBOfgL2CHLfAbvFfDRfI1aplPSSb2KYEN8Gt4OLYElkA5XhcJCyYYBZ/G
+ 1sROxr6FSuiBE4QnScQROwT50I3XTthFNNSc2H6wQj3cButxjJfgbKw39lccvwQ+InqS
+ z4yJvYsCxmJNADbDXniWuImHZJMbYh9hvRVxbIW9sVBsBT53CXvlw2RYg7N9QJwkg+SQ
+ neQ9ui+2PvYLXFsKtjXBXLwWw+2wA3bBPqXXHCaFNeH4VVCHbb+AU3ARvkKFm0UqyUrq
+ Tfqv9BfMGGZn7ATi0YTztcPDhEaqeEkTmUeWkH3kGfIn8jVVSnXQAfpNZgnzCOLWBJvg
+ ETgCL8Ib8C58Bn3wHUQJgziNI1PIGvIf+NxfqJFUG7WW2kqdpS7RI+j3GJ7Zwt7JHo4x
+ sTdj3yHOqZANY3CnT4Vm6MRrPtwEt8LP4Q7Cw3bYD39CbN+H94lIdCSfjCATyHRyA/kp
+ WQX3kt3kOXKeXCAfk08RuyTKSXmofGoFzreB2kzto3qpQ1QfraeX02vpY/R79NeMiWlj
+ juH1PpvLLudSuDp+qvQr6f1YbmxbbCfyxYyXF7IgF8YRBqm4GO5ATm5Gmu2C3fAkPA29
+ 0Bu7QgJwAl5DvD6AS3AZOZaCl5sUklGkgUxFDBeRxeTnZAdiuJccRCwPk8PwFnmLXMFL
+ AhulonKpG6gOahVeO2EH9YZCHw3tpjPpXLqOnhb7kt5H76e/YtKZWcxSZg3Tw+xgHmZT
+ 2LHsTHYWu4S9nz3IvsL+L3uJ7eccXDe3m3uGe4MX+CJ+By+RNMTFRdLhGTiKUvcAvQTL
+ XhhP7kCuzoBTKL198DxcgW/hGPyOOECiZW5mxB6BSGwTcvMI/IH+GZTBvdQvqUmxcnoP
+ rSKFscs4VgHy6+oFweysTF9GuteT5nY5Ux0pyXab1WI2GZMMel1iglajFlUCz7EMTRHw
+ V3tq2l3hjPYwk+Gprc2Vy54OrOi4pqI97MKqmuv7hF3ycx3YdF3PIPacP6xnMN4zONST
+ 6FxlUJbrd1V7XOHTVR5XhMya2oz5u6s8La5wn5IPKfltSl6LebcbH3BVW7uqXGHS7qoO
+ 16zo6qlur8r1k0NBNAZirh8OAQRBLQ8chvEda1G5wni5R3XY7qmqDts8mMc2Or26Y164
+ YWpzdVWy292S6w+T8XM9c8LgqQwn5gw+Lj+HSjC9sRnnzvUvCCP+sEUzzzNvSyQIc9rl
+ XEdrc5juaAlT7fIc+pywxVMVtqz+yPrP4tVc9dZrGsNUek1HZ09NONi+BYkuF9vlUsdW
+ LNVNc+Gw1J0tzWFyJyInI6HgHl9F3Eykty90hVWeSk9Xz8J2pDk0NPfag/ZqT3tVSxga
+ m3ttQZtSyPUfsq4b40aiHMqtyK2Q0zFu67p4+snGeP3rx+TUuu7EnzGtaxyiC5Hn9kxE
+ NMOuuTgJ0gJxHSXfOkdBz9xRSD78tRBc5QLEZ3yYQlGi08Ns+sSO8Pppg2h0dFUNIrew
+ qldlsyt2qbIF+7f36EYjA7G/zuPq+QcgZz19n19f0zFYw6Xr/gFyo8z/IREKk46r+RWy
+ /UxHk9Rl9XTJ7FuhsBrLHmv1NRVYlu1WLjqc/roIqBqa9xPyi5YIid0ZgSrHITQw9Owb
+ sTlHFrgFVTgdFvx+rMh2Yw4xqMGJamTJcPW4eibO63HVuLpQpJh0JcWGzp6WfCTYtGYk
+ C0xvdoeDLclD2c6WltE4Tp48Dj6C3XtacISFgyNgqlTlR7FTvr8OV5XR0Dy1Oby+Kjkc
+ rGpBoqMQH2toDh9D+W1pwV4FQ5gixmsXWAdxHoE4F2Rje2F8FHRr1uMQLT098pjTmj3u
+ 8LGenuQeedfFy+ghD68IDlZEQO4iUzhC1jfgs5h43MkKyd0eN6LVItN0JArwVQFCt/5f
+ U7h4CG98sgSxLVYoXPojUXjUD6Fw4AdRePQQptdReAziPFqmcNm/j8Jjr6PwuH9N4fIh
+ vBHJIGJbrlC44keicOUPofD4H0ThqiFMr6NwNeJcJVO45t9H4QnXUbj2X1N44hDeiOQk
+ xHaiQuG6H4nC9T+EwqEfROHJQ5heR+EpiPNkmcIN/z4KT72Owo3/msLThvBGJKcjttMU
+ Cjf9SBSe8UMoPPMHUbh5CNPrKNyCODfLFJ41ROFgchiu1cPrh6ld+NEV8w3XkJx9EXZS
+ AQBMixBa2RnwOPMh7OIC0KSke2E71j/G3AJjECZgXTmm+ZhWInTjs5uxvAHTLbwD1st1
+ g21raQdswLZKai+YsG4tjpmAZTmfgn5aPKaEgSHgSA+WXejt4kH+//iTwwE0AoOnJW5o
+ LB5jWld/qquZ701FrFUjTlpMEyARo2AAejBAEhjxTGnGkgXPfTY86wEkI8gr+f/lhyd1
+ /BXhdZwUkflkB2WngtQLdAl9lqllHmVL2DD7HZfHneAu8Fv580KhsE04q2pX7VVJYpl4
+ Rl2CT1N4sgY8Bx1HLvAwLuhmOQeeLxjeQYPIMg6apuwqjncQsAmqve5FZRh8mdxfFoqW
+ TdZ9XRbSRcugvCxaJsOIgpF6t96HsJN5LDJwmj3+3bgI03jlaRlLGrEEdg/OQ4GIHDsf
+ /GkXRXxspjiKK1XVcl3iSnETs4nbSd/P7OD20o8ze7gIiYgnyUnxbfpt0UR4jqNAUKnw
+ JhKepYyimG7AopFl0w3YxgvZclxJVOMBiVOJNCuotRaLXS0yHBshxl4VTWFyULRpOm9d
+ Zs1ZMVnXbw1FAwH86wM2jJ1UfWzNh3JLWai8rMwQCOTjktjuvJy1ujp04ZhjyWHmREt3
+ nnWwgsYK+kSLHnviv1tXVsYjjCggbdBG3Go8wLrxAOomVD5ZEXmStFKi1Ds7+sF86Sj1
+ HJ5Xq8jU78aRfOk1hSKtsbfYNewlPL87YXkwa6b4K/5XAn0D1ZLc7JjP3EY2s08Ye5ln
+ xReYF9VnqXPGd63vJ39j1VkiRB302AXBrqlw0rShwq5ymkstQqkzlbe7E0tTbS73g+59
+ MxSehfqQYyF9oO9MHy6zr7yszxDI1/XFMTaUlrhdFrPFneHL8KRRJqN5ZGFpSambA7fL
+ l6Enrf/zDDGT5U/N5qVTqfnTH99z/PSvH23Kd5IRmdKzUkw6fvAgtY2Z+drB/s09C0va
+ pS+/+ebywsCyL6XXT50mnbQdNcXjyH8KV6uGfDl6/BxudxXUYfSY00WAvArPofwJWPEc
+ 9gAlpVEr1OUUjCBulKnBi3lvoJ86FS2iC648xgSYI9KLMZDulC7jwDjHLlQk+9ljOHBp
+ 0MJnM4yKzgZKJXAriF1NC+kqm6iOkJQD7sYn4zRRxDh0AcrLo0iN6IiCpKGZdjGmqIPq
+ jq6S/ps9JkWlfTGIPoDS2xR7h/09exHSMJp0Z7DupHBO+M7+rZvJojLdgaQ6a4tph/sF
+ 23HHNypVkmhIO+NMyE5MNDAVHidtEMQKi8qTZEgyaOk0gFJPctpTiTp7Ol+abPOmR8jP
+ D7j3rbqGW6f7kV96gyWQPzZfFs6+8jjbojqsxapBcYszTa9DpiHPit16j4/jOY/MOZ3M
+ WLAQZo1nU31b70ff/PqhFyzSk9T8U86WCat7pXOH//T886SK2EiTLbqS/np7mVv6u/SV
+ 9MVfDtz79cCnkQU5da+cInPI/Lfflj58k3wl7+U4nfciyVnICiYCRVWwAm3nqXSwcfz1
+ 9J2s+xjKQ9Hyq5TdRYqos1e+Yo9fmSBdVsbajm8cMnEsAxwLblMBLwgqVm8WbKos8Ak5
+ Kq8+21DKFwtlqlGGhdCpXwW36jfDXfqd8IB+D/xW/yJcFr5RpbCCqDILVhXDG+y8XbQY
+ kD36fMNYvlwsN6w2HFIdNLxoSEjkE0VKTDToVQKwCTxFG0SeTtADlSDQghG1BcXQPsqQ
+ qE3wJdqSGpEVqCVQ19l0589bo2U6RUugwkN9h0whuPkx0QdGFMDSNoJ/WXiKSopx8xvN
+ JllkCbOYHJY+oKRPpTelzyjpA3KMaGTFSH+U81D2lRzmzeyHcgaSkRyrZF38GO6RpUgL
+ EaNCzcFslyfZamJ9SRnZBMNK2VmUzyE4XGlJnCWNK7Ukz9TZ/eBLz7Tl+CMkFYV6cKMP
+ CvWJ6AlEUB8IIMLl8maPBvQWxJXo3bi3i4twp5eYLanEZOT4VAxlGXH/m2QFkE/yiEfZ
+ B+RV0tZV1NpSOO/c70YXjFq4en6ToPFL+xI4DaGouZuk49Ib1BvMcWm5Nftnd+XZozVV
+ ozbNXPBKdtb2h+Z2egPJ6SNSx1VsvvvG6FFcFQ1jYu8xo5jZaKkDMBruCU4ZQxWXrCKb
+ CfN2Ksn4+8fZn3gStCxGcJPsORgHYzLyMvKy5QomWZ2WbPaPdvLZotpfqB6dFIJQ3uji
+ 7HEZ9jJ7KDlXCBXbxpT9kdjADbXkaRjcRP2K0rugD5z+6KPB/RM9HZB3FCpt5B9yDyFn
+ cB8lkESCG0fRfiWlvhKZSqgOeY53Y95diNE4vREphmTKI8oWS8soLkI9mUS9l1xaEJzl
+ q5w6uvUhet+UtLFtszqzU0WpTzVhKUk6sGULRaekSC9rRXpMqHX5r/7roabHl1AGvUml
+ 0Vl8jRMrFt1zSUy0l44fWZhefk/rtgkTnpc0RZNGZWqz3aPTg7nFTzz00qwRJiK/TEQ5
+ mRA7yxQhHR1oMW4KVj9o3mOmulPIRFOzocuwUlxliJheTDppEqwUxzheZ7ypdt6cIGp0
+ z2q8RnWqriTRCSWpFofdJZRYbE5Xt7t28jVaRx+I9is2og+FJ4AaR0llGi1F26YoG5lI
+ lri6QYK5XVSxDkYWMhZC6wR3Qee24pSUkXfPm64iHnH6XdK30rffEMOXpwlrlZKpw2NH
+ VN5Tv27lxE2LZmxYfpiM+ha1z6jIp2S3srZylJFO1OE6XN2UoP+iBi2/yUHpaLB4dTwn
+ Oryi2kTbk5yck/Yxdqe9RGtLde5w11Zfs4Ro/wWUfUVh9pXrcRMY5E3aBmaLvCuLE4gn
+ DWSUDfF9kKbwnFq9s4C4pc/G7lr+n9IVQt56dl3nuMa1t962immdGaKE74LbO5pJ8VfE
+ QoIDy5655+SMoiNbt/8B5To/dp4ZjfxAc4l24cngxBqh27idPIi+B1GxnI6117E1uomu
+ u8idid1OkTbTliRzkqVWqDfXWybaW82tlln28+Qc86njE9dll24SqdFtYjfqGHRZ7g+O
+ nJIwO+HmBDohIZnzprl5i8GfrDbTVBpdYlmTltquWa+hNHYv5Uy4P9Xm8SIpBrkZvYAm
+ vw1t/oW+/Dg5TsftRxtaurjKApRt3O2oCPDi3XgbNPxoP9JAr4MxhLy6OIEc5tfcsOns
+ hGCSmoqauY4x05pLUy3Eo561deBV6ThxfmSkl/9s4dJbP5t/U8f6urt3V2YVJhd0zHuY
+ aFCZJOMrYPzRUClVMjcinbT45qUAZgV1Pam4CVlvQT5v4NK13qwIKQ+6Ulx+a2IB5TQ4
+ 030F/iR7YcodybmqEr9tROE1bI5vbVlWL+DOjp4u7wvI1lHWxqTNe3XnKmJqwMWhVTSi
+ pKZ5fVcXOVbe6+jsFBcZRpZSR3o23vRAINU1+gH12K4gMU1YLf32NembBFKiSc5bvLMo
+ LSu/adPrV75674a/bn/8oUfvrrtp9qQeepkt55b/uPL1Gz+N7H6s0Oz7SeWumhpPBfEN
+ /J3UyccatJXd6JPcyB7Bc0h5MJ2lfFRzQlcCY7QYQOO18DpeFEpYuy1J59PbrLaj7oZB
+ MY4r8T5Fd6MEKxpK0dayiZGdNE4xMPpxZCQ9/vHiXKP0bqpv8dJbpQskZdxjs5gba2rH
+ 3n5fdD21vbmkfvvWaC97JHp5dp2ME4XvYIDsZV9BjvAwJphWD/WkFVrxddN+VLUcL6rQ
+ FALnIzw6/b1XUVKcftlNRm+pPISOo+zooomTYa/0Pu4cBRh8dSfdduWovPYNuPbFuHY1
+ fBHsDVI17BnqI4pJRFvdxG5m7xF+oXqefVl4h39fOK9SC5yVy6fzmUw2lyulR3H1dC3X
+ RrdwC+kF3EpmE7Odvp9/gv49s5fbwx+kI8wL9EuMvY6bxM9gNzEbhRPsSeEd+h3mXf6s
+ oGZVKoZlObUa30vzmMX3JiLloulXDOgTqvCEwHCUSmRoTuTxBMnZtUT0gdqlLlAH1Yza
+ ptF2uxs+lPXJQJty1Pkbrlk2+rLRsAS6Q3k5jHIuWN1yAgxYFwgkdusE+QiAjFrahnsL
+ HUniVqEnwOvdG4iVzCUd0kayVdojXVkhXWSPDHxMdkqzo/PI62ukJ2RabcGbfD6iIT2Y
+ RAERWZkJPmJj2CEWhKKDHgj6U1kE6b5H+pA48CF8fj2uYxczC9+2Ha8IQSlyGV+/492M
+ kI6wAE/HC/EcvArT1ZhuxrQH0wcxfRDTJxAOIXyC3ErA/m58c0fjeUSL7/By8Qwt39NR
+ Xpw4qgO9NQG9lHyUags+w+EbWBVJxCf0EAIj5lIxPuAAH6Y2yIN84sHxGvA9cFxHR0/o
+ +vsC/VdXg/5UeVmoD51axT/BExQqarxM9KCsowW4KvbxrNuEBnkkGmSLnLL3bA3k6URK
+ Om/MmL8i1yJ9YPQuWJ1tQYE0FedPu2NtaJxr1LTmRcysUTWBaaULo1Opg+My6+cUTYze
+ Rm3u8E+ZktsSXcIEH27yBktHNrTn5uL65X3bgbrKjCusC+ayxETSSSlpVnepOWLQcSov
+ KswERrSwJZZEym7Tyz7jdTv4xOCBC9UTyk5feWBwF3/vWnx0z1vSeUv2intLUnAPJ5WO
+ aO5ewLTuPx1No7bPyJu+pqIz2osoTk+vlBUL6lL0AXYxncgtOcIRCmZaaCJoNmk26WiL
+ 1po4X0uzXquRV3sT1FarQJVY7HahRG+z2SNkxYEhE6H4R6g0FeeoTD4NLoNlSwfVp2IV
+ vXgEhOIi+W4i1Gd33bV2bXf3WipP+lz6BK/PiRHNt40Yo2+81Lt79/79u3f3zpeeJE1f
+ fE5mSb/9nAoiLddK05idKJtalIpJwSxLkiCm2Cmvi7dzojdJbUsQtFZtic6exjmTnVaf
+ zeZO2+FuuGrF+mUzFsITDxp0+QiE6A4adMU5G/REig2yufKk+TLkEERcQOjlt9z+0OjU
+ zrLG29Y6iEqKntowIz9X+pjo84pmb6QePv7LySuPhnIjD1IB6WPpkvRn6fUKb3X0JHvp
+ kQlZE5HMcR1GXWFaMaI06RDQZMIBKlGLoYkJQVsSr+U0oosqoIIUbZJPDwlqn8ZmNEXI
+ vAPuhvlXZf2MsmlDbbLeRNzPyKoTHRE0u+haKlpckWbqXXVScrb2qTFuPCboKkc0rGda
+ CZHO09SS8o3Ry0zl0cWZ42WcKOT9OXyX3QE54Id1wSkqHZdh09Iqxq1W14kT1RPcVa7a
+ rLdowZHm0oiMOYcx2/1+A8/4M9V+f6JJdDnMoTTelMuH0u15GnCEEnMhlGPLzbvGE+zH
+ I4NCd+UMikESPEEocYPoad1pZaPe2HYjaSOKy6C4UenoGhYX4bZkBuMIipOobGQjnkYz
+ igmZq0otvmf63MxMKXaovr7vrVOEJEkfcrb8pW1TsrNje5umfzkgxf6BL/Zb612BwsIC
+ m21sXnXV+u3vPHay1DV6tG+E2TIqc2rjmkdPv7OHxo1AwBT7K7WS7cJ9Oumgzp/o1Pj1
+ z5GlwJDWoJmHVo5wVmRNItfPqHxwH/LJGiEJB9ztMnvOlF2IlvWXyfz5Wwh3aRR3KfoT
+ eFgtlmNZI00evRwJKSk18RyuTW/aQez796fN1DoSul+eVEAvfoUUSK++Ej023k3Imywf
+ GjGfeliW99hFpgl1hxx3rA/miWa7Ods8yjyD7+Q5O1oczpygFVn0xe1a0We3qu0ppMRq
+ S075p/mX96UhEIqeUWgue+Go8pHaeP5QPLRiWcbRj+VlV1ZGLZ08YvYtu68EP52QPmNc
+ 5vFrp381PZ98zlRGb27Ln7YiuICaeuXoTrYwqcz/dPth6l4H0i4BbYYbv/nRQED+ig8i
+ wGJwRkCQgzQ0gpj/HK6HxaCqISBHaK7mNIM5OTqTLAe7lIhXEtVN3L/dS7KkE9K5J/dJ
+ b0v/TQr3MpUDl2j9laO0feBjzCsxBApM0gSmAWkkR2rfCS7xiTPE+eL94m7xDRGNNeG4
+ FF6vzeVd2rH8CG0d38bLmvc2fpVWa0ks0XarNql3qCNqzmjUCFrKpdH4DGq1yPGUUxB8
+ GBeUs1rRpFFj9IdXgZPyJzl1iUbejMKQoFVrIkRzABtETIOapPsEW6fJ/ERcKlZM7g9d
+ sA7g2UeGwdAgbt7QhegFNFRKdBDJQTA4yKIX0Lhy9fMjBwODcl4OC+TLzFqKboCTmEtK
+ xxFfnEoU+psZPrLfm11vt+Uw0hIy9m8fYBSwZ9G6Ixl5eWTDaxQlGvSLNMyygfO098qr
+ 0sv3E5ozynseI9fMTPY11PwpMDc4eoo4W6R4L+cUvfi9jFd0Yh5D9EZ9qyWBM9BiKq6T
+ +EDXwxm0viSn9T6TzZGKCxx0L/tR8M9ceC9ugWXRV6K4KPx95X398ulA8e1QTZlkNcVZ
+ TPJewMBS8Uj5wDuSHkPQSknREocxI3l8KnX4sHTh4V2h6jNybIN9jaEuEjJpivGlgXvp
+ m1+qebqpIa635DvE5C+Tvu+XipU0+hkZkImeRLZyRijG76xq8IumWvxYsA6//JoMU9CP
+ mAqNMA2/mZoBM/FLp1n4ldV/KQMS9EuIkuMw+g+TKqqrx0/Nqe1ctKJz+YK5HbmVNy+a
+ J+uMq7/1mNmKgHFDeArhjwinEM4jfI4wgJ01CCkIfoQyhHqEVoRFCD9D2IqwC+EphD8i
+ nEI4j/A5wgAyToOQguBHKEOojw3+cHwYyhO0jNeXK4aVFdV/Tf/qYe01w8oThpXrh5VD
+ w8qNw8odw8pzh5WRkNfhr/D0Gvx+Mqy9a1h5wbDyT4eVFw0rK99jXzP+TcPabx5WXjKs
+ vGxY+ZZh5eXDyrcOK982rIwBu2vXf4WSy/8PQiA9pQplbmRzdHJlYW0KZW5kb2JqCjY1
+ IDAgb2JqCjc3NDEKZW5kb2JqCjY2IDAgb2JqCjw8IC9UeXBlIC9Gb250RGVzY3JpcHRv
+ ciAvQXNjZW50IDc3MCAvQ2FwSGVpZ2h0IDcyMCAvRGVzY2VudCAtMjMwIC9GbGFncyAz
+ MgovRm9udEJCb3ggWy0xMDE4IC00ODEgMTQzNiAxMTU5XSAvRm9udE5hbWUgL0pBRUVD
+ UStIZWx2ZXRpY2EtQm9sZCAvSXRhbGljQW5nbGUKMCAvU3RlbVYgMCAvTWF4V2lkdGgg
+ MTUwMCAvWEhlaWdodCA2NDQgL0ZvbnRGaWxlMiA2NCAwIFIgPj4KZW5kb2JqCjY3IDAg
+ b2JqClsgMjc4IDAgMCAwIDAgMCAwIDAgMCAwIDAgMCAwIDAgMCAwIDAgMCAwIDAgMCAw
+ IDAgMCAwIDAgMCAwIDAgMCAwIDAgMCA3MjIKMCA3MjIgMCA2NjcgNjExIDc3OCAwIDAg
+ MCAwIDYxMSA4MzMgMCAwIDAgMCA3MjIgMCAwIDAgMCAwIDAgMCAwIDAgMCAwIDAgMAow
+ IDU1NiAwIDU1NiA2MTEgNTU2IDAgNjExIDYxMSAyNzggMCA1NTYgMjc4IDg4OSA2MTEg
+ NjExIDYxMSAwIDM4OSA1NTYgMzMzCjYxMSAwIDc3OCAwIDU1NiAwIDAgMCAwIDAgMCAw
+ IDAgMCAwIDAgMCAwIDAgMCAwIDAgMCAwIDAgMCAwIDAgMCAwIDAgMCAwIDAKMCAwIDAg
+ MCAwIDAgMCAwIDAgMCAwIDAgMCAwIDAgMCAwIDAgMCAwIDAgMCAwIDAgMCAwIDAgMCAw
+ IDAgMCAwIDAgMCAwIDAgMAowIDAgMCAwIDAgMCAwIDAgMCAwIDAgMCAwIDAgMCAwIDAg
+ MCAwIDAgMCAwIDAgMCAwIDAgMCAwIDAgMCAwIDAgMCAwIDAgNjExCl0KZW5kb2JqCjE3
+ IDAgb2JqCjw8IC9UeXBlIC9Gb250IC9TdWJ0eXBlIC9UcnVlVHlwZSAvQmFzZUZvbnQg
+ L0pBRUVDUStIZWx2ZXRpY2EtQm9sZCAvRm9udERlc2NyaXB0b3IKNjYgMCBSIC9XaWR0
+ aHMgNjcgMCBSIC9GaXJzdENoYXIgMzIgL0xhc3RDaGFyIDIyMyAvRW5jb2RpbmcgL01h
+ Y1JvbWFuRW5jb2RpbmcKPj4KZW5kb2JqCjY4IDAgb2JqCihNYWMgT1MgWCAxMC42Ljgg
+ UXVhcnR6IFBERkNvbnRleHQpCmVuZG9iago2OSAwIG9iagooRDoyMDExMTEyOTE3MTM1
+ MVowMCcwMCcpCmVuZG9iagoxIDAgb2JqCjw8IC9Qcm9kdWNlciA2OCAwIFIgL0NyZWF0
+ aW9uRGF0ZSA2OSAwIFIgL01vZERhdGUgNjkgMCBSID4+CmVuZG9iagp4cmVmCjAgNzAK
+ MDAwMDAwMDAwMCA2NTUzNSBmIAowMDAwMDQ2ODM1IDAwMDAwIG4gCjAwMDAwMzAyMzIg
+ MDAwMDAgbiAKMDAwMDAwNDAwMyAwMDAwMCBuIAowMDAwMDI1ODg4IDAwMDAwIG4gCjAw
+ MDAwMDAwMjIgMDAwMDAgbiAKMDAwMDAwMzk4MyAwMDAwMCBuIAowMDAwMDA0MTA3IDAw
+ MDAwIG4gCjAwMDAwMjQ5ODcgMDAwMDAgbiAKMDAwMDAwNzExMCAwMDAwMCBuIAowMDAw
+ MDEwMzg3IDAwMDAwIG4gCjAwMDAwMTA0MDggMDAwMDAgbiAKMDAwMDAxMTI5NCAwMDAw
+ MCBuIAowMDAwMDA1NTUyIDAwMDAwIG4gCjAwMDAwMDcwODkgMDAwMDAgbiAKMDAwMDAw
+ NDQ2OSAwMDAwMCBuIAowMDAwMDI1ODUxIDAwMDAwIG4gCjAwMDAwNDY1NjEgMDAwMDAg
+ biAKMDAwMDAwNDkzNCAwMDAwMCBuIAowMDAwMDA0NjIwIDAwMDAwIG4gCjAwMDAwMDUz
+ OTUgMDAwMDAgbiAKMDAwMDAwNTA4NSAwMDAwMCBuIAowMDAwMDA1MjQyIDAwMDAwIG4g
+ CjAwMDAwMzc4NDAgMDAwMDAgbiAKMDAwMDAwNDc3NyAwMDAwMCBuIAowMDAwMDE3ODI2
+ IDAwMDAwIG4gCjAwMDAwMTc4NzMgMDAwMDAgbiAKMDAwMDAxNzkyMCAwMDAwMCBuIAow
+ MDAwMDE3OTY4IDAwMDAwIG4gCjAwMDAwMjk4MDkgMDAwMDAgbiAKMDAwMDAyOTE2NCAw
+ MDAwMCBuIAowMDAwMDI4NTQ1IDAwMDAwIG4gCjAwMDAwMjgxMjIgMDAwMDAgbiAKMDAw
+ MDAyNzQ3NyAwMDAwMCBuIAowMDAwMDI2NjcwIDAwMDAwIG4gCjAwMDAwMjYwNTEgMDAw
+ MDAgbiAKMDAwMDAyNDA5MCAwMDAwMCBuIAowMDAwMDE1NzcyIDAwMDAwIG4gCjAwMDAw
+ MTc4MDUgMDAwMDAgbiAKMDAwMDAxMjc3MCAwMDAwMCBuIAowMDAwMDE1NzUxIDAwMDAw
+ IG4gCjAwMDAwMTEzMTQgMDAwMDAgbiAKMDAwMDAxMjc0OSAwMDAwMCBuIAowMDAwMDE4
+ MDEzIDAwMDAwIG4gCjAwMDAwMjQwNjkgMDAwMDAgbiAKMDAwMDAyNDEyNyAwMDAwMCBu
+ IAowMDAwMDI0OTY3IDAwMDAwIG4gCjAwMDAwMjUwMjMgMDAwMDAgbiAKMDAwMDAyNTgz
+ MSAwMDAwMCBuIAowMDAwMDI1OTcxIDAwMDAwIG4gCjAwMDAwMjY2NTAgMDAwMDAgbiAK
+ MDAwMDAyNzQ1NyAwMDAwMCBuIAowMDAwMDI4MTAyIDAwMDAwIG4gCjAwMDAwMjg1MjUg
+ MDAwMDAgbiAKMDAwMDAyOTE0NCAwMDAwMCBuIAowMDAwMDI5Nzg5IDAwMDAwIG4gCjAw
+ MDAwMzAyMTIgMDAwMDAgbiAKMDAwMDAzMDM5NSAwMDAwMCBuIAowMDAwMDMwMjgwIDAw
+ MDAwIG4gCjAwMDAwMzAzNzMgMDAwMDAgbiAKMDAwMDAzMDQ4OCAwMDAwMCBuIAowMDAw
+ MDM3MzU0IDAwMDAwIG4gCjAwMDAwMzczNzUgMDAwMDAgbiAKMDAwMDAzNzYwMCAwMDAw
+ MCBuIAowMDAwMDM4MDE1IDAwMDAwIG4gCjAwMDAwNDU4NDcgMDAwMDAgbiAKMDAwMDA0
+ NTg2OCAwMDAwMCBuIAowMDAwMDQ2MDk5IDAwMDAwIG4gCjAwMDAwNDY3NDEgMDAwMDAg
+ biAKMDAwMDA0Njc5MyAwMDAwMCBuIAp0cmFpbGVyCjw8IC9TaXplIDcwIC9Sb290IDQ5
+ IDAgUiAvSW5mbyAxIDAgUiAvSUQgWyA8MDMyMzk3ZTAwZDIyMzQyMWNhZjU0MmY1MTM0
+ N2VjMGY+CjwwMzIzOTdlMDBkMjIzNDIxY2FmNTQyZjUxMzQ3ZWMwZj4gXSA+PgpzdGFy
+ dHhyZWYKNDY5MTAKJSVFT0YKMSAwIG9iago8PC9BdXRob3IgKFJvYmVydCBMeSkvQ3Jl
+ YXRpb25EYXRlIChEOjIwMTEwOTA3MjEzMjAwWikvQ3JlYXRvciAoT21uaUdyYWZmbGUg
+ UHJvZmVzc2lvbmFsIDUuMy4yKS9Nb2REYXRlIChEOjIwMTExMTI5MTcxMzAwWikvUHJv
+ ZHVjZXIgNjggMCBSIC9UaXRsZSAocmVuZGVyc2NyaXB0X292ZXJ2aWV3KT4+CmVuZG9i
+ agp4cmVmCjEgMQowMDAwMDQ4NDY4IDAwMDAwIG4gCnRyYWlsZXIKPDwvSUQgWzwwMzIz
+ OTdlMDBkMjIzNDIxY2FmNTQyZjUxMzQ3ZWMwZj4gPDAzMjM5N2UwMGQyMjM0MjFjYWY1
+ NDJmNTEzNDdlYzBmPl0gL0luZm8gMSAwIFIgL1ByZXYgNDY5MTAgL1Jvb3QgNDkgMCBS
+ IC9TaXplIDcwPj4Kc3RhcnR4cmVmCjQ4NjU2CiUlRU9GCg==
+ </data>
+ <key>QuickLookThumbnail</key>
+ <data>
+ TU0AKgAAF16AP+BP8AQWDQeEQmFQuGQ2HQ+IRGJROKRWLReMRmNRuOR2OQOCR6RSOSSW
+ TSeUSmVSuNSCWS+YTGZTOaTWaPecP9xTsAAefTaBQUAgGbQ+ggChyuBgB9U0ACaoUWpV
+ OqQ56Vd/vCtAAG12EUOiUuq1+k2KxwawACzRGtPAAB64We5XOZvW7P923muV6L2m1why
+ 4EABvCUik3l2gAJYuEYjDUScPcAVd6AAT5eyWGjwq/UG2gAIaGT52CZ8Qae6anVSi7PV
+ /uzYXsG4+1ZuM0subkAFbeABzb+EV3ZujiYrGU19AAK8sACTnABm9EAP7qABw9cABftA
+ AHd0AN3wAAOeOmU4CecACz1AAee3ayG0WXbRTPiH7av8fmOa3X7EGP+zL3wCv6Dn3AwA
+ HlBIAHtBgAAHB4AHjCQAAxCoAHTDAAAfDYAM/CoMNkADiHQADIgAA0UAAAsVgAfkXABA
+ x9gABUaMmq4AAnHIAH7HjlOYh7SQG+bPhFIr9SPJCJv4dUmRCv8gyg+T4ITKKiIOpcgo
+ PKsBSyzkpNpK6gy6oUvy2z4RzRJM1TWhUlya/4GIRJ8yzpKyDSxOsuKShc5s0gktzDP8
+ 8zxOyEz7PU/QRBU0BHNlHTY/kRgBOCGG2dYBoKBADoKo8907K1P05Ka0TvUlOM4oSFVC
+ 2syVFVtWSpUtU1PWKCIIAh9uSEQJn62ilwSeTmuesdgIQ7oHUfZL+N+c0QoWbR302ewD
+ tmpFZrVK9ssNV1U09MNX21a1aXFO0p3NV7NqJb07pDPdwysBZ7HiAASgnGVAgAed9XoE
+ oSrOX2AXzfbCA3GzK2OAAE4VgR5sGwuCWSmz+MCcsnPmbR4AQyYDWRWCF3c+FC25d12V
+ 9b6yW5j9y1Nk+SVcv2ToMBx9WCEgInzXzPK2BeeZzUaTPGDgAAFogAMc84CRhA6fU2pc
+ eV7fWG4hB9MWKz6VRiAGeAXCkLPw/hybDScAIWa5240eACY6o1UVhTx/XbdWV2vbVbTB
+ dk/3FLWR7nkO571bQJH7eYTgnnCF2KqATZ8la0mtx8Oq3hQEu470UANhgAHxzetZ7EwX
+ 9BxiYHB0gASKET8v4cfV87rkgmud4FaMrlrStKxOEGNb2CWLUInadIAHedZzgACgMg/z
+ R62DbZ6HidwABQGQdgAbRnmOnoFa4AwEa55rEgQBU4g2EITgAcZuGrox0HGywY+mfR8H
+ toYBaTuCCAUrx4nYdQAAIArmBxjbGo9AGYPCngwByqRPYFB+luBQBRw5CligpgoVMdcF
+ 3MlpaIAJHaPYNm0ay0xhzBYPk0OuOEAAH4VOpLu6t9jWyGDTHW5QdQ/wHoCVyzgawyhf
+ NaAaBA6Y/lew5AABEC7BR0jiG4jOH6LR9M4AcBMCyCx5FuHANcZr2E4gXA6CR/r/2hno
+ HeOlir4E4gJAZDcfo/EZRpAkicA7lB3jqWaPkfA9X+gEcwPkfMeAOAjBa8UDIHlsMlA0
+ ANeYKgKD4TkUEygAIKApYikmE8KYVtfLvJWGBCxpDrdkOgfsN29M/lGyyUjf1PSklNKt
+ WK42/t7lcqCVSswNgBHeAAFYFpGKEcyCuX0k0kSVhU8iTBrpKo0dkQsaA6nZDiHzKKUq
+ 3ZZMhVKupbE1FxpkM0uGWEhXazTlXNZuy11RmdWyCIA8twWS6IY1E9J65gH6mFJc1Z/H
+ SDgRmjUhYyhxzNH3EAhs43apyWwyKV8rJouAVVN6ay2W8zdlOrKUs6C3AyA2ZIhc7gW0
+ bnjPI7Ew4WGuG/SNhLCyFj3H0UQfg/iCgDAEyIqSEl5gFPQ9lrhdKXUsAO0lxhrYOq9p
+ GN8AAQ6iEYmQAAaNSYigRAi5VZDm5GUyURHlpLl0BI5AmT0n5yCKAIq8idFJIp5zEnqX
+ c8A3Z8zJPiokvqXyRFpHdXFFSLFKJArcR5MZEKfVWrOAAHNfyMHCOsdhYrSERHFApYkA
+ AFrGAAHPY+rSm7EgUfM6wDNl3i2KqgRBp4AILjrAACq0RI6x0hH+Nu1FaSMV5S0oM+ZE
+ zoxZaoAAGFtXRJeUTayvCX6fW1BhR0jFnVmAAA7cW0lH56GqP4Nq5lqrdEsrykEY9065
+ gFAADS7Bo67zaQERenwMbwXAIvcI4FxQO3HhRSCYo/7mDapK5QhY6x6jXQcAlYMHCwze
+ VjflvN/COI8pYQcAiEKBX7mvQPApGG7D/HxVkCgC3Fl/QY/K8AMbxEWvIs2816JLVkuU
+ XcbGIbVF/luMNhIFhsNtoIqtVc5G3UwIrjBWzcW+UQxeREew5wXo4AIDeqdPgZ5BwuRX
+ DNxLjViuRh41J/MQ4pq8xpII7h/jEJ6BMa1+j5swbo3hVsqFVZZLKzG7k2JG40y8oY+Y
+ +R14WAmAQGzjMJ3XuzkMieRcN5IvTcnJZdxr59ABk8hg78pv9AjleVM1CBUsLTi5bbHs
+ bWtrZN9UWZKIq0lTiqcqXx9jsBkYoAgNSGImuwDTOmdUe3DzuR60t6xq6tveQwdo/MqA
+ CAgNOgZBxpDMWaLAUj6QgBJUaOccawQDAHUwBACTGgEgLcwOQcBbgJAWdlAIdgAAvBtB
+ mAAaYy0SP7jwBoDyyB4DsMkPAd8jAfhIBCAAX4tRvRFAo5Qe49o2gNcwAgBN1oqyMAGA
+ SDmyHKAxBwwVu1DSDD7HdhYCoBsfL4s2DXiGpSJZ2yPqrJNphqcZz/V8hY7R+jFKQA3W
+ xfx1jojwO8dr8o1kE36QUfI91exo30O+CJBAHAQU2OEbhbggBIUaMMXlQlWbzH49AF0U
+ 9920BuwUYYut3gYA2sgcg4S3AVAs1wf6Vh5bnsWBpOL8UZAsBmBnBF+i1Dy1IBQAuoCF
+ 5xdOfsux4jyIrutMUAApO8AADB3uyOCigjD8AADiGoHJ57NcNLxGr5eDsH3iYrkA6CSt
+ oZRLGVCMzkM0r5OV1C9GUJVAPHToFQD4+l5nF0GO7nkMp9bMxcbyTxCKYPLatryHomFS
+ K0V4AAtBWCpWBzBF0EsNGuNm9wHwPXnAwBeKZYx/D5fkfzxA0u+pB8ZlQfoCfpV20ilR
+ MtEtIXdIt6lKH3q1/gIKAIeupPRZv++iav8CSNzuaz60k49x0z4AENgYT/QDsaIgxYxo
+ 8xACKNAGIdAAXAy/AQIYH6jsAAP4qSGi76IWHOHuGAR2ASgGoO8onIxaIkzI0wT4VMXL
+ A6IjA+paHs06A0AWem4cc4B1BeI4/kQO/oJMHwHceAAKGsF6Qc/684oULlBMJhAYkYP4
+ GfCM42/8IU3oLcH+OqaIUw++Xw++l4UOT49o+4ZEUPCozAxg0maGACqqAGrUu4j4ZxBe
+ B1BiX2/mMZBrBuRUGmFxB5CSZ+8yb8ZS8s0eK+/I7M860vD082lXAYZwP4GdELCQ/McY
+ 0Wy+UEtyTyXwujEdEXETEjC9EhEbC6c0c4PagM/jDVBnDYJLBtBwGiFrB4U2VnBImyZY
+ XeVlA+lkbpFe0a8jD/Fmb7FWKJCHAcLuti+mtclnCmTE8ou2IYS2QItwS5GE+3GJF8Ig
+ q5E3DSYbDW9dFDDcAKGeFgQcjAVnBGXRACXPG2ZLFlA2ZSdtHDD8XXEBG5HEVoH6H2Zw
+ wmH+GZHk98qml5CtEYqnEeZdHvEnExC3HxH1ExIDHzEkayB7IPGgaURlBpGpBwGaFaQc
+ 2LFUy2UNFXHG8xItIq8lBDIo81IwVmH6ieABDKH/EKGdEQTYRc6KLStmYihEBlJgI5JU
+ QE7oJPFERUGSFRIi9/GJD2I3D8tXJ8I1KAILJCOSJAOopYs6YiMcqssEYitmhKIcWKIO
+ YQJpJuAKGQFLIjFOkK8yXEtfKJG7LGcBFtI3FitbDvLI0vHbKPGMkmriefJrKe4kIW8A
+ xMRMqPDKsWsbKScyLgkJMAIxKwGKFBGy7rDtI1LBAGJDDsHGHUeepWpYBCAwsobdB9H2
+ 80xbMaPiZGlgKCjWRkJcwvLiuqWdLqTa7iq4q40AqsketmKWQ2huUkg/L8++Hy3GhSG6
+ FsQcPQ87DzA0XWFSGEGeAAFWGG1sBIA0qyBMA2soGqHEf4A+AqiAAcAUY0bgpYB2BUBA
+ MsA4AvIuZ/HRI8VGjW6LNGvEFbPVHoCbPbNQIXAgUUWDNk1eQweAsEqYqahgqxMHGqF+
+ EvJ2xq0c+5QEPmHcHoMkHSHeYaW2AsAeTiHeHofkH2H6pYAqAacoGoHGtACABY3XGXQL
+ PFFiZdKMPeH+p9CiTW1afSqsX6X8TYKWKWrqIcUlL2qszjL88KMcsYimsu7IIvKwF8Ep
+ MPIzAJFhMxQFFmm7A8XbSXHHBJLaYMH+seeIk2JpFSLHSwJQziUYI5L8KXJbIaRUF0Eh
+ Gyp5HUIhHKmy0pLJFolNF/D+lfTY0aPnHaV7HgMdLozHCvTTGHJ/T8Ik9SrbGUIeM+vU
+ I1BlIXFAJJKwFyEbN7ChLTI9CtLWVAoQkLLFTpSKZbRHUtN+IIjWV6P5TyL4/CS/JnPV
+ IgCDVXNMhEtQG2AANPO6XwsMIOSYf5PyAANg2qs3NKt8IRSpHpPoUoq5T0tWS+NMNRE7
+ GjE/GnUZGqFsENN7MRMZMUULU7PDEAlbM3WtM/Wq0YmxPNF0NdV2RDUEIcs2D5XUABS7
+ VuegBQBQAAFtXmbGTiBvXuABJMAABdX4RaRfPoF3YCAACRYIQcQhWCGzYSABIOB6ABRW
+ tUNCiAp8UoDJYqSFTgIaPqPvWXIUONWcJHKwFoELN6g5D7ANDxMVSdW7W1I489B9SdVD
+ XGH+s/XrYvZsZVEvJREkLSLSRMqkQ/Z1T3HxLfT7GUryTOTTY5GlJtGqFgD9UhAVQHT7
+ LVTpPFJ9H3T5RBalUyStTtZlXcsFC0TFGZZxIJErGHGLbHUI/LHsy5EtHrbUciLdS7aV
+ WbaZBwFeD5YNZKY/b6kbSOxvb+ZRalZVIoU7W9ajTrQra+TebIy4HGluOmf6mrEpbhaH
+ bjH5GBcvIBbdGZEUzQIIbgKIAQAEpYAyAg0US+WLbpURE9UVY+JEHuHaeIAKFYDuf6pc
+ KrA0LOZWH5cWP5WCUob+G2HeY0HyfDHAv9D4oTM6yxSLTmXIWsnHDrQJedI6mwAQeUOa
+ AiOSSCWLRdITaWJNAYMkHIGMFoRKH0Rk4NBBAcHskYT2Ro/9YwJLd3DzA8WwP+NmWWOB
+ WMIOGwHccwHoY5apUlUnSSZKy1apUzgNCDFTbiXMVGZmWCBMXszLbksyspKsIskes2A1
+ g+JjaIIeFdhI1eCThPPe/KbAbFbCYuHgcoHiAIWreZIm89LRZRN/UvhqlRhvZMlWAgH2
+ WCBKAjfgS+G5iPNM8LR4Ios6OWArEOSQz6vosNfBhSIRhWHJZqIWGqbOdmNmoanBc+qQ
+ GIF0eCeGAAA0BCcWjsMkAoAwvOHAGzAikGX8Hve0Ac2iMmHkMTL8+cfkiERkBCBU2yGo
+ GRB2BCBW06H4HyOSHKG+xSAq3AOaBcx8pfZLFsmoT2AqH8XmgegiISWLXhXjisIAAIFA
+ 4JAndBwABIUAAdDYLD4hEYlE4pFYtFXrGX+444AAXHwAAZEAH/JQA1naCQA6wAD5JJpE
+ AYLJX/IZG1mWwAA8ndLHe63MAAiFg0AAEAgGAHg63QAAYEAkAAUDZc9Hg7QABwSC6lVA
+ A32szpaEwwABWOCEAGmxl0AAmFw6AHY53FWQSCgA7XQ4wARSwawABgOCJtMpphZnJgwA
+ XiABSFHzEnlk8cKRTF8xmc1m85BoRCgJDIdndJpdND4y9Y3HQVrYk0nXKnO/JdIYHNYf
+ MoFuNtu4hupJA5HL4nwNw+Hs8wACKnudvwufzt9AuHJolug6A3gABUFXxEnn4e4KhVp/
+ N5/PB3dCYXDQd6Ph8YlqX+4ftHpBEWe6ZU4ny2reuC6ibN260ApqmTDQFA6Cpi4jowbC
+ EEt0w8Bt9BLgt440GpHAzghEA53gAFoLsiw8HPC5QVxW+UWxciL1PY0L3RfGrzvo+xwq
+ k1yImWcy8HEfAIIomsNQC30EQi6clQXDcLIlIroOBJEjwY6UmueEIDu2GQNnu8DxBZMU
+ bTI+UYtA0T3zLNbNPob83x2vEYHo3SRgHKc2IojJ6KMpAAATQE8s0kSagcBLeIeelFRG
+ FoW0FR7NxjBwI0pSFLNQjU3m/P9As7B0KvRT8PIKd9SgAAtUKcBgGMRUDz1FRFBw6kzU
+ gAclbgAbddAALFes0A9gABHKdspYADgACVkgAf1mAAdFngAftpMQ1q8Aba4AUVPgY24v
+ J2qwzrJnkAAM3K/CuUvdIAPobl2zjDjDVGzNYPjB1SxFVAC3Oi16PhfrMVqEWBAAc+Cg
+ AE2ENJe6XpqeGHRkAB8YkAAB4q5YEMIglpH6rNgnvj4ABBkV1ZJGr6V0bd309WdYoJel
+ /s2W2ZVPVIi5tVt5OFlmcZbUOd1qGGg5LoeiaKgb6G1pN33ofR+HtZZ/45MmYZ4ABwG+
+ cGKIWDoOg5F+qXomp/YoAQDMCAaVIjWtuBjo23bfSD6GzudObTnSZHOfJfqkDBswK6Dp
+ urwEHys3rjSNKqHwNJ3BSfxcJcdxE8AAfJ0baCwDhvhiCntzoABl0G4dF0eTI0bHT3fV
+ ylH+YtTgoasj8neUNyM4cBQ1CmWyd2PFd05/ayd3G/yYe50hgAAKALzUTpHWoZ+f0no+
+ k8z6dObGLsJeh3H8YaEgka2/m0aqWHmeDIhOFoLAAfZ944BAEtCdRzz4CYLLw6wBQogZ
+ 3nZL4GgQMIcgfRLQIkqGeMgoIJAUgTYuUkAgBikj8H2QIphygGgObMAsB5hB+vtOWAlf
+ Q+h8scOGPQecA33mhAeBFjJAx9jsBkW4AoNmqudaeDSHD04dQ7MyfQa0P3sESe260AgE
+ RqEFF6LNlI6RzJ8HGN87YEQJkqMEUkfw/SalagcAUpI6ByHKBQC59Re1xlIAEYEA5oQc
+ BBLiLwWLKQBgEjOASLi6x5GRAyB4BoABtDTHYuQDx7wMAbj2NAZJQQZg7a8Nc/YAAOgj
+ SGNgaQ6gABWDGC8AAHgRFRN9C9toE4ZkSY+l8GspYeSnlQRA+g1ZWN1IkOwfb3QAgOGm
+ hZDCFSRu0AAPYekEx4juS+BoDxLh/EmfygompdFxgSAqXgAsaTbE1GwNOSgG5hrrHpAM
+ DIHSXS/S+A8CTGXdIdcGlFBbLiZD9HfDFzDmiCGHYkd+UoNZUz1lSfQak+YgkRHaP11o
+ AQGy1dUv9DYxRdtZAuBxVg0hlDnQsOgcpygGAOWOB4EBLh0vzJbOEAAFgMx7G0NQlkg1
+ WIEGsNAdK5AOHvom2YcI3ERBcDVDF96+iKy3nOSQeQNHkAFnoREfNQQATzntUWHZ9BpV
+ Jlc8wmQ6x9PdH+AuWs76coYSWTIew9YBv8S+P0fjYwHARWOPUecExvjaKwCkGAF11wnI
+ THUBYDGzReXHBqDNcgADBFsN4AANwflxAUAxY48B3NPA+COThM5ynQSjVYeYM6OgIeWT
+ AkcowAA4sxUazT0akVKWM1UdY/HWj+AQNFfjOyIsvQhOheLPSLtUtY5t3dsXVACHrTwC
+ oB4aWxssDm31m7gNwPoNG4hgQDNmIiOgewzFlgFHKbZyaGUpWKSS7u6NrjfpESwnixrh
+ brkWAGPsEAAALgLePO8k1QTIg6vZcG9zRT6DPvlPsiDqrUu2QKrFl9qG7pQZybm/Dm7a
+ WUtavC/12LY3qABewHV78HMkPoM7CUQaBs7QcRGplssLYBwzhXAuF764Ew1h/DmIsPYj
+ IlPEAAPMWYPxcpY+gzMZMdWPfvAtN8LISv4cXDeNyKWqqvjs6+PcBEUH1kcAAPclYvyY
+ nmGw/8ZXMXzijDOGMTYivQgjAOVstYkujflquIMwZiwPmHLZtyTPsgmD7NmTc3JkH5nE
+ f4186ZFInifPCo2wZEy5gbPN+shY2zLgMmqgCVAl0Rm/RSLiaKIvtouHWZNIaTPNo3Sm
+ l9MaZd7f/TWndPYPICAAAA4BAAADAAAAAQBfAAABAQADAAAAAQBPAAABAgADAAAABAAA
+ GAwBAwADAAAAAQAFAAABBgADAAAAAQACAAABEQAEAAAAAQAAAAgBEgADAAAAAQABAAAB
+ FQADAAAAAQAEAAABFgADAAAAAQBPAAABFwAEAAAAAQAAF1UBHAADAAAAAQABAAABPQAD
+ AAAAAQACAAABUgADAAAAAQABAAABUwADAAAABAAAGBQAAAAAAAgACAAIAAgAAQABAAEA
+ AQ==
+ </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>{{318, 108}, {971, 888}}</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>{{-130, 0}, {836, 734}}</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/rs_overview.png b/docs/html/images/rs_overview.png
new file mode 100644
index 0000000..888063dc
--- /dev/null
+++ b/docs/html/images/rs_overview.png
Binary files differ
diff --git a/docs/html/images/ui/menu-context.png b/docs/html/images/ui/menu-context.png
new file mode 100644
index 0000000..f6975fb
--- /dev/null
+++ b/docs/html/images/ui/menu-context.png
Binary files differ
diff --git a/docs/html/images/ui/popupmenu.png b/docs/html/images/ui/popupmenu.png
new file mode 100644
index 0000000..5c99821
--- /dev/null
+++ b/docs/html/images/ui/popupmenu.png
Binary files differ
diff --git a/docs/html/index.jd b/docs/html/index.jd
index 9197b5d..b9d6758 100644
--- a/docs/html/index.jd
+++ b/docs/html/index.jd
@@ -1,4 +1,5 @@
home=true
+page.metaDescription=The official site for Android developers. Provides the Android SDK and documentation for app developers and designers.
@jd:body
@@ -142,6 +143,20 @@
+ "href='{@docRoot}sdk/api_diff/15/changes.html'>diff report</a>. If you're new to Android, "
+ "get started with the <a href='/sdk/index.html'>SDK starter package</a>.</p>"
},
+
+ 'plus': {
+ 'layout':"imgLeft",
+ 'icon':"google-plus-small.png",
+ 'name':"Google+ Page",
+ 'img':"google-plus.png",
+ 'title':"Android Developers on Google+",
+ 'desc': "<p>We now have a Google+ page for <a "
++ "href='https://plus.google.com/108967384991768947849'>+Android Developers</a>. "
++ "We'll use it to host Hangouts for developers, talk about the latest releases, "
++ "development and design tips, and much more.</p>"
++ "<div style='margin:.7em 0 0 -1.2em'><g:plus href='https://plus.google.com/108967384991768947849' "
++ "size=\"smallbadge\" width=\"275\"></g:plus></div>"
+ },
'tv': {
'layout':"imgLeft",
@@ -186,5 +201,16 @@
</script>
<script type="text/javascript" src="{@docRoot}assets/carousel.js"></script>
<script type="text/javascript">
- initCarousel("sdk");
+ initCarousel("plus");
</script>
+
+<script type="text/javascript" src="https://plus.google.com/108967384991768947849"
+rel="publisher"></script>
+<script type="text/javascript">
+window.___gcfg = {lang: 'en'};
+(function()
+{var po = document.createElement("script");
+po.type = "text/javascript"; po.async = true;po.src = "https://apis.google.com/js/plusone.js";
+var s = document.getElementsByTagName("script")[0];
+s.parentNode.insertBefore(po, s);
+})();</script>
diff --git a/docs/html/resources/community-more.jd b/docs/html/resources/community-more.jd
index df72926..3089d45 100644
--- a/docs/html/resources/community-more.jd
+++ b/docs/html/resources/community-more.jd
@@ -1,5 +1,5 @@
community=true
-page.title=IRC and Twitter
+page.title=IRC, G+, Twitter
@jd:body
<p>In addition to the <a href="community-groups.html">Android developer forums</a>, you can participate in the Android developer community through IRC and you can follow us on Twitter. </p>
@@ -45,8 +45,27 @@
</li>
</ul>
+
+<h3 id="gplus">Google+</h3>
+<p>We use a Google+ page to host Hangouts for developers, talk about the latest
+releases, development and design tips, and much more.</p>
+
+<div style='margin-top:1em'><g:plus href='https://plus.google.com/108967384991768947849'
+size='badge'></g:plus></div>
+
+
<h3 id="twitter">Twitter</h3>
<p>You can follow us on Twitter at this account:</p>
<p style="margin-left:2em;"><a href="http://twitter.com/androiddev">http://twitter.com/androiddev</a></p>
+<script type="text/javascript" src="https://plus.google.com/108967384991768947849"
+rel="publisher"></script>
+<script type="text/javascript">
+window.___gcfg = {lang: 'en'};
+(function()
+{var po = document.createElement("script");
+po.type = "text/javascript"; po.async = true;po.src = "https://apis.google.com/js/plusone.js";
+var s = document.getElementsByTagName("script")[0];
+s.parentNode.insertBefore(po, s);
+})();</script>
\ No newline at end of file
diff --git a/docs/html/resources/dashboard/opengl.jd b/docs/html/resources/dashboard/opengl.jd
index 357c1ea..d55ab2b 100644
--- a/docs/html/resources/dashboard/opengl.jd
+++ b/docs/html/resources/dashboard/opengl.jd
@@ -57,7 +57,7 @@
<div class="dashboard-panel">
<img alt="" width="400" height="250"
-src="http://chart.googleapis.com/chart?cht=p&chs=400x250&chco=c4df9b,6fad0c&chl=GL%201.1|GL%202.0%20%26%201.1&chd=t%3A9.5,90.5" />
+src="http://chart.googleapis.com/chart?cht=p&chs=400x250&chco=c4df9b,6fad0c&chl=GL%201.1%20only|GL%202.0%20%26%201.1&chd=t%3A10.7,89.3" />
<table>
<tr>
@@ -65,15 +65,15 @@
<th scope="col">Distribution</th>
</tr>
<tr>
-<td>1.1</th>
-<td>9.5%</td>
+<td>1.1 only</th>
+<td>10.7%</td>
</tr>
<tr>
-<td>2.0</th>
-<td>90.5%</td>
+<td>2.0 & 1.1</th>
+<td>89.3%</td>
</tr>
</table>
-<p><em>Data collected during a 7-day period ending on January 3, 2012</em></p>
+<p><em>Data collected during a 7-day period ending on February 1, 2012</em></p>
</div>
diff --git a/docs/html/resources/dashboard/platform-versions.jd b/docs/html/resources/dashboard/platform-versions.jd
index 2618a04..4ea52af 100644
--- a/docs/html/resources/dashboard/platform-versions.jd
+++ b/docs/html/resources/dashboard/platform-versions.jd
@@ -52,7 +52,7 @@
<div class="dashboard-panel">
<img alt="" height="250" width="470"
-src="http://chart.apis.google.com/chart?&cht=p&chs=460x250&chd=t:0.6,1.1,8.5,30.4,0.6,54.9,0.1,1.5,1.7,0.3,0.3&chl=Android%201.5|Android%201.6|Android%202.1|Android%202.2|Android%202.3|Android%202.3.3|Android%203.0|Android%203.1|Android%203.2|Android%204.0|Android%204.0.3&chco=c4df9b,6fad0c" />
+src="http://chart.apis.google.com/chart?&cht=p&chs=460x250&chd=t:0.6,1.0,7.6,27.8,0.5,58.1,0.1,1.4,1.9,0.3,0.7&chl=Android%201.5|Android%201.6|Android%202.1|Android%202.2|Android%202.3|Android%202.3.3|Android%203.0|Android%203.1|Android%203.2|Android%204.0|Android%204.0.3&chco=c4df9b,6fad0c" />
<table>
<tr>
@@ -62,24 +62,24 @@
<th>Distribution</th>
</tr>
<tr><td><a href="{@docRoot}sdk/android-1.5.html">Android 1.5</a></td><td>Cupcake</td> <td>3</td><td>0.6%</td></tr>
-<tr><td><a href="{@docRoot}sdk/android-1.6.html">Android 1.6</a></td><td>Donut</td> <td>4</td><td>1.1%</td></tr>
-<tr><td><a href="{@docRoot}sdk/android-2.1.html">Android 2.1</a></td><td>Eclair</td> <td>7</td><td>8.5%</td></tr>
-<tr><td><a href="{@docRoot}sdk/android-2.2.html">Android 2.2</a></td><td>Froyo</td> <td>8</td><td>30.4%</td></tr>
+<tr><td><a href="{@docRoot}sdk/android-1.6.html">Android 1.6</a></td><td>Donut</td> <td>4</td><td>1.0%</td></tr>
+<tr><td><a href="{@docRoot}sdk/android-2.1.html">Android 2.1</a></td><td>Eclair</td> <td>7</td><td>7.6%</td></tr>
+<tr><td><a href="{@docRoot}sdk/android-2.2.html">Android 2.2</a></td><td>Froyo</td> <td>8</td><td>27.8%</td></tr>
<tr><td><a href="{@docRoot}sdk/android-2.3.html">Android 2.3 -<br/>
- Android 2.3.2</a></td><td rowspan="2">Gingerbread</td> <td>9</td><td>0.6%</td></tr>
+ Android 2.3.2</a></td><td rowspan="2">Gingerbread</td> <td>9</td><td>0.5%</td></tr>
<tr><td><a href="{@docRoot}sdk/android-2.3.3.html">Android 2.3.3 -<br/>
- Android 2.3.7</a></td><!-- Gingerbread --> <td>10</td><td>54.9%</td></tr>
+ Android 2.3.7</a></td><!-- Gingerbread --> <td>10</td><td>58.1%</td></tr>
<tr><td><a href="{@docRoot}sdk/android-3.0.html">Android 3.0</a></td>
<td rowspan="3">Honeycomb</td> <td>11</td><td>0.1%</td></tr>
-<tr><td><a href="{@docRoot}sdk/android-3.1.html">Android 3.1</a></td><!-- Honeycomb --><td>12</td><td>1.5%</td></tr>
-<tr><td><a href="{@docRoot}sdk/android-3.2.html">Android 3.2</a></td><!-- Honeycomb --><td>13</td><td>1.7%</td></tr>
+<tr><td><a href="{@docRoot}sdk/android-3.1.html">Android 3.1</a></td><!-- Honeycomb --><td>12</td><td>1.4%</td></tr>
+<tr><td><a href="{@docRoot}sdk/android-3.2.html">Android 3.2</a></td><!-- Honeycomb --><td>13</td><td>1.9%</td></tr>
<tr><td><a href="{@docRoot}sdk/android-4.0.html">Android 4.0 -<br/>
Android 4.0.2</a></td>
<td rowspan="2">Ice Cream Sandwich</td><td>14</td><td>0.3%</td></tr>
-<tr><td><a href="{@docRoot}sdk/android-4.0.3.html">Android 4.0.3</a></td><!-- ICS --><td>15</td><td>0.3%</td></tr>
+<tr><td><a href="{@docRoot}sdk/android-4.0.3.html">Android 4.0.3</a></td><!-- ICS --><td>15</td><td>0.7%</td></tr>
</table>
-<p><em>Data collected during a 14-day period ending on January 3, 2012</em></p>
+<p><em>Data collected during a 14-day period ending on February 1, 2012</em></p>
<!--
<p style="font-size:.9em">* <em>Other: 0.1% of devices running obsolete versions</em></p>
-->
@@ -108,9 +108,9 @@
<div class="dashboard-panel">
<img alt="" height="250" width="660" style="padding:5px;background:#fff"
-src="http://chart.apis.google.com/chart?&cht=lc&chs=660x250&chxt=x,x,y,r&chxr=0,0,12|1,0,12|2,0,100|3,0,100&chxl=0%3A%7C07/01%7C07/15%7C08/01%7C08/15%7C09/01%7C09/15%7C10/01%7C10/15%7C11/01%7C11/15%7C12/01%7C12/15%7C01/01%7C1%3A%7C2011%7C%7C%7C%7C%7C%7C%7C%7C%7C%7C%7C%7C2012%7C2%3A%7C0%25%7C25%25%7C50%25%7C75%25%7C100%25%7C3%3A%7C0%25%7C25%25%7C50%25%7C75%25%7C100%25&chxp=0,0,1,2,3,4,5,6,7,8,9,10,11,12&chxtc=0,5&chd=t:99.2,99.0,98.8,98.7,98.5,98.5,98.2,98.1,98.0,99.9,99.9,99.7,99.2|97.7,97.6,97.5,97.5,97.5,97.5,97.1,97.1,97.0,99.1,99.1,99.0,98.6|95.5,95.5,95.5,95.6,95.7,95.8,95.6,95.9,95.7,97.7,97.8,97.8,97.5|77.6,79.0,80.2,81.1,82.4,83.3,83.8,84.9,85.1,87.5,88.2,88.6,89.0|17.8,20.6,24.3,27.5,31.2,34.7,38.3,41.3,44.0,48.9,52.9,55.7,58.5|16.8,20.0,23.7,26.9,30.6,34.1,37.8,40.8,43.5,48.4,52.4,55.2,57.9|0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,2.0,2.3,2.6,3.2|0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.0,1.2,1.3,1.7&chm=b,c3df9b,0,1,0|b,b8dc82,1,2,0|tAndroid 2.1,608920,2,0,15,,t::-5|b,addb67,2,3,0|tAndroid 2.2,517617,3,0,15,,t::-5|b,a3db4b,3,4,0|b,98dc2e,4,5,0|tAndroid 2.3.3,334d0a,5,0,15,,t::-5|b,8cd41b,5,6,0|b,7ec113,6,7,0|B,6fad0c,7,8,0&chg=7,25&chdl=Android 1.5|Android 1.6|Android 2.1|Android 2.2|Android 2.3|Android 2.3.3|Android 3.1|Android 3.2&chco=add274,a2d15a,97d13e,8bcb28,7dba1e,6ea715,5f920e,507d08" />
+src="http://chart.apis.google.com/chart?&cht=lc&chs=660x250&chxt=x,x,y,r&chxr=0,0,12|1,0,12|2,0,100|3,0,100&chxl=0%3A%7C08/01%7C08/15%7C09/01%7C09/15%7C10/01%7C10/15%7C11/01%7C11/15%7C12/01%7C12/15%7C01/01%7C01/15%7C02/01%7C1%3A%7C2011%7C%7C%7C%7C%7C%7C%7C%7C%7C%7C2012%7C%7C2012%7C2%3A%7C0%25%7C25%25%7C50%25%7C75%25%7C100%25%7C3%3A%7C0%25%7C25%25%7C50%25%7C75%25%7C100%25&chxp=0,0,1,2,3,4,5,6,7,8,9,10,11,12&chxtc=0,5&chd=t:98.2,98.1,97.9,97.9,97.7,97.6,97.5,99.4,99.4,99.2,98.6,98.4,98.5|96.9,96.9,96.9,96.9,96.6,96.6,96.5,98.6,98.6,98.5,98.0,97.8,97.9|94.9,95.0,95.1,95.2,95.1,95.4,95.2,97.2,97.3,97.3,96.9,96.8,96.9|79.6,80.5,81.8,82.7,83.3,84.4,84.6,87.0,87.7,88.1,88.4,88.8,89.2|23.7,26.9,30.6,34.1,37.8,40.8,43.5,48.4,52.4,55.2,57.9,59.7,61.3|0.0,0.0,0.0,0.0,0.0,0.0,0.0,2.0,2.3,2.6,3.2,3.2,3.3|0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.0,1.2,1.3,1.7,1.8,1.9&chm=b,c3df9b,0,1,0|b,b6dc7d,1,2,0|tAndroid%202.1,5b831d,2,0,15,,t::-5|b,aadb5e,2,3,0|tAndroid%202.2,496c13,3,0,15,,t::-5|b,9ddb3d,3,4,0|tAndroid%202.3.3,38540b,4,0,15,,t::-5|b,91da1e,4,5,0|b,80c414,5,6,0|B,6fad0c,6,7,0&chg=7,25&chdl=Android%201.5|Android%201.6|Android%202.1|Android%202.2|Android%202.3.3|Android%203.1|Android%203.2&chco=add274,a0d155,94d134,84c323,73ad18,62960f,507d08" />
-<p><em>Last historical dataset collected during a 14-day period ending on January 3, 2012</em></p>
+<p><em>Last historical dataset collected during a 14-day period ending on February 1, 2012</em></p>
</div><!-- end dashboard-panel -->
diff --git a/docs/html/resources/dashboard/screens.jd b/docs/html/resources/dashboard/screens.jd
index 79d59d9..ae5cdc7 100644
--- a/docs/html/resources/dashboard/screens.jd
+++ b/docs/html/resources/dashboard/screens.jd
@@ -60,7 +60,7 @@
<div class="dashboard-panel">
<img alt="" width="400" height="250"
-src="http://chart.googleapis.com/chart?cht=p&chs=400x250&chco=c4df9b,6fad0c&chl=Xlarge%20/%20mdpi|Large%20/%20ldpi|Large%20/%20mdpi|Normal%20/%20hdpi|Normal%20/%20ldpi|Normal%20/%20mdpi|Small%20/%20hdpi|Small%20/%20ldpi&chd=t%3A3.1,0.1,3.1,71.0,1.0,17.5,2.9,1.3" />
+src="http://chart.googleapis.com/chart?cht=p&chs=400x250&chco=c4df9b,6fad0c&chl=Xlarge%20/%20mdpi|Large%20/%20ldpi|Large%20/%20mdpi|Normal%20/%20hdpi|Normal%20/%20ldpi|Normal%20/%20mdpi|Normal%20/%20xhdpi|Small%20/%20hdpi|Small%20/%20ldpi&chd=t%3A4.8,0.2,2.9,67.1,0.7,18.4,1.8,2.5,1.6" />
<table>
<tr>
@@ -71,31 +71,31 @@
<th scope="col">xhdpi</th>
</tr>
<tr><th scope="row">small</th>
-<td>1.3%</td> <!-- small/ldpi -->
+<td>1.6%</td> <!-- small/ldpi -->
<td></td> <!-- small/mdpi -->
-<td>2.9%</td> <!-- small/hdpi -->
+<td>2.5%</td> <!-- small/hdpi -->
<td></td> <!-- small/xhdpi -->
</tr>
<tr><th scope="row">normal</th>
-<td>1.0%</td> <!-- normal/ldpi -->
-<td>17.5%</td> <!-- normal/mdpi -->
-<td>71%</td> <!-- normal/hdpi -->
-<td></td> <!-- normal/xhdpi -->
+<td>0.7%</td> <!-- normal/ldpi -->
+<td>18.4%</td> <!-- normal/mdpi -->
+<td>67.1%</td> <!-- normal/hdpi -->
+<td>1.8%</td> <!-- normal/xhdpi -->
</tr>
<tr><th scope="row">large</th>
-<td>0.1%</td> <!-- large/ldpi -->
-<td>3.1%</td> <!-- large/mdpi -->
+<td>0.2%</td> <!-- large/ldpi -->
+<td>2.9%</td> <!-- large/mdpi -->
<td></td> <!-- large/hdpi -->
<td></td> <!-- large/xhdpi -->
</tr>
<tr><th scope="row">xlarge</th>
<td></td> <!-- xlarge/ldpi -->
-<td>3.1%</td> <!-- xlarge/mdpi -->
+<td>4.8%</td> <!-- xlarge/mdpi -->
<td></td> <!-- xlarge/hdpi -->
<td></td> <!-- xlarge/xhdpi -->
</tr>
</table>
-<p><em>Data collected during a 7-day period ending on December 1, 2011</em></p>
+<p><em>Data collected during a 7-day period ending on February 1, 2012</em></p>
</div>
diff --git a/docs/html/resources/resources_toc.cs b/docs/html/resources/resources_toc.cs
index 8df419f..8483037 100644
--- a/docs/html/resources/resources_toc.cs
+++ b/docs/html/resources/resources_toc.cs
@@ -1,7 +1,8 @@
<ul>
<li>
- <h2><span class="en">Android Training</span>
- </h2>
+ <span class="heading">
+ <span class="en">Android Training</span>
+ </span>
<ul>
<li><a href="<?cs var:toroot ?>training/index.html">
@@ -237,8 +238,9 @@
<li>
- <h2><span class="en">Technical Resources</span>
- </h2>
+ <span class="heading">
+ <span class="en">Technical Resources</span>
+ </span>
<ul>
<li class="toggle-list">
<div><a href="<?cs var:toroot ?>resources/browser.html?tag=sample">
@@ -288,29 +290,31 @@
</ul>
</li>
<li>
- <h2><span class="en">Community</span>
- <span style="display:none" class="de"></span>
- <span style="display:none" class="es">Comunidad</span>
- <span style="display:none" class="fr">Communauté</span>
- <span style="display:none" class="it"></span>
- <span style="display:none" class="ja">コミュニティ</span>
- <span style="display:none" class="zh-CN">社区</span>
- <span style="display:none" class="zh-TW">社群</span>
- </h2>
+ <span class="heading">
+ <span class="en">Community</span>
+ <span style="display:none" class="de"></span>
+ <span style="display:none" class="es">Comunidad</span>
+ <span style="display:none" class="fr">Communauté</span>
+ <span style="display:none" class="it"></span>
+ <span style="display:none" class="ja">コミュニティ</span>
+ <span style="display:none" class="zh-CN">社区</span>
+ <span style="display:none" class="zh-TW">社群</span>
+ </span>
<ul>
<li><a href="<?cs var:toroot ?>resources/community-groups.html">
<span class="en">Developer Forums</span>
</a></li>
<li><a href="<?cs var:toroot ?>resources/community-more.html">
- <span class="en">IRC, Twitter</span>
+ <span class="en">IRC, G+, Twitter</span>
</a></li>
</ul>
</li>
<?cs
if:android.whichdoc == "online" ?>
<li>
- <h2><span class="en">Device Dashboard</span>
- </h2>
+ <span class="heading">
+ <span class="en">Device Dashboard</span>
+ </span>
<ul>
<li><a href="<?cs var:toroot ?>resources/dashboard/platform-versions.html">
<span class="en">Platform Versions</span>
@@ -327,7 +331,9 @@
?>
<li>
- <h2><span class="en">More</span></h2>
+ <span class="heading">
+ <span class="en">More</span>
+ </span>
<ul>
<li><a href="<?cs var:toroot ?>resources/faq/commontasks.html">
<span class="en">Common Tasks </span>
diff --git a/docs/html/resources/tutorials/hello-world.jd b/docs/html/resources/tutorials/hello-world.jd
index 9afab6a..cc8cb3e 100644
--- a/docs/html/resources/tutorials/hello-world.jd
+++ b/docs/html/resources/tutorials/hello-world.jd
@@ -24,7 +24,7 @@
management to greatly speed up your development cycles.</p>
<p>This tutorial assumes that you're using Eclipse. If you're using the command line, see
-<a href="{@docRoot}/guide/developing/building/building-cmdline.html">Building and Running from the
+<a href="{@docRoot}guide/developing/building/building-cmdline.html">Building and Running from the
Command Line</a>. You can then return to this tutorial and ignore anything about Eclipse.</p>
<p>Before you start, you should already have the SDK installed, and if you're
diff --git a/docs/html/sdk/android-2.3.3.jd b/docs/html/sdk/android-2.3.3.jd
index 7a5b044..023e2e4 100644
--- a/docs/html/sdk/android-2.3.3.jd
+++ b/docs/html/sdk/android-2.3.3.jd
@@ -336,7 +336,7 @@
<li>English, New Zealand (en_NZ)</li>
<li>English, Singapore(en_SG)</li>
<li>English, US (en_US)</li>
-<li>English, Zimbabwe (en_ZA)</li>
+<li>English, South Africa (en_ZA)</li>
<li>Spanish (es_ES)</li>
<li>Spanish, US (es_US)</li>
<li>Finnish, Finland (fi_FI)</li>
diff --git a/docs/html/sdk/android-2.3.4.jd b/docs/html/sdk/android-2.3.4.jd
index 4cb44b9..eeaa69a 100644
--- a/docs/html/sdk/android-2.3.4.jd
+++ b/docs/html/sdk/android-2.3.4.jd
@@ -296,7 +296,7 @@
<li>English, New Zealand (en_NZ)</li>
<li>English, Singapore(en_SG)</li>
<li>English, US (en_US)</li>
-<li>English, Zimbabwe (en_ZA)</li>
+<li>English, South Africa (en_ZA)</li>
<li>Spanish (es_ES)</li>
<li>Spanish, US (es_US)</li>
<li>Finnish, Finland (fi_FI)</li>
diff --git a/docs/html/sdk/android-2.3.jd b/docs/html/sdk/android-2.3.jd
index e7aa0fa..fc4f5aa 100644
--- a/docs/html/sdk/android-2.3.jd
+++ b/docs/html/sdk/android-2.3.jd
@@ -859,7 +859,7 @@
<li>English, New Zealand (en_NZ)</li>
<li>English, Singapore(en_SG)</li>
<li>English, US (en_US)</li>
-<li>English, Zimbabwe (en_ZA)</li>
+<li>English, South Africa (en_ZA)</li>
<li>Spanish (es_ES)</li>
<li>Spanish, US (es_US)</li>
<li>Finnish, Finland (fi_FI)</li>
diff --git a/docs/html/sdk/android-3.0.jd b/docs/html/sdk/android-3.0.jd
index 96b92d9..49fefee 100644
--- a/docs/html/sdk/android-3.0.jd
+++ b/docs/html/sdk/android-3.0.jd
@@ -1119,7 +1119,7 @@
<li>English, New Zealand (en_NZ)</li>
<li>English, Singapore(en_SG)</li>
<li>English, US (en_US)</li>
-<li>English, Zimbabwe (en_ZA)</li>
+<li>English, South Africa (en_ZA)</li>
<li>Spanish (es_ES)</li>
<li>Spanish, US (es_US)</li>
<li>Finnish, Finland (fi_FI)</li>
diff --git a/docs/html/sdk/android-3.1.jd b/docs/html/sdk/android-3.1.jd
index 78f265d..b9cf969 100644
--- a/docs/html/sdk/android-3.1.jd
+++ b/docs/html/sdk/android-3.1.jd
@@ -1040,7 +1040,7 @@
<li>English, New Zealand (en_NZ)</li>
<li>English, Singapore(en_SG)</li>
<li>English, US (en_US)</li>
-<li>English, Zimbabwe (en_ZA)</li>
+<li>English, South Africa (en_ZA)</li>
<li>Spanish (es_ES)</li>
<li>Spanish, US (es_US)</li>
<li>Finnish, Finland (fi_FI)</li>
diff --git a/docs/html/sdk/android-4.0.3.jd b/docs/html/sdk/android-4.0.3.jd
index 1fca8df..809c83c 100644
--- a/docs/html/sdk/android-4.0.3.jd
+++ b/docs/html/sdk/android-4.0.3.jd
@@ -435,7 +435,7 @@
<li>English, New Zealand (en_NZ)</li>
<li>English, Singapore(en_SG)</li>
<li>English, US (en_US)</li>
-<li>English, Zimbabwe (en_ZA)</li>
+<li>English, South Africa (en_ZA)</li>
<li>Spanish (es_ES)</li>
<li>Spanish, US (es_US)</li>
<li>Finnish, Finland (fi_FI)</li>
diff --git a/docs/html/sdk/android-4.0.jd b/docs/html/sdk/android-4.0.jd
index 5f55947..2cad86b 100644
--- a/docs/html/sdk/android-4.0.jd
+++ b/docs/html/sdk/android-4.0.jd
@@ -1963,7 +1963,7 @@
<li>English, New Zealand (en_NZ)</li>
<li>English, Singapore(en_SG)</li>
<li>English, US (en_US)</li>
-<li>English, Zimbabwe (en_ZA)</li>
+<li>English, South Africa (en_ZA)</li>
<li>Spanish (es_ES)</li>
<li>Spanish, US (es_US)</li>
<li>Finnish, Finland (fi_FI)</li>
diff --git a/docs/html/sdk/eclipse-adt.jd b/docs/html/sdk/eclipse-adt.jd
index f15da78..30825ee 100644
--- a/docs/html/sdk/eclipse-adt.jd
+++ b/docs/html/sdk/eclipse-adt.jd
@@ -42,7 +42,7 @@
<p>Developing in Eclipse with ADT is highly recommended and is the fastest way
to get started. With the guided project setup it provides, as well as tools
-integration, custom XML editors, and debug ouput pane, ADT gives you an
+integration, custom XML editors, and debug output pane, ADT gives you an
incredible boost in developing Android applications. </p>
<p>This document provides step-by-step instructions on how to download the ADT
@@ -1104,7 +1104,7 @@
<h3 id="downloading">Downloading the ADT Plugin</h3>
<p>Use the Update Manager feature of your Eclipse installation to install the latest
-revision of ADT on your development computer.<>
+revision of ADT on your development computer.</p>
<p>Assuming that you have a compatible version of the Eclipse IDE installed, as
described in <a href="#preparing">Preparing for Installation</a>, above, follow
diff --git a/docs/html/sdk/index.jd b/docs/html/sdk/index.jd
index 65a1f46..5cf05e0 100644
--- a/docs/html/sdk/index.jd
+++ b/docs/html/sdk/index.jd
@@ -1,4 +1,5 @@
page.title=Android SDK
+page.metaDescription=Download the official Android SDK to develop apps for Android-powered devices.
sdk.redirect=0
sdk.win_installer=installer_r16-windows.exe
diff --git a/docs/html/sdk/sdk_toc.cs b/docs/html/sdk/sdk_toc.cs
index 5f6a57f..0de477a 100644
--- a/docs/html/sdk/sdk_toc.cs
+++ b/docs/html/sdk/sdk_toc.cs
@@ -1,7 +1,7 @@
<?cs if:!sdk.redirect ?>
<ul>
<li>
- <h2>
+ <span class="heading">
<span class="en">Android SDK Starter Package</span>
<span style="display:none" class="de">Aktuelle SDK-Version</span>
<span style="display:none" class="es">Versión actual del SDK</span>
@@ -10,7 +10,7 @@
<span style="display:none" class="ja">現在リリースされている SDK</span>
<span style="display:none" class="zh-CN">当前的 SDK 版本</span>
<span style="display:none" class="zh-TW">目前 SDK 發行版本</span>
- </h2>
+ </span>
<ul><?cs
if:android.whichdoc == "online" ?>
<li><a href="<?cs var:toroot ?>sdk/index.html">
@@ -37,7 +37,8 @@
</ul>
</li><?cs
if:sdk.preview ?>
- <li><h2>Android 3.0 Preview SDK</h2>
+ <li>
+ <span class="heading">Android 3.0 Preview SDK</span>
<ul>
<li><a href="<?cs var:toroot ?>sdk/preview/start.html">Getting Started</a> <span
class="new">new!</span></li>
@@ -46,13 +47,14 @@
/if ?>
<?cs
if:sdk.preview ?>
- <li><h2>Android x.x Preview</h2>
+ <li>
+ <span class="heading">Android x.x Preview</span>
<ul>
</ul>
</li><?cs
/if ?>
<li>
- <h2>
+ <span class="heading">
<span class="en">Downloadable SDK Components</span>
<span style="display:none" class="de"></span>
<span style="display:none" class="es"></span>
@@ -61,7 +63,7 @@
<span style="display:none" class="ja"></span>
<span style="display:none" class="zh-CN"></span>
<span style="display:none" class="zh-TW"></span>
- </h2>
+ </span>
<ul>
<li><a href="<?cs var:toroot ?>sdk/adding-components.html">
<span class="en">Adding SDK Components</span>
@@ -158,7 +160,7 @@
</ul>
</li>
<li>
- <h2>
+ <span class="heading">
<span class="en">ADT Plugin for Eclipse</span>
<span style="display:none" class="de"></span>
<span style="display:none" class="es"></span>
@@ -167,7 +169,7 @@
<span style="display:none" class="ja"></span>
<span style="display:none" class="zh-CN"></span>
<span style="display:none" class="zh-TW"></span>
- </h2>
+ </span>
<ul>
<li><a href="<?cs var:toroot ?>sdk/eclipse-adt.html">ADT 16.0.1
<span style="display:none" class="de"></span>
@@ -182,7 +184,8 @@
</ul>
</li>
<li>
- <h2><span class="en">Native Development Tools</span>
+ <span class="heading">
+ <span class="en">Native Development Tools</span>
<span style="display:none" class="de"></span>
<span style="display:none" class="es"></span>
<span style="display:none" class="fr"></span>
@@ -190,7 +193,7 @@
<span style="display:none" class="ja"></span>
<span style="display:none" class="zh-CN"></span>
<span style="display:none" class="zh-TW"></span>
- </h2>
+ </span>
<ul>
<li><a href="<?cs var:toroot ?>sdk/ndk/index.html">Android NDK, r7</a>
<span class="new">new!</span>
@@ -200,7 +203,7 @@
</li>
<li>
- <h2>
+ <span class="heading">
<span class="en">More Information</span>
<span style="display:none" class="de"></span>
<span style="display:none" class="es"></span>
@@ -209,7 +212,7 @@
<span style="display:none" class="ja"></span>
<span style="display:none" class="zh-CN"></span>
<span style="display:none" class="zh-TW"></span>
- </h2>
+ </span>
<ul>
<li><a href="<?cs var:toroot ?>sdk/oem-usb.html">
<span class="en">OEM USB Drivers</span>
diff --git a/docs/html/shareables/adl/2010Q2_Business_Overview.pdf b/docs/html/shareables/adl/2010Q2_Business_Overview.pdf
deleted file mode 100644
index c34ea15..0000000
--- a/docs/html/shareables/adl/2010Q2_Business_Overview.pdf
+++ /dev/null
Binary files differ
diff --git a/docs/html/shareables/adl/2010Q2_Market_Overview.pdf b/docs/html/shareables/adl/2010Q2_Market_Overview.pdf
deleted file mode 100644
index 3752258..0000000
--- a/docs/html/shareables/adl/2010Q2_Market_Overview.pdf
+++ /dev/null
Binary files differ
diff --git a/docs/html/shareables/adl/2010Q2_SDK_Overview.pdf b/docs/html/shareables/adl/2010Q2_SDK_Overview.pdf
deleted file mode 100644
index 8796584..0000000
--- a/docs/html/shareables/adl/2010Q2_SDK_Overview.pdf
+++ /dev/null
Binary files differ
diff --git a/docs/html/shareables/adl/2011Q3_Android_Market_for_Developers.pdf b/docs/html/shareables/adl/2011Q3_Android_Market_for_Developers.pdf
deleted file mode 100644
index 598a27e..0000000
--- a/docs/html/shareables/adl/2011Q3_Android_Market_for_Developers.pdf
+++ /dev/null
Binary files differ
diff --git a/docs/html/shareables/adl/2011Q3_Designing_UIs_for_Phones_and_Tablets.pdf b/docs/html/shareables/adl/2011Q3_Designing_UIs_for_Phones_and_Tablets.pdf
deleted file mode 100644
index 6ef41dd..0000000
--- a/docs/html/shareables/adl/2011Q3_Designing_UIs_for_Phones_and_Tablets.pdf
+++ /dev/null
Binary files differ
diff --git a/docs/html/shareables/adl/2011Q3_Introduction_to_Honeycomb_APIs.pdf b/docs/html/shareables/adl/2011Q3_Introduction_to_Honeycomb_APIs.pdf
deleted file mode 100755
index e56d2377..0000000
--- a/docs/html/shareables/adl/2011Q3_Introduction_to_Honeycomb_APIs.pdf
+++ /dev/null
Binary files differ
diff --git a/docs/html/shareables/icon_templates-v1.0.zip b/docs/html/shareables/icon_templates-v1.0.zip
deleted file mode 100644
index 94fbcdc..0000000
--- a/docs/html/shareables/icon_templates-v1.0.zip
+++ /dev/null
Binary files differ
diff --git a/docs/html/sitemap.txt b/docs/html/sitemap.txt
index 0298a8e..cfbda2b 100644
--- a/docs/html/sitemap.txt
+++ b/docs/html/sitemap.txt
@@ -231,7 +231,6 @@
http://developer.android.com/resources/samples/CubeLiveWallpaper/index.html
http://developer.android.com/resources/samples/LunarLander/index.html
http://developer.android.com/resources/samples/MultiResolution/index.html
-http://developer.android.com/resources/samples/NFCDemo/index.html
http://developer.android.com/resources/samples/NotePad/index.html
http://developer.android.com/resources/samples/SampleSyncAdapter/index.html
http://developer.android.com/resources/samples/SearchableDictionary/index.html
@@ -1996,17 +1995,6 @@
http://developer.android.com/reference/android/content/DialogInterface.html
http://developer.android.com/reference/org/apache/http/message/BasicHeaderIterator.html
http://developer.android.com/reference/org/apache/http/message/BasicListHeaderIterator.html
-http://developer.android.com/resources/samples/NFCDemo/src/com/example/android/nfc/TagViewer.html
-http://developer.android.com/resources/samples/NFCDemo/src/com/example/android/nfc/NdefMessageParser.html
-http://developer.android.com/resources/samples/NFCDemo/src/com/example/android/nfc/record/ParsedNdefRecord.html
-http://developer.android.com/resources/samples/NFCDemo/src/com/example/android/nfc/record/SmartPoster.html
-http://developer.android.com/resources/samples/NFCDemo/src/com/example/android/nfc/record/TextRecord.html
-http://developer.android.com/resources/samples/NFCDemo/src/com/example/android/nfc/record/UriRecord.html
-http://developer.android.com/resources/samples/NFCDemo/src/com/example/android/nfc/simulator/FakeTagsActivity.html
-http://developer.android.com/resources/samples/NFCDemo/src/com/example/android/nfc/simulator/MockNdefMessages.html
-http://developer.android.com/resources/samples/NFCDemo/res/index.html
-http://developer.android.com/resources/samples/NFCDemo/src/index.html
-http://developer.android.com/resources/samples/NFCDemo/AndroidManifest.html
http://developer.android.com/reference/java/lang/InternalError.html
http://developer.android.com/reference/java/lang/Error.html
http://developer.android.com/reference/java/lang/VirtualMachineError.html
@@ -3039,7 +3027,6 @@
http://developer.android.com/sdk/api_diff/3/changes/pkg_java.lang.html
http://developer.android.com/sdk/api_diff/3/changes/pkg_java.util.jar.html
http://developer.android.com/sdk/api_diff/3/changes/pkg_java.util.logging.html
-http://developer.android.com/resources/samples/NFCDemo/src/com/index.html
http://developer.android.com/sdk/api_diff/9/changes/alldiffs_index_removals.html
http://developer.android.com/sdk/api_diff/9/changes/alldiffs_index_additions.html
http://developer.android.com/sdk/api_diff/9/changes/alldiffs_index_changes.html
@@ -3514,7 +3501,6 @@
http://developer.android.com/resources/samples/ApiDemos/src/com/example/android/apis/view/LabelView.html
http://developer.android.com/resources/samples/ApiDemos/res/layout/custom_view_1.html
http://developer.android.com/resources/samples/NotePad/src/com/example/android/notepad/NoteEditor.html
-http://developer.android.com/resources/samples/NFCDemo/src/com/example/index.html
http://developer.android.com/reference/org/apache/http/conn/ssl/SSLSocketFactory.html
http://developer.android.com/reference/android/location/package-descr.html
http://developer.android.com/resources/samples/AccessibilityService/res/values/strings.html
@@ -3939,10 +3925,6 @@
http://developer.android.com/resources/samples/ContactManager/res/drawable-mdpi/icon.html
http://developer.android.com/resources/samples/BackupRestore/src/com/example/index.html
http://developer.android.com/reference/org/apache/http/message/package-descr.html
-http://developer.android.com/resources/samples/NFCDemo/res/drawable/index.html
-http://developer.android.com/resources/samples/NFCDemo/res/layout/index.html
-http://developer.android.com/resources/samples/NFCDemo/res/raw/index.html
-http://developer.android.com/resources/samples/NFCDemo/res/values/index.html
http://developer.android.com/reference/android/bluetooth/package-descr.html
http://developer.android.com/resources/samples/SipDemo/res/drawable/index.html
http://developer.android.com/resources/samples/SipDemo/res/layout/index.html
@@ -4110,7 +4092,6 @@
http://developer.android.com/sdk/api_diff/9/changes/methods_index_additions.html
http://developer.android.com/sdk/api_diff/9/changes/methods_index_changes.html
http://developer.android.com/reference/android/media/audiofx/package-descr.html
-http://developer.android.com/resources/samples/NFCDemo/res/values/strings.html
http://developer.android.com/reference/android/sax/ElementListener.html
http://developer.android.com/reference/android/sax/EndElementListener.html
http://developer.android.com/reference/android/sax/EndTextElementListener.html
@@ -4599,7 +4580,6 @@
http://developer.android.com/reference/android/text/method/package-descr.html
http://developer.android.com/resources/samples/JetBoy/JETBOY_content/JETBOY_Music.logic/LgDoc/index.html
http://developer.android.com/resources/samples/TicTacToeMain/res/layout/main.html
-http://developer.android.com/resources/samples/NFCDemo/src/com/example/android/index.html
http://developer.android.com/resources/samples/SearchableDictionary/res/drawable-mdpi/ic_menu_search.html
http://developer.android.com/resources/samples/TicTacToeMain/res/values/strings.html
http://developer.android.com/sdk/api_diff/7/changes/alldiffs_index_additions.html
@@ -4637,9 +4617,6 @@
http://developer.android.com/resources/samples/SoftKeyboard/res/values-land/index.html
http://developer.android.com/resources/samples/SoftKeyboard/res/xml/index.html
http://developer.android.com/reference/junit/runner/package-descr.html
-http://developer.android.com/resources/samples/NFCDemo/res/layout/tag_divider.html
-http://developer.android.com/resources/samples/NFCDemo/res/layout/tag_text.html
-http://developer.android.com/resources/samples/NFCDemo/res/layout/tag_viewer.html
http://developer.android.com/resources/samples/AccelerometerPlay/res/drawable-ldpi/icon.html
http://developer.android.com/resources/samples/CubeLiveWallpaper/src/com/example/index.html
http://developer.android.com/reference/android/text/style/package-descr.html
@@ -4726,14 +4703,12 @@
http://developer.android.com/sdk/api_diff/3/changes/classes_index_additions.html
http://developer.android.com/sdk/api_diff/3/changes/classes_index_changes.html
http://developer.android.com/resources/samples/WiktionarySimple/src/com/index.html
-http://developer.android.com/resources/samples/NFCDemo/res/drawable/icon.html
http://developer.android.com/resources/samples/SearchableDictionary/res/drawable-hdpi/ic_menu_search.html
http://developer.android.com/resources/samples/SipDemo/res/values/strings.html
http://developer.android.com/resources/samples/SpinnerTest/src/com/android/index.html
http://developer.android.com/sdk/api_diff/3/changes/methods_index_removals.html
http://developer.android.com/sdk/api_diff/3/changes/methods_index_additions.html
http://developer.android.com/sdk/api_diff/3/changes/methods_index_changes.html
-http://developer.android.com/resources/samples/NFCDemo/src/com/example/android/nfc/index.html
http://developer.android.com/resources/samples/SoftKeyboard/res/xml/method.html
http://developer.android.com/resources/samples/SoftKeyboard/res/xml/qwerty.html
http://developer.android.com/resources/samples/SoftKeyboard/res/xml/symbols.html
@@ -5326,8 +5301,6 @@
http://developer.android.com/sdk/api_diff/5/changes/alldiffs_index_removals.html
http://developer.android.com/sdk/api_diff/5/changes/alldiffs_index_additions.html
http://developer.android.com/sdk/api_diff/5/changes/alldiffs_index_changes.html
-http://developer.android.com/resources/samples/NFCDemo/src/com/example/android/nfc/record/index.html
-http://developer.android.com/resources/samples/NFCDemo/src/com/example/android/nfc/simulator/index.html
http://developer.android.com/resources/samples/BackupRestore/src/com/example/android/index.html
http://developer.android.com/resources/samples/BluetoothChat/src/com/example/android/BluetoothChat/index.html
http://developer.android.com/resources/samples/ContactManager/src/com/example/android/index.html
diff --git a/docs/html/training/design-navigation/ancestral-temporal.jd b/docs/html/training/design-navigation/ancestral-temporal.jd
index 02e43e1..c0b1aef 100644
--- a/docs/html/training/design-navigation/ancestral-temporal.jd
+++ b/docs/html/training/design-navigation/ancestral-temporal.jd
@@ -21,6 +21,7 @@
<h2>You should also read</h2>
<ul>
+ <li><a href="{@docRoot}design/patterns/navigation.html">Android Design: Navigation</a></li>
<li><a href="{@docRoot}guide/topics/fundamentals/tasks-and-back-stack.html">Tasks and Back Stack</a></li>
</ul>
@@ -30,6 +31,11 @@
<p>Now that users can navigate <a href="descendant-lateral.html">deep into</a> the application's screen hierarchy, we need to provide a method for navigating up the hierarchy, to parent and ancestor screens. Additionally, we should ensure that temporal navigation via the BACK button is respected to respect Android conventions.</p>
+<div class="design-announce">
+<p><strong>Back/Up Navigation Design</strong></p>
+ <p>For design guidelines, read Android Design's <a
+ href="{@docRoot}design/patterns/navigation.html">Navigation</a> pattern guide.</p>
+</div>
<h2 id="temporal-navigation">Support Temporal Navigation: <em>Back</em></h2>
@@ -49,7 +55,7 @@
<h2 id="ancestral-navigation">Provide Ancestral Navigation: <em>Up</em> and <em>Home</em></h2>
-<p>Before Android 3.0, the most common form of ancestral navigation was the <em>Home</em> metaphor. This was generally implemented as a <em>Home</em> item accessible via the device's MENU button, or a <em>Home</em> button at the top-left of the screen, usually as a component of the <a href="{@docRoot}guide/topics/ui/actionbar.html">Action Bar</a>. Upon selecting <em>Home</em>, the user would be taken to the screen at the top of the screen hierarchy, generally known as the application's home screen.</p>
+<p>Before Android 3.0, the most common form of ancestral navigation was the <em>Home</em> metaphor. This was generally implemented as a <em>Home</em> item accessible via the device's MENU button, or a <em>Home</em> button at the top-left of the screen, usually as a component of the Action Bar (<a href="{@docRoot}design/patterns/actionbar.html">pattern docs</a> at Android Design). Upon selecting <em>Home</em>, the user would be taken to the screen at the top of the screen hierarchy, generally known as the application's home screen.</p>
<p>Providing direct access to the application's home screen can give the user a sense of comfort and security. Regardless of where they are in the application, if they get lost in the app, they can select <em>Home</em> to arrive back at the familiar home screen.</p>
diff --git a/docs/html/training/design-navigation/descendant-lateral.jd b/docs/html/training/design-navigation/descendant-lateral.jd
index ebfd913..0064bd4 100644
--- a/docs/html/training/design-navigation/descendant-lateral.jd
+++ b/docs/html/training/design-navigation/descendant-lateral.jd
@@ -18,9 +18,18 @@
<li><a href="#buttons">Buttons and Simple Targets</a></li>
<li><a href="#lists">Lists, Grids, Carousels, and Stacks</a></li>
<li><a href="#tabs">Tabs</a></li>
- <li><a href="#paging">Horizontal Paging</a></li>
+ <li><a href="#paging">Horizontal Paging (Swipe Views)</a></li>
</ol>
+<h2>You should also read</h2>
+<ul>
+ <li><a href="{@docRoot}design/building-blocks/buttons.html">Android Design: Buttons</a></li>
+ <li><a href="{@docRoot}design/building-blocks/lists.html">Android Design: Lists</a></li>
+ <li><a href="{@docRoot}design/building-blocks/grid-lists.html">Android Design: Grid Lists</a></li>
+ <li><a href="{@docRoot}design/building-blocks/tabs.html">Android Design: Tabs</a></li>
+ <li><a href="{@docRoot}design/patterns/swipe-views.html">Android Design: Swipe Views</a></li>
+</ul>
+
</div>
</div>
@@ -48,6 +57,12 @@
<h2 id="buttons">Buttons and Simple Targets</h2>
+<div class="design-announce">
+<p><strong>Button Design</strong></p>
+ <p>For design guidelines, read Android Design's <a
+ href="{@docRoot}design/building-blocks/buttons.html">Buttons</a> guide.</p>
+</div>
+
<p>For section-related screens, offering touchable and keyboard-focusable targets in the parent is generally the most straightforward and familiar kind of touch-based navigation interface. Examples of such targets include buttons, fixed-size list views, or text links, although the latter is not an ideal UI (user interface) element for touch-based navigation. Upon selecting one of these targets, the child screen is opened, replacing the current context (screen) entirely. Buttons and other simple targets are rarely used for representing items in a collection.</p>
@@ -64,6 +79,13 @@
<h2 id="lists">Lists, Grids, Carousels, and Stacks</h2>
+<div class="design-announce">
+<p><strong>List and Grid List Design</strong></p>
+ <p>For design guidelines, read Android Design's <a
+ href="{@docRoot}design/building-blocks/lists.html">Lists</a> and <a
+ href="{@docRoot}design/building-blocks/grid-lists.html">Grid Lists</a> guides.</p>
+</div>
+
<p>For collection-related screens, and especially for textual information, vertically scrolling lists are often the most straightforward and familiar kind of interface. For more visual or media-rich content items such as photos or videos, vertically scrolling grids of items, horizontally scrolling lists (sometimes referred to as <em>carousels</em>), or stacks (sometimes referred to as <em>cards</em>) can be used instead. These UI elements are generally best used for presenting item collections or large sets of child screens (for example, a list of stories or a list of 10 or more news topics), rather than a small set of unrelated, sibling child screens.</p>
@@ -80,6 +102,12 @@
<h2 id="tabs">Tabs</h2>
+<div class="design-announce">
+<p><strong>Tab Design</strong></p>
+ <p>For design guidelines, read Android Design's <a
+ href="{@docRoot}design/building-blocks/tabs.html">Tabs</a> guide.</p>
+</div>
+
<p>Using tabs is a very popular solution for lateral navigation. This pattern allows grouping of sibling screens, in that the tab content container in the parent screen can embed child screens that otherwise would be entirely separate contexts. Tabs are most appropriate for small sets (4 or fewer) of section-related screens.</p>
@@ -89,7 +117,7 @@
<p class="img-caption"><strong>Figure 5.</strong> Example phone and tablet tab-based navigation interfaces with relevant screen map excerpt.</p>
-<p>Several best practices apply when using tabs. Tabs should be persistent across immediate related screens. Only the designated content region should change when selecting a tab, and tab indicators should remain available at all times. Additionally, tab switches should not be treated as history. For example, if a user switches from a tab <em>A</em> to another tab <em>B</em>, pressing the BACK button (more on that in the <a href="ancestral-temporal.html">next lesson</a>) should not re-select tab <em>A</em>. Tabs are usually laid out horizontally, although other presentations of tab navigation such as using a drop-down list in the <a href="{@docRoot}guide/topics/ui/actionbar.html">Action Bar</a> are sometimes appropriate. Lastly, and most importantly, <em>tabs should always run along the top of the screen</em>, and should not be aligned to the bottom of the screen.</p>
+<p>Several best practices apply when using tabs. Tabs should be persistent across immediate related screens. Only the designated content region should change when selecting a tab, and tab indicators should remain available at all times. Additionally, tab switches should not be treated as history. For example, if a user switches from a tab <em>A</em> to another tab <em>B</em>, pressing the BACK button (more on that in the <a href="ancestral-temporal.html">next lesson</a>) should not re-select tab <em>A</em>. Tabs are usually laid out horizontally, although other presentations of tab navigation such as using a drop-down list in the Action Bar (<a href="{@docRoot}design/patterns/actionbar.html">pattern docs</a> at Android Design) are sometimes appropriate. Lastly, and most importantly, <em>tabs should always run along the top of the screen</em>, and should not be aligned to the bottom of the screen.</p>
<p>There are some obvious immediate benefits of tabs over simpler list- and button-based navigation:</p>
@@ -101,9 +129,15 @@
<p>A common criticism is that space must be reserved for the tab indicators, detracting from the space available to tab contents. This consequence is usually acceptable, and the tradeoff commonly weighs in favor of using this pattern. You should also feel free to customize tab indicators, showing text and/or icons to make optimal use of vertical space. When adjusting indicator heights however, ensure that tab indicators are large enough for a human finger to touch without error.</p>
-<h2 id="paging">Horizontal Paging</h2>
+<h2 id="paging">Horizontal Paging (Swipe Views)</h2>
-<p>Another popular lateral navigation pattern is horizontal paging. This pattern applies best to collection-related sibling screens, such as a list of categories (world, business, technology, and health stories). Like tabs, this pattern also allows grouping screens in that the parent presents the contents of child screens embedded within its own layout.</p>
+<div class="design-announce">
+<p><strong>Swipe Views Design</strong></p>
+ <p>For design guidelines, read Android Design's <a
+ href="{@docRoot}design/patterns/swipe-views.html">Swipe Views</a> pattern guides.</p>
+</div>
+
+<p>Another popular lateral navigation pattern is horizontal paging, also referred to as swipe views. This pattern applies best to collection-related sibling screens, such as a list of categories (world, business, technology, and health stories). Like tabs, this pattern also allows grouping screens in that the parent presents the contents of child screens embedded within its own layout.</p>
<img src="{@docRoot}images/training/app-navigation-descendant-lateral-paging.png"
diff --git a/docs/html/training/design-navigation/index.jd b/docs/html/training/design-navigation/index.jd
index e02d52e..cb20a60 100644
--- a/docs/html/training/design-navigation/index.jd
+++ b/docs/html/training/design-navigation/index.jd
@@ -14,7 +14,7 @@
<p>This class is not specific to any particular version of the Android platform. It is also primarily design-focused and does not require knowledge of the Android SDK. That said, you should have experience using an Android device for a better understanding of the context in which Android applications run.</p>
-<p>You should also have basic familiarity with the <a href="{@docRoot}guide/topics/ui/actionbar.html">Action Bar</a>, used across most applications in devices running Android 3.0 and later.</p>
+<p>You should also have basic familiarity with the Action Bar (<a href="{@docRoot}design/patterns/actionbar.html">pattern docs</a> at Android Design), used across most applications in devices running Android 3.0 and later.</p>
</div>
diff --git a/docs/html/training/design-navigation/multiple-sizes.jd b/docs/html/training/design-navigation/multiple-sizes.jd
index 7a8139f..ebaec0f 100644
--- a/docs/html/training/design-navigation/multiple-sizes.jd
+++ b/docs/html/training/design-navigation/multiple-sizes.jd
@@ -22,6 +22,7 @@
<h2>You should also read</h2>
<ul>
+ <li><a href="{@docRoot}design/patterns/multi-pane-layouts.html">Android Design: Multi-pane Layouts</a></li>
<li><a href="{@docRoot}training/multiscreen/index.html">Designing for Multiple Screens</a></li>
</ul>
@@ -35,6 +36,12 @@
<h2 id="multi-pane-layouts">Group Screens with Multi-pane Layouts</h2>
+<div class="design-announce">
+<p><strong>Multi-pane Layout Design</strong></p>
+ <p>For design guidelines, read Android Design's <a
+ href="{@docRoot}design/patterns/multi-pane-layouts.html">Multi-pane Layouts</a> pattern guide.</p>
+</div>
+
<p>3 to 4-inch screens are generally only suitable for showing a single vertical pane of content at a time, be it a list of items, or detail information about an item, etc. Thus on such devices, screens generally map one-to-one with levels in the information hierarchy (<em>categories</em> → <em>object list</em> → <em>object detail</em>).</p>
<p>Larger screens such as those found on tablets and TVs, on the other hand, generally have much more available screen space and are able to present multiple panes of content. In landscape, panes are usually ordered from left to right in increasing detail order. Users are especially accustomed to multiple panes on larger screens from years and years of desktop application and desktop web site use. Many desktop applications and websites offer a left-hand navigation pane or use a master/detail two-pane layout.</p>
@@ -76,12 +83,12 @@
<li><strong>Expand/collapse</strong>
<img src="{@docRoot}images/training/app-navigation-multiple-sizes-strategy-collapse.png"
alt="Expand/collapse strategy">
- <p>A variation on the stretch strategy is to collapse the contents of the left pane when in portrait. This works quite well with master/detail panes where the left (master) pane contains easily collapsible list items. An example would be for a realtime chat application. In landscape, the left list could contain chat contact photos, names, and online statuses. In portrait, horizontal space could be collapsed by hiding contact names and only showing photos and online status indicator icons.</p></li>
+ <p>A variation on the stretch strategy is to collapse the contents of the left pane when in portrait. This works quite well with master/detail panes where the left (master) pane contains easily collapsible list items. An example would be for a realtime chat application. In landscape, the left list could contain chat contact photos, names, and online statuses. In portrait, horizontal space could be collapsed by hiding contact names and only showing photos and online status indicator icons. Optionally also provide an expand control that allows the user to expand the left pane content to its larger width and vice versa.</p></li>
<li><strong>Show/Hide</strong>
<img src="{@docRoot}images/training/app-navigation-multiple-sizes-strategy-show-hide.png"
alt="Show/Hide strategy">
- <p>In this scenario, the left pane is completely hidden in portrait mode. However, <em>to ensure the functional parity</em> of your screen in portrait and landscape, the left pane should be made available via an onscreen affordance (such as a button). It's usually appropriate to use the <em>Up</em> button in the <a href="{@docRoot}guide/topics/ui/actionbar.html">Action Bar</a> to show the left pane, as is discussed in a <a href="ancestral-temporal.html">later lesson</a>.</p></li>
+ <p>In this scenario, the left pane is completely hidden in portrait mode. However, <em>to ensure the functional parity</em> of your screen in portrait and landscape, the left pane should be made available via an onscreen affordance (such as a button). It's usually appropriate to use the <em>Up</em> button in the Action Bar (<a href="{@docRoot}design/patterns/actionbar.html">pattern docs</a> at Android Design) to show the left pane, as is discussed in a <a href="ancestral-temporal.html">later lesson</a>.</p></li>
<li><strong>Stack</strong>
<img src="{@docRoot}images/training/app-navigation-multiple-sizes-strategy-stack.png"
diff --git a/docs/html/training/design-navigation/wireframing.jd b/docs/html/training/design-navigation/wireframing.jd
index c7687dd..6deceb1 100644
--- a/docs/html/training/design-navigation/wireframing.jd
+++ b/docs/html/training/design-navigation/wireframing.jd
@@ -121,5 +121,5 @@
<li><a href="{@docRoot}guide/topics/ui/index.html">Developer's Guide: User Interface</a>: learn how to implement your user interface designs using the Android SDK.</li>
<li><a href="{@docRoot}guide/topics/ui/actionbar.html">Action Bar</a>: implement tabs, up navigation, on-screen actions, etc.
<li><a href="{@docRoot}guide/topics/fundamentals/fragments.html">Fragments</a>: implement re-usable, multi-pane layouts
- <li><a href="{@docRoot}sdk/compatibility-library.html">Support Library</a>: implement horizontal paging using <code>ViewPager</code></li>
+ <li><a href="{@docRoot}sdk/compatibility-library.html">Support Library</a>: implement horizontal paging (swipe views) using <code>ViewPager</code></li>
</ul>
diff --git a/graphics/java/android/graphics/AvoidXfermode.java b/graphics/java/android/graphics/AvoidXfermode.java
index 7e2722d..5a59e36 100644
--- a/graphics/java/android/graphics/AvoidXfermode.java
+++ b/graphics/java/android/graphics/AvoidXfermode.java
@@ -20,6 +20,7 @@
* AvoidXfermode xfermode will draw the src everywhere except on top of the
* opColor or, depending on the Mode, draw only on top of the opColor.
*/
+@Deprecated
public class AvoidXfermode extends Xfermode {
// these need to match the enum in SkAvoidXfermode.h on the native side
diff --git a/graphics/java/android/graphics/LinearGradient.java b/graphics/java/android/graphics/LinearGradient.java
index 82ed199..96a71e3 100644
--- a/graphics/java/android/graphics/LinearGradient.java
+++ b/graphics/java/android/graphics/LinearGradient.java
@@ -28,8 +28,8 @@
the the colors are distributed evenly along the gradient line.
@param tile The Shader tiling mode
*/
- public LinearGradient(float x0, float y0, float x1, float y1,
- int colors[], float positions[], TileMode tile) {
+ public LinearGradient(float x0, float y0, float x1, float y1, int colors[], float positions[],
+ TileMode tile) {
if (colors.length < 2) {
throw new IllegalArgumentException("needs >= 2 number of colors");
}
@@ -50,8 +50,8 @@
@param color1 The color at the end of the gradient line.
@param tile The Shader tiling mode
*/
- public LinearGradient(float x0, float y0, float x1, float y1,
- int color0, int color1, TileMode tile) {
+ public LinearGradient(float x0, float y0, float x1, float y1, int color0, int color1,
+ TileMode tile) {
native_instance = nativeCreate2(x0, y0, x1, y1, color0, color1, tile.nativeInt);
native_shader = nativePostCreate2(native_instance, x0, y0, x1, y1, color0, color1,
tile.nativeInt);
diff --git a/graphics/java/android/graphics/PaintFlagsDrawFilter.java b/graphics/java/android/graphics/PaintFlagsDrawFilter.java
index 0f0d03d..c833a12 100644
--- a/graphics/java/android/graphics/PaintFlagsDrawFilter.java
+++ b/graphics/java/android/graphics/PaintFlagsDrawFilter.java
@@ -17,6 +17,10 @@
package android.graphics;
public class PaintFlagsDrawFilter extends DrawFilter {
+ /** @hide **/
+ public final int clearBits;
+ /** @hide **/
+ public final int setBits;
/**
* Subclass of DrawFilter that affects every paint by first clearing
@@ -27,6 +31,8 @@
* @param setBits These bits will be set in the paint's flags
*/
public PaintFlagsDrawFilter(int clearBits, int setBits) {
+ this.clearBits = clearBits;
+ this.setBits = setBits;
// our native constructor can return 0, if the specified bits
// are effectively a no-op
mNativeInt = nativeConstructor(clearBits, setBits);
diff --git a/graphics/java/android/graphics/PixelXorXfermode.java b/graphics/java/android/graphics/PixelXorXfermode.java
index 18d15cf..6075ec3 100644
--- a/graphics/java/android/graphics/PixelXorXfermode.java
+++ b/graphics/java/android/graphics/PixelXorXfermode.java
@@ -22,6 +22,7 @@
* this mode *always* returns an opaque color (alpha == 255). Thus it is
* not really usefull for operating on blended colors.
*/
+@Deprecated
public class PixelXorXfermode extends Xfermode {
public PixelXorXfermode(int opColor) {
diff --git a/graphics/java/android/graphics/Rect.java b/graphics/java/android/graphics/Rect.java
index 7830224..0ada1fb 100644
--- a/graphics/java/android/graphics/Rect.java
+++ b/graphics/java/android/graphics/Rect.java
@@ -76,13 +76,21 @@
}
@Override
- public boolean equals(Object obj) {
- Rect r = (Rect) obj;
- if (r != null) {
- return left == r.left && top == r.top && right == r.right
- && bottom == r.bottom;
- }
- return false;
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+
+ Rect r = (Rect) o;
+ return left == r.left && top == r.top && right == r.right && bottom == r.bottom;
+ }
+
+ @Override
+ public int hashCode() {
+ int result = left;
+ result = 31 * result + top;
+ result = 31 * result + right;
+ result = 31 * result + bottom;
+ return result;
}
@Override
diff --git a/graphics/java/android/graphics/RectF.java b/graphics/java/android/graphics/RectF.java
index 00e9609..293dfcc 100644
--- a/graphics/java/android/graphics/RectF.java
+++ b/graphics/java/android/graphics/RectF.java
@@ -79,6 +79,24 @@
bottom = r.bottom;
}
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+
+ Rect r = (Rect) o;
+ return left == r.left && top == r.top && right == r.right && bottom == r.bottom;
+ }
+
+ @Override
+ public int hashCode() {
+ int result = (left != +0.0f ? Float.floatToIntBits(left) : 0);
+ result = 31 * result + (top != +0.0f ? Float.floatToIntBits(top) : 0);
+ result = 31 * result + (right != +0.0f ? Float.floatToIntBits(right) : 0);
+ result = 31 * result + (bottom != +0.0f ? Float.floatToIntBits(bottom) : 0);
+ return result;
+ }
+
public String toString() {
return "RectF(" + left + ", " + top + ", "
+ right + ", " + bottom + ")";
diff --git a/graphics/java/android/graphics/drawable/GradientDrawable.java b/graphics/java/android/graphics/drawable/GradientDrawable.java
index 50964d5..5b50beb 100644
--- a/graphics/java/android/graphics/drawable/GradientDrawable.java
+++ b/graphics/java/android/graphics/drawable/GradientDrawable.java
@@ -173,9 +173,20 @@
}
/**
- * Specify radii for each of the 4 corners. For each corner, the array
- * contains 2 values, [X_radius, Y_radius]. The corners are ordered
- * top-left, top-right, bottom-right, bottom-left
+ * <p>Specify radii for each of the 4 corners. For each corner, the array
+ * contains 2 values, <code>[X_radius, Y_radius]</code>. The corners are ordered
+ * top-left, top-right, bottom-right, bottom-left. This property
+ * is honored only when the shape is of type {@link #RECTANGLE}.</p>
+ * <p><strong>Note</strong>: changing this property will affect all instances
+ * of a drawable loaded from a resource. It is recommended to invoke
+ * {@link #mutate()} before changing this property.</p>
+ *
+ * @param radii 4 pairs of X and Y radius for each corner, specified in pixels.
+ * The length of this array must be >= 8
+ *
+ * @see #mutate()
+ * @see #setCornerRadii(float[])
+ * @see #setShape(int)
*/
public void setCornerRadii(float[] radii) {
mGradientState.setCornerRadii(radii);
@@ -184,23 +195,57 @@
}
/**
- * Specify radius for the corners of the gradient. If this is > 0, then the
- * drawable is drawn in a round-rectangle, rather than a rectangle.
+ * <p>Specify radius for the corners of the gradient. If this is > 0, then the
+ * drawable is drawn in a round-rectangle, rather than a rectangle. This property
+ * is honored only when the shape is of type {@link #RECTANGLE}.</p>
+ * <p><strong>Note</strong>: changing this property will affect all instances
+ * of a drawable loaded from a resource. It is recommended to invoke
+ * {@link #mutate()} before changing this property.</p>
+ *
+ * @param radius The radius in pixels of the corners of the rectangle shape
+ *
+ * @see #mutate()
+ * @see #setCornerRadii(float[])
+ * @see #setShape(int)
*/
public void setCornerRadius(float radius) {
mGradientState.setCornerRadius(radius);
mPathIsDirty = true;
invalidateSelf();
}
-
+
/**
- * Set the stroke width and color for the drawable. If width is zero,
- * then no stroke is drawn.
+ * <p>Set the stroke width and color for the drawable. If width is zero,
+ * then no stroke is drawn.</p>
+ * <p><strong>Note</strong>: changing this property will affect all instances
+ * of a drawable loaded from a resource. It is recommended to invoke
+ * {@link #mutate()} before changing this property.</p>
+ *
+ * @param width The width in pixels of the stroke
+ * @param color The color of the stroke
+ *
+ * @see #mutate()
+ * @see #setStroke(int, int, float, float)
*/
public void setStroke(int width, int color) {
setStroke(width, color, 0, 0);
}
-
+
+ /**
+ * <p>Set the stroke width and color for the drawable. If width is zero,
+ * then no stroke is drawn. This method can also be used to dash the stroke.</p>
+ * <p><strong>Note</strong>: changing this property will affect all instances
+ * of a drawable loaded from a resource. It is recommended to invoke
+ * {@link #mutate()} before changing this property.</p>
+ *
+ * @param width The width in pixels of the stroke
+ * @param color The color of the stroke
+ * @param dashWidth The length in pixels of the dashes, set to 0 to disable dashes
+ * @param dashGap The gap in pixels between dashes
+ *
+ * @see #mutate()
+ * @see #setStroke(int, int)
+ */
public void setStroke(int width, int color, float dashWidth, float dashGap) {
mGradientState.setStroke(width, color, dashWidth, dashGap);
@@ -218,13 +263,37 @@
mStrokePaint.setPathEffect(e);
invalidateSelf();
}
-
+
+
+ /**
+ * <p>Sets the size of the shape drawn by this drawable.</p>
+ * <p><strong>Note</strong>: changing this property will affect all instances
+ * of a drawable loaded from a resource. It is recommended to invoke
+ * {@link #mutate()} before changing this property.</p>
+ *
+ * @param width The width of the shape used by this drawable
+ * @param height The height of the shape used by this drawable
+ *
+ * @see #mutate()
+ * @see #setGradientType(int)
+ */
public void setSize(int width, int height) {
mGradientState.setSize(width, height);
mPathIsDirty = true;
invalidateSelf();
}
-
+
+ /**
+ * <p>Sets the type of shape used to draw the gradient.</p>
+ * <p><strong>Note</strong>: changing this property will affect all instances
+ * of a drawable loaded from a resource. It is recommended to invoke
+ * {@link #mutate()} before changing this property.</p>
+ *
+ * @param shape The desired shape for this drawable: {@link #LINE},
+ * {@link #OVAL}, {@link #RECTANGLE} or {@link #RING}
+ *
+ * @see #mutate()
+ */
public void setShape(int shape) {
mRingPath = null;
mPathIsDirty = true;
@@ -232,24 +301,73 @@
invalidateSelf();
}
+ /**
+ * <p>Sets the type of gradient used by this drawable..</p>
+ * <p><strong>Note</strong>: changing this property will affect all instances
+ * of a drawable loaded from a resource. It is recommended to invoke
+ * {@link #mutate()} before changing this property.</p>
+ *
+ * @param gradient The type of the gradient: {@link #LINEAR_GRADIENT},
+ * {@link #RADIAL_GRADIENT} or {@link #SWEEP_GRADIENT}
+ *
+ * @see #mutate()
+ */
public void setGradientType(int gradient) {
mGradientState.setGradientType(gradient);
mRectIsDirty = true;
invalidateSelf();
}
+ /**
+ * <p>Sets the center location of the gradient. The radius is honored only when
+ * the gradient type is set to {@link #RADIAL_GRADIENT} or {@link #SWEEP_GRADIENT}.</p>
+ * <p><strong>Note</strong>: changing this property will affect all instances
+ * of a drawable loaded from a resource. It is recommended to invoke
+ * {@link #mutate()} before changing this property.</p>
+ *
+ * @param x The x coordinate of the gradient's center
+ * @param y The y coordinate of the gradient's center
+ *
+ * @see #mutate()
+ * @see #setGradientType(int)
+ */
public void setGradientCenter(float x, float y) {
mGradientState.setGradientCenter(x, y);
mRectIsDirty = true;
invalidateSelf();
}
+ /**
+ * <p>Sets the radius of the gradient. The radius is honored only when the
+ * gradient type is set to {@link #RADIAL_GRADIENT}.</p>
+ * <p><strong>Note</strong>: changing this property will affect all instances
+ * of a drawable loaded from a resource. It is recommended to invoke
+ * {@link #mutate()} before changing this property.</p>
+ *
+ * @param gradientRadius The radius of the gradient in pixels
+ *
+ * @see #mutate()
+ * @see #setGradientType(int)
+ */
public void setGradientRadius(float gradientRadius) {
mGradientState.setGradientRadius(gradientRadius);
mRectIsDirty = true;
invalidateSelf();
}
+ /**
+ * <p>Sets whether or not this drawable will honor its <code>level</code>
+ * property.</p>
+ * <p><strong>Note</strong>: changing this property will affect all instances
+ * of a drawable loaded from a resource. It is recommended to invoke
+ * {@link #mutate()} before changing this property.</p>
+ *
+ * @param useLevel True if this drawable should honor its level, false otherwise
+ *
+ * @see #mutate()
+ * @see #setLevel(int)
+ * @see #getLevel()
+ */
public void setUseLevel(boolean useLevel) {
mGradientState.mUseLevel = useLevel;
mRectIsDirty = true;
@@ -261,6 +379,47 @@
return alpha * scale >> 8;
}
+ /**
+ * Returns the orientation of the gradient defined in this drawable.
+ */
+ public Orientation getOrientation() {
+ return mGradientState.mOrientation;
+ }
+
+ /**
+ * <p>Changes the orientation of the gradient defined in this drawable.</p>
+ * <p><strong>Note</strong>: changing orientation will affect all instances
+ * of a drawable loaded from a resource. It is recommended to invoke
+ * {@link #mutate()} before changing the orientation.</p>
+ *
+ * @param orientation The desired orientation (angle) of the gradient
+ *
+ * @see #mutate()
+ */
+ public void setOrientation(Orientation orientation) {
+ mGradientState.mOrientation = orientation;
+ mRectIsDirty = true;
+ invalidateSelf();
+ }
+
+ /**
+ * <p>Sets the colors used to draw the gradient. Each color is specified as an
+ * ARGB integer and the array must contain at least 2 colors.</p>
+ * <p><strong>Note</strong>: changing orientation will affect all instances
+ * of a drawable loaded from a resource. It is recommended to invoke
+ * {@link #mutate()} before changing the orientation.</p>
+ *
+ * @param colors 2 or more ARGB colors
+ *
+ * @see #mutate()
+ * @see #setColor(int)
+ */
+ public void setColors(int[] colors) {
+ mGradientState.setColors(colors);
+ mRectIsDirty = true;
+ invalidateSelf();
+ }
+
@Override
public void draw(Canvas canvas) {
if (!ensureValidRect()) {
@@ -442,6 +601,17 @@
return ringPath;
}
+ /**
+ * <p>Changes this drawbale to use a single color instead of a gradient.</p>
+ * <p><strong>Note</strong>: changing orientation will affect all instances
+ * of a drawable loaded from a resource. It is recommended to invoke
+ * {@link #mutate()} before changing the orientation.</p>
+ *
+ * @param argb The color used to fill the shape
+ *
+ * @see #mutate()
+ * @see #setColors(int[])
+ */
public void setColor(int argb) {
mGradientState.setSolidColor(argb);
mFillPaint.setColor(argb);
@@ -450,10 +620,9 @@
@Override
public int getChangingConfigurations() {
- return super.getChangingConfigurations()
- | mGradientState.mChangingConfigurations;
+ return super.getChangingConfigurations() | mGradientState.mChangingConfigurations;
}
-
+
@Override
public void setAlpha(int alpha) {
if (alpha != mAlpha) {
@@ -480,7 +649,6 @@
@Override
public int getOpacity() {
- // XXX need to figure out the actual opacity...
return PixelFormat.TRANSLUCENT;
}
@@ -911,11 +1079,6 @@
private float mGradientRadius = 0.5f;
private boolean mUseLevel;
private boolean mUseLevelForShape;
-
-
- GradientState() {
- mOrientation = Orientation.TOP_BOTTOM;
- }
GradientState(Orientation orientation, int[] colors) {
mOrientation = orientation;
@@ -987,6 +1150,11 @@
mCenterY = y;
}
+ public void setColors(int[] colors) {
+ mHasSolidColor = false;
+ mColors = colors;
+ }
+
public void setSolidColor(int argb) {
mHasSolidColor = true;
mSolidColor = argb;
@@ -1055,4 +1223,3 @@
}
}
}
-
diff --git a/graphics/java/android/renderscript/Allocation.java b/graphics/java/android/renderscript/Allocation.java
index f285f5b..11c2427 100644
--- a/graphics/java/android/renderscript/Allocation.java
+++ b/graphics/java/android/renderscript/Allocation.java
@@ -487,6 +487,7 @@
final byte[] data = fp.getData();
int eSize = mType.mElement.mElements[component_number].getSizeBytes();
+ eSize *= mType.mElement.mArraySizes[component_number];
if (data.length != eSize) {
throw new RSIllegalArgumentException("Field packer sizelength " + data.length +
diff --git a/graphics/java/android/renderscript/RenderScript.java b/graphics/java/android/renderscript/RenderScript.java
index ad10832..03ad5ae 100644
--- a/graphics/java/android/renderscript/RenderScript.java
+++ b/graphics/java/android/renderscript/RenderScript.java
@@ -837,7 +837,7 @@
mRS.mErrorCallback.mErrorNum = subID;
mRS.mErrorCallback.run();
} else {
- //throw new RSRuntimeException("Received error num " + subID + ", details: " + e);
+ throw new RSRuntimeException("Received error num " + subID + ", details: " + e);
}
continue;
}
diff --git a/graphics/jni/android_renderscript_RenderScript.cpp b/graphics/jni/android_renderscript_RenderScript.cpp
index bc1db4d..07bf7bf 100644
--- a/graphics/jni/android_renderscript_RenderScript.cpp
+++ b/graphics/jni/android_renderscript_RenderScript.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2011 The Android Open Source Project
+ * Copyright (C) 2011-2012 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -567,7 +567,7 @@
jint len = _env->GetArrayLength(data);
LOG_API("nAllocationElementData1D, con(%p), alloc(%p), offset(%i), comp(%i), len(%i), sizeBytes(%i)", con, (RsAllocation)alloc, offset, compIdx, len, sizeBytes);
jbyte *ptr = _env->GetByteArrayElements(data, NULL);
- rsAllocation1DElementData(con, (RsAllocation)alloc, offset, lod, ptr, compIdx, sizeBytes);
+ rsAllocation1DElementData(con, (RsAllocation)alloc, offset, lod, ptr, sizeBytes, compIdx);
_env->ReleaseByteArrayElements(data, ptr, JNI_ABORT);
}
diff --git a/include/gui/DisplayEventReceiver.h b/include/gui/DisplayEventReceiver.h
index dccc164..7bca8d6 100644
--- a/include/gui/DisplayEventReceiver.h
+++ b/include/gui/DisplayEventReceiver.h
@@ -63,7 +63,9 @@
public:
/*
* DisplayEventReceiver creates and registers an event connection with
- * SurfaceFlinger. Events start being delivered immediately.
+ * SurfaceFlinger. VSync events are disabled by default. Call setVSyncRate
+ * or requestNextVsync to receive them.
+ * Other events start being delivered immediately.
*/
DisplayEventReceiver();
@@ -93,6 +95,8 @@
* should be destroyed and getEvents() shouldn't be called again.
*/
ssize_t getEvents(Event* events, size_t count);
+ static ssize_t getEvents(const sp<BitTube>& dataChannel,
+ Event* events, size_t count);
/*
* setVsyncRate() sets the Event::VSync delivery rate. A value of
diff --git a/include/media/AudioRecord.h b/include/media/AudioRecord.h
index 756e91d..76ec3b1 100644
--- a/include/media/AudioRecord.h
+++ b/include/media/AudioRecord.h
@@ -149,7 +149,7 @@
RECORD_IIR_ENABLE = AUDIO_IN_ACOUSTICS_TX_IIR_ENABLE,
};
- AudioRecord(int inputSource,
+ AudioRecord(audio_source_t inputSource,
uint32_t sampleRate = 0,
audio_format_t format = AUDIO_FORMAT_DEFAULT,
uint32_t channelMask = AUDIO_CHANNEL_IN_MONO,
@@ -175,7 +175,7 @@
* - NO_INIT: audio server or audio hardware not initialized
* - PERMISSION_DENIED: recording is not allowed for the requesting process
* */
- status_t set(int inputSource = 0,
+ status_t set(audio_source_t inputSource = AUDIO_SOURCE_DEFAULT,
uint32_t sampleRate = 0,
audio_format_t format = AUDIO_FORMAT_DEFAULT,
uint32_t channelMask = AUDIO_CHANNEL_IN_MONO,
@@ -208,7 +208,7 @@
int channels() const;
uint32_t frameCount() const;
size_t frameSize() const;
- int inputSource() const;
+ audio_source_t inputSource() const;
/* After it's created the track is not active. Call start() to
@@ -367,8 +367,7 @@
audio_track_cblk_t* mCblk;
audio_format_t mFormat;
uint8_t mChannelCount;
- uint8_t mInputSource;
- uint8_t mReserved[2];
+ audio_source_t mInputSource;
status_t mStatus;
uint32_t mLatency;
diff --git a/include/media/AudioSystem.h b/include/media/AudioSystem.h
index c6368fb..74a1e62 100644
--- a/include/media/AudioSystem.h
+++ b/include/media/AudioSystem.h
@@ -163,7 +163,7 @@
audio_stream_type_t stream,
int session = 0);
static void releaseOutput(audio_io_handle_t output);
- static audio_io_handle_t getInput(int inputSource,
+ static audio_io_handle_t getInput(audio_source_t inputSource,
uint32_t samplingRate = 0,
audio_format_t format = AUDIO_FORMAT_DEFAULT,
uint32_t channels = AUDIO_CHANNEL_IN_MONO,
@@ -248,7 +248,7 @@
static sp<IAudioPolicyService> gAudioPolicyService;
// mapping between stream types and outputs
- static DefaultKeyedVector<int, audio_io_handle_t> gStreamOutputMap;
+ static DefaultKeyedVector<audio_stream_type_t, audio_io_handle_t> gStreamOutputMap;
// list of output descriptors containing cached parameters
// (sampling rate, framecount, channel count...)
static DefaultKeyedVector<audio_io_handle_t, OutputDescriptor *> gOutputs;
diff --git a/include/media/AudioTrack.h b/include/media/AudioTrack.h
index fe91799..98abfbd 100644
--- a/include/media/AudioTrack.h
+++ b/include/media/AudioTrack.h
@@ -411,7 +411,7 @@
*/
enum {
- NO_MORE_BUFFERS = 0x80000001,
+ NO_MORE_BUFFERS = 0x80000001, // same name in AudioFlinger.h, ok to be different value
STOPPED = 1
};
diff --git a/include/media/IAudioPolicyService.h b/include/media/IAudioPolicyService.h
index 07d17c5..4d88297 100644
--- a/include/media/IAudioPolicyService.h
+++ b/include/media/IAudioPolicyService.h
@@ -60,7 +60,7 @@
audio_stream_type_t stream,
int session = 0) = 0;
virtual void releaseOutput(audio_io_handle_t output) = 0;
- virtual audio_io_handle_t getInput(int inputSource,
+ virtual audio_io_handle_t getInput(audio_source_t inputSource,
uint32_t samplingRate = 0,
audio_format_t format = AUDIO_FORMAT_DEFAULT,
uint32_t channels = 0,
diff --git a/include/media/IOMX.h b/include/media/IOMX.h
index c4cc947..a295e9a 100644
--- a/include/media/IOMX.h
+++ b/include/media/IOMX.h
@@ -42,10 +42,10 @@
typedef void *buffer_id;
typedef void *node_id;
- // Given the calling process' pid, returns true iff
+ // Given a node_id and the calling process' pid, returns true iff
// the implementation of the OMX interface lives in the same
// process.
- virtual bool livesLocally(pid_t pid) = 0;
+ virtual bool livesLocally(node_id node, pid_t pid) = 0;
struct ComponentInfo {
String8 mName;
diff --git a/include/media/stagefright/AudioSource.h b/include/media/stagefright/AudioSource.h
index 19bd31b..2427e2f 100644
--- a/include/media/stagefright/AudioSource.h
+++ b/include/media/stagefright/AudioSource.h
@@ -34,7 +34,7 @@
// Note that the "channels" parameter is _not_ the number of channels,
// but a bitmask of audio_channels_t constants.
AudioSource(
- int inputSource, uint32_t sampleRate,
+ audio_source_t inputSource, uint32_t sampleRate,
uint32_t channels = AUDIO_CHANNEL_IN_MONO);
status_t initCheck() const;
diff --git a/include/media/stagefright/OMXCodec.h b/include/media/stagefright/OMXCodec.h
index 84f8282..4c30e04 100644
--- a/include/media/stagefright/OMXCodec.h
+++ b/include/media/stagefright/OMXCodec.h
@@ -172,6 +172,7 @@
uint32_t mFlags;
bool mIsEncoder;
+ bool mIsVideo;
char *mMIME;
char *mComponentName;
sp<MetaData> mOutputFormat;
diff --git a/include/utils/ResourceTypes.h b/include/utils/ResourceTypes.h
index 46420c1..c496da6 100644
--- a/include/utils/ResourceTypes.h
+++ b/include/utils/ResourceTypes.h
@@ -444,23 +444,31 @@
void uninit();
+ // Return string entry as UTF16; if the pool is UTF8, the string will
+ // be converted before returning.
inline const char16_t* stringAt(const ResStringPool_ref& ref, size_t* outLen) const {
return stringAt(ref.index, outLen);
}
const char16_t* stringAt(size_t idx, size_t* outLen) const;
+ // Note: returns null if the string pool is not UTF8.
const char* string8At(size_t idx, size_t* outLen) const;
+ // Return string whether the pool is UTF8 or UTF16. Does not allow you
+ // to distinguish null.
+ const String8 string8ObjectAt(size_t idx) const;
+
const ResStringPool_span* styleAt(const ResStringPool_ref& ref) const;
const ResStringPool_span* styleAt(size_t idx) const;
ssize_t indexOfString(const char16_t* str, size_t strLen) const;
size_t size() const;
+ size_t styleCount() const;
+ size_t bytes() const;
-#ifndef HAVE_ANDROID_OS
+ bool isSorted() const;
bool isUTF8() const;
-#endif
private:
status_t mError;
@@ -746,7 +754,9 @@
/**
* Header for a resource table. Its data contains a series of
* additional chunks:
- * * A ResStringPool_header containing all table values.
+ * * A ResStringPool_header containing all table values. This string pool
+ * contains all of the string values in the entire resource table (not
+ * the names of entries or type identifiers however).
* * One or more ResTable_package chunks.
*
* Specific entries within a resource table can be uniquely identified
@@ -843,6 +853,8 @@
DENSITY_MEDIUM = ACONFIGURATION_DENSITY_MEDIUM,
DENSITY_TV = ACONFIGURATION_DENSITY_TV,
DENSITY_HIGH = ACONFIGURATION_DENSITY_HIGH,
+ DENSITY_XHIGH = ACONFIGURATION_DENSITY_XHIGH,
+ DENSITY_XXHIGH = ACONFIGURATION_DENSITY_XXHIGH,
DENSITY_NONE = ACONFIGURATION_DENSITY_NONE
};
@@ -982,68 +994,15 @@
uint32_t screenSizeDp;
};
- inline void copyFromDeviceNoSwap(const ResTable_config& o) {
- const size_t size = dtohl(o.size);
- if (size >= sizeof(ResTable_config)) {
- *this = o;
- } else {
- memcpy(this, &o, size);
- memset(((uint8_t*)this)+size, 0, sizeof(ResTable_config)-size);
- }
- }
+ void copyFromDeviceNoSwap(const ResTable_config& o);
- inline void copyFromDtoH(const ResTable_config& o) {
- copyFromDeviceNoSwap(o);
- size = sizeof(ResTable_config);
- mcc = dtohs(mcc);
- mnc = dtohs(mnc);
- density = dtohs(density);
- screenWidth = dtohs(screenWidth);
- screenHeight = dtohs(screenHeight);
- sdkVersion = dtohs(sdkVersion);
- minorVersion = dtohs(minorVersion);
- smallestScreenWidthDp = dtohs(smallestScreenWidthDp);
- screenWidthDp = dtohs(screenWidthDp);
- screenHeightDp = dtohs(screenHeightDp);
- }
+ void copyFromDtoH(const ResTable_config& o);
- inline void swapHtoD() {
- size = htodl(size);
- mcc = htods(mcc);
- mnc = htods(mnc);
- density = htods(density);
- screenWidth = htods(screenWidth);
- screenHeight = htods(screenHeight);
- sdkVersion = htods(sdkVersion);
- minorVersion = htods(minorVersion);
- smallestScreenWidthDp = htods(smallestScreenWidthDp);
- screenWidthDp = htods(screenWidthDp);
- screenHeightDp = htods(screenHeightDp);
- }
-
- inline int compare(const ResTable_config& o) const {
- int32_t diff = (int32_t)(imsi - o.imsi);
- if (diff != 0) return diff;
- diff = (int32_t)(locale - o.locale);
- if (diff != 0) return diff;
- diff = (int32_t)(screenType - o.screenType);
- if (diff != 0) return diff;
- diff = (int32_t)(input - o.input);
- if (diff != 0) return diff;
- diff = (int32_t)(screenSize - o.screenSize);
- if (diff != 0) return diff;
- diff = (int32_t)(version - o.version);
- if (diff != 0) return diff;
- diff = (int32_t)(screenLayout - o.screenLayout);
- if (diff != 0) return diff;
- diff = (int32_t)(uiMode - o.uiMode);
- if (diff != 0) return diff;
- diff = (int32_t)(smallestScreenWidthDp - o.smallestScreenWidthDp);
- if (diff != 0) return diff;
- diff = (int32_t)(screenSizeDp - o.screenSizeDp);
- return (int)diff;
- }
-
+ void swapHtoD();
+
+ int compare(const ResTable_config& o) const;
+ int compareLogical(const ResTable_config& o) const;
+
// Flags indicating a set of config values. These flag constants must
// match the corresponding ones in android.content.pm.ActivityInfo and
// attrs_manifest.xml.
@@ -1066,158 +1025,10 @@
// Compare two configuration, returning CONFIG_* flags set for each value
// that is different.
- inline int diff(const ResTable_config& o) const {
- int diffs = 0;
- if (mcc != o.mcc) diffs |= CONFIG_MCC;
- if (mnc != o.mnc) diffs |= CONFIG_MNC;
- if (locale != o.locale) diffs |= CONFIG_LOCALE;
- if (orientation != o.orientation) diffs |= CONFIG_ORIENTATION;
- if (density != o.density) diffs |= CONFIG_DENSITY;
- if (touchscreen != o.touchscreen) diffs |= CONFIG_TOUCHSCREEN;
- if (((inputFlags^o.inputFlags)&(MASK_KEYSHIDDEN|MASK_NAVHIDDEN)) != 0)
- diffs |= CONFIG_KEYBOARD_HIDDEN;
- if (keyboard != o.keyboard) diffs |= CONFIG_KEYBOARD;
- if (navigation != o.navigation) diffs |= CONFIG_NAVIGATION;
- if (screenSize != o.screenSize) diffs |= CONFIG_SCREEN_SIZE;
- if (version != o.version) diffs |= CONFIG_VERSION;
- if (screenLayout != o.screenLayout) diffs |= CONFIG_SCREEN_LAYOUT;
- if (uiMode != o.uiMode) diffs |= CONFIG_UI_MODE;
- if (smallestScreenWidthDp != o.smallestScreenWidthDp) diffs |= CONFIG_SMALLEST_SCREEN_SIZE;
- if (screenSizeDp != o.screenSizeDp) diffs |= CONFIG_SCREEN_SIZE;
- return diffs;
- }
+ int diff(const ResTable_config& o) const;
// Return true if 'this' is more specific than 'o'.
- inline bool
- isMoreSpecificThan(const ResTable_config& o) const {
- // The order of the following tests defines the importance of one
- // configuration parameter over another. Those tests first are more
- // important, trumping any values in those following them.
- if (imsi || o.imsi) {
- if (mcc != o.mcc) {
- if (!mcc) return false;
- if (!o.mcc) return true;
- }
-
- if (mnc != o.mnc) {
- if (!mnc) return false;
- if (!o.mnc) return true;
- }
- }
-
- if (locale || o.locale) {
- if (language[0] != o.language[0]) {
- if (!language[0]) return false;
- if (!o.language[0]) return true;
- }
-
- if (country[0] != o.country[0]) {
- if (!country[0]) return false;
- if (!o.country[0]) return true;
- }
- }
-
- if (smallestScreenWidthDp || o.smallestScreenWidthDp) {
- if (smallestScreenWidthDp != o.smallestScreenWidthDp) {
- if (!smallestScreenWidthDp) return false;
- if (!o.smallestScreenWidthDp) return true;
- }
- }
-
- if (screenSizeDp || o.screenSizeDp) {
- if (screenWidthDp != o.screenWidthDp) {
- if (!screenWidthDp) return false;
- if (!o.screenWidthDp) return true;
- }
-
- if (screenHeightDp != o.screenHeightDp) {
- if (!screenHeightDp) return false;
- if (!o.screenHeightDp) return true;
- }
- }
-
- if (screenLayout || o.screenLayout) {
- if (((screenLayout^o.screenLayout) & MASK_SCREENSIZE) != 0) {
- if (!(screenLayout & MASK_SCREENSIZE)) return false;
- if (!(o.screenLayout & MASK_SCREENSIZE)) return true;
- }
- if (((screenLayout^o.screenLayout) & MASK_SCREENLONG) != 0) {
- if (!(screenLayout & MASK_SCREENLONG)) return false;
- if (!(o.screenLayout & MASK_SCREENLONG)) return true;
- }
- }
-
- if (orientation != o.orientation) {
- if (!orientation) return false;
- if (!o.orientation) return true;
- }
-
- if (uiMode || o.uiMode) {
- if (((uiMode^o.uiMode) & MASK_UI_MODE_TYPE) != 0) {
- if (!(uiMode & MASK_UI_MODE_TYPE)) return false;
- if (!(o.uiMode & MASK_UI_MODE_TYPE)) return true;
- }
- if (((uiMode^o.uiMode) & MASK_UI_MODE_NIGHT) != 0) {
- if (!(uiMode & MASK_UI_MODE_NIGHT)) return false;
- if (!(o.uiMode & MASK_UI_MODE_NIGHT)) return true;
- }
- }
-
- // density is never 'more specific'
- // as the default just equals 160
-
- if (touchscreen != o.touchscreen) {
- if (!touchscreen) return false;
- if (!o.touchscreen) return true;
- }
-
- if (input || o.input) {
- if (((inputFlags^o.inputFlags) & MASK_KEYSHIDDEN) != 0) {
- if (!(inputFlags & MASK_KEYSHIDDEN)) return false;
- if (!(o.inputFlags & MASK_KEYSHIDDEN)) return true;
- }
-
- if (((inputFlags^o.inputFlags) & MASK_NAVHIDDEN) != 0) {
- if (!(inputFlags & MASK_NAVHIDDEN)) return false;
- if (!(o.inputFlags & MASK_NAVHIDDEN)) return true;
- }
-
- if (keyboard != o.keyboard) {
- if (!keyboard) return false;
- if (!o.keyboard) return true;
- }
-
- if (navigation != o.navigation) {
- if (!navigation) return false;
- if (!o.navigation) return true;
- }
- }
-
- if (screenSize || o.screenSize) {
- if (screenWidth != o.screenWidth) {
- if (!screenWidth) return false;
- if (!o.screenWidth) return true;
- }
-
- if (screenHeight != o.screenHeight) {
- if (!screenHeight) return false;
- if (!o.screenHeight) return true;
- }
- }
-
- if (version || o.version) {
- if (sdkVersion != o.sdkVersion) {
- if (!sdkVersion) return false;
- if (!o.sdkVersion) return true;
- }
-
- if (minorVersion != o.minorVersion) {
- if (!minorVersion) return false;
- if (!o.minorVersion) return true;
- }
- }
- return false;
- }
+ bool isMoreSpecificThan(const ResTable_config& o) const;
// Return true if 'this' is a better match than 'o' for the 'requested'
// configuration. This assumes that match() has already been used to
@@ -1229,222 +1040,7 @@
// they are not equal then one must be generic because only generic and
// '==requested' will pass the match() call. So if this is not generic,
// it wins. If this IS generic, o wins (return false).
- inline bool
- isBetterThan(const ResTable_config& o,
- const ResTable_config* requested) const {
- if (requested) {
- if (imsi || o.imsi) {
- if ((mcc != o.mcc) && requested->mcc) {
- return (mcc);
- }
-
- if ((mnc != o.mnc) && requested->mnc) {
- return (mnc);
- }
- }
-
- if (locale || o.locale) {
- if ((language[0] != o.language[0]) && requested->language[0]) {
- return (language[0]);
- }
-
- if ((country[0] != o.country[0]) && requested->country[0]) {
- return (country[0]);
- }
- }
-
- if (smallestScreenWidthDp || o.smallestScreenWidthDp) {
- // The configuration closest to the actual size is best.
- // We assume that larger configs have already been filtered
- // out at this point. That means we just want the largest one.
- return smallestScreenWidthDp >= o.smallestScreenWidthDp;
- }
-
- if (screenSizeDp || o.screenSizeDp) {
- // "Better" is based on the sum of the difference between both
- // width and height from the requested dimensions. We are
- // assuming the invalid configs (with smaller dimens) have
- // already been filtered. Note that if a particular dimension
- // is unspecified, we will end up with a large value (the
- // difference between 0 and the requested dimension), which is
- // good since we will prefer a config that has specified a
- // dimension value.
- int myDelta = 0, otherDelta = 0;
- if (requested->screenWidthDp) {
- myDelta += requested->screenWidthDp - screenWidthDp;
- otherDelta += requested->screenWidthDp - o.screenWidthDp;
- }
- if (requested->screenHeightDp) {
- myDelta += requested->screenHeightDp - screenHeightDp;
- otherDelta += requested->screenHeightDp - o.screenHeightDp;
- }
- //ALOGI("Comparing this %dx%d to other %dx%d in %dx%d: myDelta=%d otherDelta=%d",
- // screenWidthDp, screenHeightDp, o.screenWidthDp, o.screenHeightDp,
- // requested->screenWidthDp, requested->screenHeightDp, myDelta, otherDelta);
- return (myDelta <= otherDelta);
- }
-
- if (screenLayout || o.screenLayout) {
- if (((screenLayout^o.screenLayout) & MASK_SCREENSIZE) != 0
- && (requested->screenLayout & MASK_SCREENSIZE)) {
- // A little backwards compatibility here: undefined is
- // considered equivalent to normal. But only if the
- // requested size is at least normal; otherwise, small
- // is better than the default.
- int mySL = (screenLayout & MASK_SCREENSIZE);
- int oSL = (o.screenLayout & MASK_SCREENSIZE);
- int fixedMySL = mySL;
- int fixedOSL = oSL;
- if ((requested->screenLayout & MASK_SCREENSIZE) >= SCREENSIZE_NORMAL) {
- if (fixedMySL == 0) fixedMySL = SCREENSIZE_NORMAL;
- if (fixedOSL == 0) fixedOSL = SCREENSIZE_NORMAL;
- }
- // For screen size, the best match is the one that is
- // closest to the requested screen size, but not over
- // (the not over part is dealt with in match() below).
- if (fixedMySL == fixedOSL) {
- // If the two are the same, but 'this' is actually
- // undefined, then the other is really a better match.
- if (mySL == 0) return false;
- return true;
- }
- return fixedMySL >= fixedOSL;
- }
- if (((screenLayout^o.screenLayout) & MASK_SCREENLONG) != 0
- && (requested->screenLayout & MASK_SCREENLONG)) {
- return (screenLayout & MASK_SCREENLONG);
- }
- }
-
- if ((orientation != o.orientation) && requested->orientation) {
- return (orientation);
- }
-
- if (uiMode || o.uiMode) {
- if (((uiMode^o.uiMode) & MASK_UI_MODE_TYPE) != 0
- && (requested->uiMode & MASK_UI_MODE_TYPE)) {
- return (uiMode & MASK_UI_MODE_TYPE);
- }
- if (((uiMode^o.uiMode) & MASK_UI_MODE_NIGHT) != 0
- && (requested->uiMode & MASK_UI_MODE_NIGHT)) {
- return (uiMode & MASK_UI_MODE_NIGHT);
- }
- }
-
- if (screenType || o.screenType) {
- if (density != o.density) {
- // density is tough. Any density is potentially useful
- // because the system will scale it. Scaling down
- // is generally better than scaling up.
- // Default density counts as 160dpi (the system default)
- // TODO - remove 160 constants
- int h = (density?density:160);
- int l = (o.density?o.density:160);
- bool bImBigger = true;
- if (l > h) {
- int t = h;
- h = l;
- l = t;
- bImBigger = false;
- }
-
- int reqValue = (requested->density?requested->density:160);
- if (reqValue >= h) {
- // requested value higher than both l and h, give h
- return bImBigger;
- }
- if (l >= reqValue) {
- // requested value lower than both l and h, give l
- return !bImBigger;
- }
- // saying that scaling down is 2x better than up
- if (((2 * l) - reqValue) * h > reqValue * reqValue) {
- return !bImBigger;
- } else {
- return bImBigger;
- }
- }
-
- if ((touchscreen != o.touchscreen) && requested->touchscreen) {
- return (touchscreen);
- }
- }
-
- if (input || o.input) {
- const int keysHidden = inputFlags & MASK_KEYSHIDDEN;
- const int oKeysHidden = o.inputFlags & MASK_KEYSHIDDEN;
- if (keysHidden != oKeysHidden) {
- const int reqKeysHidden =
- requested->inputFlags & MASK_KEYSHIDDEN;
- if (reqKeysHidden) {
-
- if (!keysHidden) return false;
- if (!oKeysHidden) return true;
- // For compatibility, we count KEYSHIDDEN_NO as being
- // the same as KEYSHIDDEN_SOFT. Here we disambiguate
- // these by making an exact match more specific.
- if (reqKeysHidden == keysHidden) return true;
- if (reqKeysHidden == oKeysHidden) return false;
- }
- }
-
- const int navHidden = inputFlags & MASK_NAVHIDDEN;
- const int oNavHidden = o.inputFlags & MASK_NAVHIDDEN;
- if (navHidden != oNavHidden) {
- const int reqNavHidden =
- requested->inputFlags & MASK_NAVHIDDEN;
- if (reqNavHidden) {
-
- if (!navHidden) return false;
- if (!oNavHidden) return true;
- }
- }
-
- if ((keyboard != o.keyboard) && requested->keyboard) {
- return (keyboard);
- }
-
- if ((navigation != o.navigation) && requested->navigation) {
- return (navigation);
- }
- }
-
- if (screenSize || o.screenSize) {
- // "Better" is based on the sum of the difference between both
- // width and height from the requested dimensions. We are
- // assuming the invalid configs (with smaller sizes) have
- // already been filtered. Note that if a particular dimension
- // is unspecified, we will end up with a large value (the
- // difference between 0 and the requested dimension), which is
- // good since we will prefer a config that has specified a
- // size value.
- int myDelta = 0, otherDelta = 0;
- if (requested->screenWidth) {
- myDelta += requested->screenWidth - screenWidth;
- otherDelta += requested->screenWidth - o.screenWidth;
- }
- if (requested->screenHeight) {
- myDelta += requested->screenHeight - screenHeight;
- otherDelta += requested->screenHeight - o.screenHeight;
- }
- return (myDelta <= otherDelta);
- }
-
- if (version || o.version) {
- if ((sdkVersion != o.sdkVersion) && requested->sdkVersion) {
- return (sdkVersion > o.sdkVersion);
- }
-
- if ((minorVersion != o.minorVersion) &&
- requested->minorVersion) {
- return (minorVersion);
- }
- }
-
- return false;
- }
- return isMoreSpecificThan(o);
- }
+ bool isBetterThan(const ResTable_config& o, const ResTable_config* requested) const;
// Return true if 'this' can be considered a match for the parameters in
// 'settings'.
@@ -1452,150 +1048,11 @@
// but a request for the default should not match odd specifics
// (ie, request with no mcc should not match a particular mcc's data)
// settings is the requested settings
- inline bool match(const ResTable_config& settings) const {
- if (imsi != 0) {
- if (mcc != 0 && mcc != settings.mcc) {
- return false;
- }
- if (mnc != 0 && mnc != settings.mnc) {
- return false;
- }
- }
- if (locale != 0) {
- if (language[0] != 0
- && (language[0] != settings.language[0]
- || language[1] != settings.language[1])) {
- return false;
- }
- if (country[0] != 0
- && (country[0] != settings.country[0]
- || country[1] != settings.country[1])) {
- return false;
- }
- }
- if (screenConfig != 0) {
- const int screenSize = screenLayout&MASK_SCREENSIZE;
- const int setScreenSize = settings.screenLayout&MASK_SCREENSIZE;
- // Any screen sizes for larger screens than the setting do not
- // match.
- if (screenSize != 0 && screenSize > setScreenSize) {
- return false;
- }
-
- const int screenLong = screenLayout&MASK_SCREENLONG;
- const int setScreenLong = settings.screenLayout&MASK_SCREENLONG;
- if (screenLong != 0 && screenLong != setScreenLong) {
- return false;
- }
+ bool match(const ResTable_config& settings) const;
- const int uiModeType = uiMode&MASK_UI_MODE_TYPE;
- const int setUiModeType = settings.uiMode&MASK_UI_MODE_TYPE;
- if (uiModeType != 0 && uiModeType != setUiModeType) {
- return false;
- }
+ void getLocale(char str[6]) const;
- const int uiModeNight = uiMode&MASK_UI_MODE_NIGHT;
- const int setUiModeNight = settings.uiMode&MASK_UI_MODE_NIGHT;
- if (uiModeNight != 0 && uiModeNight != setUiModeNight) {
- return false;
- }
-
- if (smallestScreenWidthDp != 0
- && smallestScreenWidthDp > settings.smallestScreenWidthDp) {
- return false;
- }
- }
- if (screenSizeDp != 0) {
- if (screenWidthDp != 0 && screenWidthDp > settings.screenWidthDp) {
- //ALOGI("Filtering out width %d in requested %d", screenWidthDp, settings.screenWidthDp);
- return false;
- }
- if (screenHeightDp != 0 && screenHeightDp > settings.screenHeightDp) {
- //ALOGI("Filtering out height %d in requested %d", screenHeightDp, settings.screenHeightDp);
- return false;
- }
- }
- if (screenType != 0) {
- if (orientation != 0 && orientation != settings.orientation) {
- return false;
- }
- // density always matches - we can scale it. See isBetterThan
- if (touchscreen != 0 && touchscreen != settings.touchscreen) {
- return false;
- }
- }
- if (input != 0) {
- const int keysHidden = inputFlags&MASK_KEYSHIDDEN;
- const int setKeysHidden = settings.inputFlags&MASK_KEYSHIDDEN;
- if (keysHidden != 0 && keysHidden != setKeysHidden) {
- // For compatibility, we count a request for KEYSHIDDEN_NO as also
- // matching the more recent KEYSHIDDEN_SOFT. Basically
- // KEYSHIDDEN_NO means there is some kind of keyboard available.
- //ALOGI("Matching keysHidden: have=%d, config=%d\n", keysHidden, setKeysHidden);
- if (keysHidden != KEYSHIDDEN_NO || setKeysHidden != KEYSHIDDEN_SOFT) {
- //ALOGI("No match!");
- return false;
- }
- }
- const int navHidden = inputFlags&MASK_NAVHIDDEN;
- const int setNavHidden = settings.inputFlags&MASK_NAVHIDDEN;
- if (navHidden != 0 && navHidden != setNavHidden) {
- return false;
- }
- if (keyboard != 0 && keyboard != settings.keyboard) {
- return false;
- }
- if (navigation != 0 && navigation != settings.navigation) {
- return false;
- }
- }
- if (screenSize != 0) {
- if (screenWidth != 0 && screenWidth > settings.screenWidth) {
- return false;
- }
- if (screenHeight != 0 && screenHeight > settings.screenHeight) {
- return false;
- }
- }
- if (version != 0) {
- if (sdkVersion != 0 && sdkVersion > settings.sdkVersion) {
- return false;
- }
- if (minorVersion != 0 && minorVersion != settings.minorVersion) {
- return false;
- }
- }
- return true;
- }
-
- void getLocale(char str[6]) const {
- memset(str, 0, 6);
- if (language[0]) {
- str[0] = language[0];
- str[1] = language[1];
- if (country[0]) {
- str[2] = '_';
- str[3] = country[0];
- str[4] = country[1];
- }
- }
- }
-
- String8 toString() const {
- char buf[200];
- sprintf(buf, "imsi=%d/%d lang=%c%c reg=%c%c orient=%d touch=%d dens=%d "
- "kbd=%d nav=%d input=%d ssz=%dx%d sw%ddp w%ddp h%ddp sz=%d long=%d "
- "ui=%d night=%d vers=%d.%d",
- mcc, mnc,
- language[0] ? language[0] : '-', language[1] ? language[1] : '-',
- country[0] ? country[0] : '-', country[1] ? country[1] : '-',
- orientation, touchscreen, density, keyboard, navigation, inputFlags,
- screenWidth, screenHeight, smallestScreenWidthDp, screenWidthDp, screenHeightDp,
- screenLayout&MASK_SCREENSIZE, screenLayout&MASK_SCREENLONG,
- uiMode&MASK_UI_MODE_TYPE, uiMode&MASK_UI_MODE_NIGHT,
- sdkVersion, minorVersion);
- return String8(buf);
- }
+ String8 toString() const;
};
/**
@@ -2054,8 +1511,14 @@
const char16_t* getBasePackageName(size_t idx) const;
uint32_t getBasePackageId(size_t idx) const;
+ // Return the number of resource tables that the object contains.
size_t getTableCount() const;
+ // Return the values string pool for the resource table at the given
+ // index. This string pool contains all of the strings for values
+ // contained in the resource table -- that is the item values themselves,
+ // but not the names their entries or types.
const ResStringPool* getTableStringBlock(size_t index) const;
+ // Return unique cookie identifier for the given resource table.
void* getTableCookie(size_t index) const;
// Return the configurations (ResTable_config) that we know about
diff --git a/include/utils/threads.h b/include/utils/threads.h
index ab3e8cd..b4a8b7c 100644
--- a/include/utils/threads.h
+++ b/include/utils/threads.h
@@ -526,6 +526,12 @@
// Do not call from this object's thread; will return WOULD_BLOCK in that case.
status_t join();
+#ifdef HAVE_ANDROID_OS
+ // Return the thread's kernel ID, same as the thread itself calling gettid() or
+ // androidGetTid(), or -1 if the thread is not running.
+ pid_t getTid() const;
+#endif
+
protected:
// exitPending() returns true if requestExit() has been called.
bool exitPending() const;
@@ -551,8 +557,10 @@
volatile bool mExitPending;
volatile bool mRunning;
sp<Thread> mHoldSelf;
-#if HAVE_ANDROID_OS
- int mTid;
+#ifdef HAVE_ANDROID_OS
+ // legacy for debugging, not used by getTid() as it is set by the child thread
+ // and so is not initialized until the child reaches that point
+ pid_t mTid;
#endif
};
diff --git a/libs/gui/Android.mk b/libs/gui/Android.mk
index b8be67d..b6f5b9e 100644
--- a/libs/gui/Android.mk
+++ b/libs/gui/Android.mk
@@ -34,6 +34,13 @@
LOCAL_MODULE:= libgui
+ifeq ($(TARGET_BOARD_PLATFORM), omap4)
+ LOCAL_CFLAGS += -DUSE_FENCE_SYNC
+endif
+ifeq ($(TARGET_BOARD_PLATFORM), s5pc110)
+ LOCAL_CFLAGS += -DUSE_FENCE_SYNC
+endif
+
ifeq ($(TARGET_BOARD_PLATFORM), tegra)
LOCAL_CFLAGS += -DALLOW_DEQUEUE_CURRENT_BUFFER
endif
diff --git a/libs/gui/DisplayEventReceiver.cpp b/libs/gui/DisplayEventReceiver.cpp
index 3b3ccaa..6a4763d 100644
--- a/libs/gui/DisplayEventReceiver.cpp
+++ b/libs/gui/DisplayEventReceiver.cpp
@@ -80,7 +80,13 @@
ssize_t DisplayEventReceiver::getEvents(DisplayEventReceiver::Event* events,
size_t count) {
- ssize_t size = mDataChannel->read(events, sizeof(events[0])*count);
+ return DisplayEventReceiver::getEvents(mDataChannel, events, count);
+}
+
+ssize_t DisplayEventReceiver::getEvents(const sp<BitTube>& dataChannel,
+ Event* events, size_t count)
+{
+ ssize_t size = dataChannel->read(events, sizeof(events[0])*count);
ALOGE_IF(size<0,
"DisplayEventReceiver::getEvents error (%s)",
strerror(-size));
diff --git a/libs/hwui/Android.mk b/libs/hwui/Android.mk
index 95e0a18..5ec3983 100644
--- a/libs/hwui/Android.mk
+++ b/libs/hwui/Android.mk
@@ -26,6 +26,7 @@
ShapeCache.cpp \
SkiaColorFilter.cpp \
SkiaShader.cpp \
+ Snapshot.cpp \
TextureCache.cpp \
TextDropShadowCache.cpp
diff --git a/libs/hwui/Caches.cpp b/libs/hwui/Caches.cpp
index d1af1a3..0ef8469 100644
--- a/libs/hwui/Caches.cpp
+++ b/libs/hwui/Caches.cpp
@@ -55,6 +55,16 @@
glGetIntegerv(GL_MAX_TEXTURE_SIZE, &maxTextureSize);
+ if (extensions.hasDebugMarker()) {
+ eventMark = glInsertEventMarkerEXT;
+ startMark = glPushGroupMarkerEXT;
+ endMark = glPopGroupMarkerEXT;
+ } else {
+ eventMark = eventMarkNull;
+ startMark = startMarkNull;
+ endMark = endMarkNull;
+ }
+
init();
mDebugLevel = readDebugLevel();
diff --git a/libs/hwui/Caches.h b/libs/hwui/Caches.h
index 409584f..f8c7bcc 100644
--- a/libs/hwui/Caches.h
+++ b/libs/hwui/Caches.h
@@ -240,7 +240,15 @@
GammaFontRenderer fontRenderer;
ResourceCache resourceCache;
+ PFNGLINSERTEVENTMARKEREXTPROC eventMark;
+ PFNGLPUSHGROUPMARKEREXTPROC startMark;
+ PFNGLPOPGROUPMARKEREXTPROC endMark;
+
private:
+ static void eventMarkNull(GLsizei length, const GLchar *marker) { }
+ static void startMarkNull(GLsizei length, const GLchar *marker) { }
+ static void endMarkNull() { }
+
GLuint mCurrentBuffer;
GLuint mCurrentIndicesBuffer;
void* mCurrentPositionPointer;
diff --git a/libs/hwui/Debug.h b/libs/hwui/Debug.h
index 0ad0c2a..16a3d73 100644
--- a/libs/hwui/Debug.h
+++ b/libs/hwui/Debug.h
@@ -62,6 +62,9 @@
// Turn on to display debug info about the layer renderer
#define DEBUG_LAYER_RENDERER 0
+// Turn on to enable additional debugging in the font renderers
+#define DEBUG_FONT_RENDERER 0
+
// Turn on to dump display list state
#define DEBUG_DISPLAY_LIST 0
diff --git a/libs/hwui/DisplayListRenderer.cpp b/libs/hwui/DisplayListRenderer.cpp
index 824ab4f..1a11fbc 100644
--- a/libs/hwui/DisplayListRenderer.cpp
+++ b/libs/hwui/DisplayListRenderer.cpp
@@ -19,9 +19,10 @@
#include "DisplayListLogBuffer.h"
#include "DisplayListRenderer.h"
-#include <utils/String8.h>
#include "Caches.h"
+#include <utils/String8.h>
+
namespace android {
namespace uirenderer {
@@ -67,6 +68,8 @@
"SetupColorFilter",
"ResetShadow",
"SetupShadow",
+ "ResetPaintFilter",
+ "SetupPaintFilter",
"DrawGLFunction"
};
@@ -215,7 +218,7 @@
indent[i] = ' ';
}
indent[count] = '\0';
- ALOGD("%sStart display list (%p)", (char*) indent + 2, this);
+ ALOGD("%sStart display list (%p, %s)", (char*) indent + 2, this, mName.string());
int saveCount = renderer.getSaveCount() - 1;
@@ -249,7 +252,7 @@
float f2 = getFloat();
float f3 = getFloat();
float f4 = getFloat();
- SkPaint* paint = getPaint();
+ SkPaint* paint = getPaint(renderer);
int flags = getInt();
ALOGD("%s%s %.2f, %.2f, %.2f, %.2f, %p, 0x%x", (char*) indent,
OP_NAMES[op], f1, f2, f3, f4, paint, flags);
@@ -322,7 +325,7 @@
Layer* layer = (Layer*) getInt();
float x = getFloat();
float y = getFloat();
- SkPaint* paint = getPaint();
+ SkPaint* paint = getPaint(renderer);
ALOGD("%s%s %p, %.2f, %.2f, %p", (char*) indent, OP_NAMES[op],
layer, x, y, paint);
}
@@ -331,7 +334,7 @@
SkBitmap* bitmap = getBitmap();
float x = getFloat();
float y = getFloat();
- SkPaint* paint = getPaint();
+ SkPaint* paint = getPaint(renderer);
ALOGD("%s%s %p, %.2f, %.2f, %p", (char*) indent, OP_NAMES[op],
bitmap, x, y, paint);
}
@@ -339,7 +342,7 @@
case DrawBitmapMatrix: {
SkBitmap* bitmap = getBitmap();
SkMatrix* matrix = getMatrix();
- SkPaint* paint = getPaint();
+ SkPaint* paint = getPaint(renderer);
ALOGD("%s%s %p, %p, %p", (char*) indent, OP_NAMES[op],
bitmap, matrix, paint);
}
@@ -354,7 +357,7 @@
float f6 = getFloat();
float f7 = getFloat();
float f8 = getFloat();
- SkPaint* paint = getPaint();
+ SkPaint* paint = getPaint(renderer);
ALOGD("%s%s %p, %.2f, %.2f, %.2f, %.2f, %.2f, %.2f, %.2f, %.2f, %p",
(char*) indent, OP_NAMES[op], bitmap, f1, f2, f3, f4, f5, f6, f7, f8, paint);
}
@@ -368,7 +371,7 @@
float* vertices = getFloats(verticesCount);
bool hasColors = getInt();
int* colors = hasColors ? getInts(colorsCount) : NULL;
- SkPaint* paint = getPaint();
+ SkPaint* paint = getPaint(renderer);
ALOGD("%s%s", (char*) indent, OP_NAMES[op]);
}
break;
@@ -387,7 +390,7 @@
float top = getFloat();
float right = getFloat();
float bottom = getFloat();
- SkPaint* paint = getPaint();
+ SkPaint* paint = getPaint(renderer);
ALOGD("%s%s %.2f, %.2f, %.2f, %.2f", (char*) indent, OP_NAMES[op],
left, top, right, bottom);
}
@@ -403,7 +406,7 @@
float f2 = getFloat();
float f3 = getFloat();
float f4 = getFloat();
- SkPaint* paint = getPaint();
+ SkPaint* paint = getPaint(renderer);
ALOGD("%s%s %.2f, %.2f, %.2f, %.2f, %p", (char*) indent, OP_NAMES[op],
f1, f2, f3, f4, paint);
}
@@ -415,7 +418,7 @@
float f4 = getFloat();
float f5 = getFloat();
float f6 = getFloat();
- SkPaint* paint = getPaint();
+ SkPaint* paint = getPaint(renderer);
ALOGD("%s%s %.2f, %.2f, %.2f, %.2f, %.2f, %.2f, %p",
(char*) indent, OP_NAMES[op], f1, f2, f3, f4, f5, f6, paint);
}
@@ -424,7 +427,7 @@
float f1 = getFloat();
float f2 = getFloat();
float f3 = getFloat();
- SkPaint* paint = getPaint();
+ SkPaint* paint = getPaint(renderer);
ALOGD("%s%s %.2f, %.2f, %.2f, %p",
(char*) indent, OP_NAMES[op], f1, f2, f3, paint);
}
@@ -434,7 +437,7 @@
float f2 = getFloat();
float f3 = getFloat();
float f4 = getFloat();
- SkPaint* paint = getPaint();
+ SkPaint* paint = getPaint(renderer);
ALOGD("%s%s %.2f, %.2f, %.2f, %.2f, %p",
(char*) indent, OP_NAMES[op], f1, f2, f3, f4, paint);
}
@@ -447,28 +450,28 @@
float f5 = getFloat();
float f6 = getFloat();
int i1 = getInt();
- SkPaint* paint = getPaint();
+ SkPaint* paint = getPaint(renderer);
ALOGD("%s%s %.2f, %.2f, %.2f, %.2f, %.2f, %.2f, %d, %p",
(char*) indent, OP_NAMES[op], f1, f2, f3, f4, f5, f6, i1, paint);
}
break;
case DrawPath: {
SkPath* path = getPath();
- SkPaint* paint = getPaint();
+ SkPaint* paint = getPaint(renderer);
ALOGD("%s%s %p, %p", (char*) indent, OP_NAMES[op], path, paint);
}
break;
case DrawLines: {
int count = 0;
float* points = getFloats(count);
- SkPaint* paint = getPaint();
+ SkPaint* paint = getPaint(renderer);
ALOGD("%s%s", (char*) indent, OP_NAMES[op]);
}
break;
case DrawPoints: {
int count = 0;
float* points = getFloats(count);
- SkPaint* paint = getPaint();
+ SkPaint* paint = getPaint(renderer);
ALOGD("%s%s", (char*) indent, OP_NAMES[op]);
}
break;
@@ -477,7 +480,7 @@
int count = getInt();
float x = getFloat();
float y = getFloat();
- SkPaint* paint = getPaint();
+ SkPaint* paint = getPaint(renderer);
float length = getFloat();
ALOGD("%s%s %s, %d, %d, %.2f, %.2f, %p, %.2f", (char*) indent, OP_NAMES[op],
text.text(), text.length(), count, x, y, paint, length);
@@ -488,7 +491,7 @@
int count = getInt();
int positionsCount = 0;
float* positions = getFloats(positionsCount);
- SkPaint* paint = getPaint();
+ SkPaint* paint = getPaint(renderer);
ALOGD("%s%s %s, %d, %d, %p", (char*) indent, OP_NAMES[op],
text.text(), text.length(), count, paint);
}
@@ -523,6 +526,16 @@
radius, dx, dy, color);
}
break;
+ case ResetPaintFilter: {
+ ALOGD("%s%s", (char*) indent, OP_NAMES[op]);
+ }
+ break;
+ case SetupPaintFilter: {
+ int clearBits = getInt();
+ int setBits = getInt();
+ ALOGD("%s%s 0x%x, 0x%x", (char*) indent, OP_NAMES[op], clearBits, setBits);
+ }
+ break;
default:
ALOGD("Display List error: op not handled: %s%s",
(char*) indent, OP_NAMES[op]);
@@ -550,9 +563,11 @@
indent[i] = ' ';
}
indent[count] = '\0';
- DISPLAY_LIST_LOGD("%sStart display list (%p)", (char*) indent + 2, this);
+ DISPLAY_LIST_LOGD("%sStart display list (%p, %s)", (char*) indent + 2, this, mName.string());
#endif
+ renderer.startMark(mName.string());
+
DisplayListLogBuffer& logBuffer = DisplayListLogBuffer::getInstance();
int saveCount = renderer.getSaveCount() - 1;
while (!mReader.eof()) {
@@ -563,7 +578,9 @@
case DrawGLFunction: {
Functor *functor = (Functor *) getInt();
DISPLAY_LIST_LOGD("%s%s %p", (char*) indent, OP_NAMES[op], functor);
+ renderer.startMark("GL functor");
needsInvalidate |= renderer.callDrawGLFunction(functor, dirty);
+ renderer.endMark();
}
break;
case Save: {
@@ -588,7 +605,7 @@
float f2 = getFloat();
float f3 = getFloat();
float f4 = getFloat();
- SkPaint* paint = getPaint();
+ SkPaint* paint = getPaint(renderer);
int flags = getInt();
DISPLAY_LIST_LOGD("%s%s %.2f, %.2f, %.2f, %.2f, %p, 0x%x", (char*) indent,
OP_NAMES[op], f1, f2, f3, f4, paint, flags);
@@ -671,7 +688,7 @@
Layer* layer = (Layer*) getInt();
float x = getFloat();
float y = getFloat();
- SkPaint* paint = getPaint();
+ SkPaint* paint = getPaint(renderer);
DISPLAY_LIST_LOGD("%s%s %p, %.2f, %.2f, %p", (char*) indent, OP_NAMES[op],
layer, x, y, paint);
renderer.drawLayer(layer, x, y, paint);
@@ -681,7 +698,7 @@
SkBitmap* bitmap = getBitmap();
float x = getFloat();
float y = getFloat();
- SkPaint* paint = getPaint();
+ SkPaint* paint = getPaint(renderer);
DISPLAY_LIST_LOGD("%s%s %p, %.2f, %.2f, %p", (char*) indent, OP_NAMES[op],
bitmap, x, y, paint);
renderer.drawBitmap(bitmap, x, y, paint);
@@ -690,7 +707,7 @@
case DrawBitmapMatrix: {
SkBitmap* bitmap = getBitmap();
SkMatrix* matrix = getMatrix();
- SkPaint* paint = getPaint();
+ SkPaint* paint = getPaint(renderer);
DISPLAY_LIST_LOGD("%s%s %p, %p, %p", (char*) indent, OP_NAMES[op],
bitmap, matrix, paint);
renderer.drawBitmap(bitmap, matrix, paint);
@@ -706,7 +723,7 @@
float f6 = getFloat();
float f7 = getFloat();
float f8 = getFloat();
- SkPaint* paint = getPaint();
+ SkPaint* paint = getPaint(renderer);
DISPLAY_LIST_LOGD("%s%s %p, %.2f, %.2f, %.2f, %.2f, %.2f, %.2f, %.2f, %.2f, %p",
(char*) indent, OP_NAMES[op], bitmap, f1, f2, f3, f4, f5, f6, f7, f8, paint);
renderer.drawBitmap(bitmap, f1, f2, f3, f4, f5, f6, f7, f8, paint);
@@ -722,7 +739,7 @@
float* vertices = getFloats(verticesCount);
bool hasColors = getInt();
int* colors = hasColors ? getInts(colorsCount) : NULL;
- SkPaint* paint = getPaint();
+ SkPaint* paint = getPaint(renderer);
DISPLAY_LIST_LOGD("%s%s", (char*) indent, OP_NAMES[op]);
renderer.drawBitmapMesh(bitmap, meshWidth, meshHeight, vertices, colors, paint);
@@ -746,7 +763,7 @@
float top = getFloat();
float right = getFloat();
float bottom = getFloat();
- SkPaint* paint = getPaint();
+ SkPaint* paint = getPaint(renderer);
DISPLAY_LIST_LOGD("%s%s", (char*) indent, OP_NAMES[op]);
renderer.drawPatch(bitmap, xDivs, yDivs, colors, xDivsCount, yDivsCount,
@@ -765,7 +782,7 @@
float f2 = getFloat();
float f3 = getFloat();
float f4 = getFloat();
- SkPaint* paint = getPaint();
+ SkPaint* paint = getPaint(renderer);
DISPLAY_LIST_LOGD("%s%s %.2f, %.2f, %.2f, %.2f, %p", (char*) indent, OP_NAMES[op],
f1, f2, f3, f4, paint);
renderer.drawRect(f1, f2, f3, f4, paint);
@@ -778,7 +795,7 @@
float f4 = getFloat();
float f5 = getFloat();
float f6 = getFloat();
- SkPaint* paint = getPaint();
+ SkPaint* paint = getPaint(renderer);
DISPLAY_LIST_LOGD("%s%s %.2f, %.2f, %.2f, %.2f, %.2f, %.2f, %p",
(char*) indent, OP_NAMES[op], f1, f2, f3, f4, f5, f6, paint);
renderer.drawRoundRect(f1, f2, f3, f4, f5, f6, paint);
@@ -788,7 +805,7 @@
float f1 = getFloat();
float f2 = getFloat();
float f3 = getFloat();
- SkPaint* paint = getPaint();
+ SkPaint* paint = getPaint(renderer);
DISPLAY_LIST_LOGD("%s%s %.2f, %.2f, %.2f, %p",
(char*) indent, OP_NAMES[op], f1, f2, f3, paint);
renderer.drawCircle(f1, f2, f3, paint);
@@ -799,7 +816,7 @@
float f2 = getFloat();
float f3 = getFloat();
float f4 = getFloat();
- SkPaint* paint = getPaint();
+ SkPaint* paint = getPaint(renderer);
DISPLAY_LIST_LOGD("%s%s %.2f, %.2f, %.2f, %.2f, %p",
(char*) indent, OP_NAMES[op], f1, f2, f3, f4, paint);
renderer.drawOval(f1, f2, f3, f4, paint);
@@ -813,7 +830,7 @@
float f5 = getFloat();
float f6 = getFloat();
int i1 = getInt();
- SkPaint* paint = getPaint();
+ SkPaint* paint = getPaint(renderer);
DISPLAY_LIST_LOGD("%s%s %.2f, %.2f, %.2f, %.2f, %.2f, %.2f, %d, %p",
(char*) indent, OP_NAMES[op], f1, f2, f3, f4, f5, f6, i1, paint);
renderer.drawArc(f1, f2, f3, f4, f5, f6, i1 == 1, paint);
@@ -821,7 +838,7 @@
break;
case DrawPath: {
SkPath* path = getPath();
- SkPaint* paint = getPaint();
+ SkPaint* paint = getPaint(renderer);
DISPLAY_LIST_LOGD("%s%s %p, %p", (char*) indent, OP_NAMES[op], path, paint);
renderer.drawPath(path, paint);
}
@@ -829,7 +846,7 @@
case DrawLines: {
int count = 0;
float* points = getFloats(count);
- SkPaint* paint = getPaint();
+ SkPaint* paint = getPaint(renderer);
DISPLAY_LIST_LOGD("%s%s", (char*) indent, OP_NAMES[op]);
renderer.drawLines(points, count, paint);
}
@@ -837,7 +854,7 @@
case DrawPoints: {
int count = 0;
float* points = getFloats(count);
- SkPaint* paint = getPaint();
+ SkPaint* paint = getPaint(renderer);
DISPLAY_LIST_LOGD("%s%s", (char*) indent, OP_NAMES[op]);
renderer.drawPoints(points, count, paint);
}
@@ -847,7 +864,7 @@
int count = getInt();
float x = getFloat();
float y = getFloat();
- SkPaint* paint = getPaint();
+ SkPaint* paint = getPaint(renderer);
float length = getFloat();
DISPLAY_LIST_LOGD("%s%s %s, %d, %d, %.2f, %.2f, %p, %.2f", (char*) indent,
OP_NAMES[op], text.text(), text.length(), count, x, y, paint, length);
@@ -859,7 +876,7 @@
int count = getInt();
int positionsCount = 0;
float* positions = getFloats(positionsCount);
- SkPaint* paint = getPaint();
+ SkPaint* paint = getPaint(renderer);
DISPLAY_LIST_LOGD("%s%s %s, %d, %d, %p", (char*) indent,
OP_NAMES[op], text.text(), text.length(), count, paint);
renderer.drawPosText(text.text(), text.length(), count, positions, paint);
@@ -902,6 +919,19 @@
renderer.setupShadow(radius, dx, dy, color);
}
break;
+ case ResetPaintFilter: {
+ DISPLAY_LIST_LOGD("%s%s", (char*) indent, OP_NAMES[op]);
+ renderer.resetPaintFilter();
+ }
+ break;
+ case SetupPaintFilter: {
+ int clearBits = getInt();
+ int setBits = getInt();
+ DISPLAY_LIST_LOGD("%s%s 0x%x, 0x%x", (char*) indent, OP_NAMES[op],
+ clearBits, setBits);
+ renderer.setupPaintFilter(clearBits, setBits);
+ }
+ break;
default:
DISPLAY_LIST_LOGD("Display List error: op not handled: %s%s",
(char*) indent, OP_NAMES[op]);
@@ -909,6 +939,8 @@
}
}
+ renderer.endMark();
+
DISPLAY_LIST_LOGD("%sDone, returning %d", (char*) indent + 2, needsInvalidate);
return needsInvalidate;
}
@@ -1277,5 +1309,15 @@
addInt(color);
}
+void DisplayListRenderer::resetPaintFilter() {
+ addOp(DisplayList::ResetPaintFilter);
+}
+
+void DisplayListRenderer::setupPaintFilter(int clearBits, int setBits) {
+ addOp(DisplayList::SetupPaintFilter);
+ addInt(clearBits);
+ addInt(setBits);
+}
+
}; // namespace uirenderer
}; // namespace android
diff --git a/libs/hwui/DisplayListRenderer.h b/libs/hwui/DisplayListRenderer.h
index 422184e..46506e4 100644
--- a/libs/hwui/DisplayListRenderer.h
+++ b/libs/hwui/DisplayListRenderer.h
@@ -28,6 +28,8 @@
#include <cutils/compiler.h>
+#include <utils/String8.h>
+
#include "DisplayListLogBuffer.h"
#include "OpenGLRenderer.h"
#include "utils/Functor.h"
@@ -103,6 +105,8 @@
SetupColorFilter,
ResetShadow,
SetupShadow,
+ ResetPaintFilter,
+ SetupPaintFilter,
DrawGLFunction,
};
@@ -126,6 +130,12 @@
return mIsRenderable;
}
+ void setName(const char* name) {
+ if (name) {
+ mName.setTo(name);
+ }
+ }
+
private:
void init();
@@ -177,8 +187,8 @@
return (SkPath*) getInt();
}
- SkPaint* getPaint() {
- return (SkPaint*) getInt();
+ SkPaint* getPaint(OpenGLRenderer& renderer) {
+ return renderer.filterPaint((SkPaint*) getInt());
}
DisplayList* getDisplayList() {
@@ -222,6 +232,8 @@
size_t mSize;
bool mIsRenderable;
+
+ String8 mName;
};
///////////////////////////////////////////////////////////////////////////////
@@ -304,6 +316,9 @@
virtual void resetShadow();
virtual void setupShadow(float radius, float dx, float dy, int color);
+ virtual void resetPaintFilter();
+ virtual void setupPaintFilter(int clearBits, int setBits);
+
ANDROID_API void reset();
const SkWriter32& writeStream() const {
diff --git a/libs/hwui/Extensions.h b/libs/hwui/Extensions.h
index 1069e3f..f11fecc 100644
--- a/libs/hwui/Extensions.h
+++ b/libs/hwui/Extensions.h
@@ -67,6 +67,7 @@
mHasNPot = hasExtension("GL_OES_texture_npot");
mHasFramebufferFetch = hasExtension("GL_NV_shader_framebuffer_fetch");
mHasDiscardFramebuffer = hasExtension("GL_EXT_discard_framebuffer");
+ mHasDebugMarker = hasExtension("GL_EXT_debug_marker");
const char* vendor = (const char*) glGetString(GL_VENDOR);
EXT_LOGD("Vendor: %s", vendor);
@@ -82,6 +83,7 @@
inline bool hasFramebufferFetch() const { return mHasFramebufferFetch; }
inline bool needsHighpTexCoords() const { return mNeedsHighpTexCoords; }
inline bool hasDiscardFramebuffer() const { return mHasDiscardFramebuffer; }
+ inline bool hasDebugMarker() const { return mHasDebugMarker; }
bool hasExtension(const char* extension) const {
const String8 s(extension);
@@ -101,6 +103,7 @@
bool mNeedsHighpTexCoords;
bool mHasFramebufferFetch;
bool mHasDiscardFramebuffer;
+ bool mHasDebugMarker;
}; // class Extensions
}; // namespace uirenderer
diff --git a/libs/hwui/FontRenderer.cpp b/libs/hwui/FontRenderer.cpp
index 74efda2..3df105b 100644
--- a/libs/hwui/FontRenderer.cpp
+++ b/libs/hwui/FontRenderer.cpp
@@ -151,10 +151,12 @@
int32_t bX = 0, bY = 0;
for (cacheX = glyph->mStartX, bX = nPenX; cacheX < endX; cacheX++, bX++) {
for (cacheY = glyph->mStartY, bY = nPenY; cacheY < endY; cacheY++, bY++) {
+#if DEBUG_FONT_RENDERER
if (bX < 0 || bY < 0 || bX >= (int32_t) bitmapW || bY >= (int32_t) bitmapH) {
ALOGE("Skipping invalid index");
continue;
}
+#endif
uint8_t tempCol = cacheBuffer[cacheY * cacheWidth + cacheX];
bitmap[bY * bitmapW + bX] = tempCol;
}
@@ -226,7 +228,7 @@
};
RenderGlyph render = gRenderGlyph[mode];
- if (positions == NULL) {
+ if (CC_LIKELY(positions == NULL)) {
SkFixed prevRsbDelta = 0;
float penX = x;
diff --git a/libs/hwui/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp
index 786a4f1..afae70f 100644
--- a/libs/hwui/OpenGLRenderer.cpp
+++ b/libs/hwui/OpenGLRenderer.cpp
@@ -111,6 +111,7 @@
mShader = NULL;
mColorFilter = NULL;
mHasShadow = false;
+ mHasDrawFilter = false;
memcpy(mMeshVertices, gMeshVertices, sizeof(gMeshVertices));
@@ -123,9 +124,25 @@
}
///////////////////////////////////////////////////////////////////////////////
+// Debug
+///////////////////////////////////////////////////////////////////////////////
+
+void OpenGLRenderer::startMark(const char* name) const {
+ mCaches.startMark(0, name);
+}
+
+void OpenGLRenderer::endMark() const {
+ mCaches.endMark();
+}
+
+///////////////////////////////////////////////////////////////////////////////
// Setup
///////////////////////////////////////////////////////////////////////////////
+uint32_t OpenGLRenderer::getStencilSize() {
+ return STENCIL_BUFFER_SIZE;
+}
+
void OpenGLRenderer::setViewport(int width, int height) {
mOrthoMatrix.loadOrtho(0, width, height, 0, -1, 1);
@@ -737,7 +754,7 @@
// TODO: See LayerRenderer.cpp::generateMesh() for important
// information about this implementation
- if (!layer->region.isEmpty()) {
+ if (CC_LIKELY(!layer->region.isEmpty())) {
size_t count;
const android::Rect* rects = layer->region.getArray(&count);
@@ -1381,7 +1398,7 @@
if (!texture) return;
const AutoTexture autoCleanup(texture);
- if (bitmap->getConfig() == SkBitmap::kA8_Config) {
+ if (CC_UNLIKELY(bitmap->getConfig() == SkBitmap::kA8_Config)) {
drawAlphaBitmap(texture, left, top, paint);
} else {
drawTextureRect(left, top, right, bottom, texture, paint);
@@ -1437,9 +1454,9 @@
float bottom = FLT_MIN;
#if RENDER_LAYERS_AS_REGIONS
- bool hasActiveLayer = hasLayer();
+ const bool hasActiveLayer = hasLayer();
#else
- bool hasActiveLayer = false;
+ const bool hasActiveLayer = false;
#endif
// TODO: Support the colors array
@@ -1524,7 +1541,7 @@
texture->setWrap(GL_CLAMP_TO_EDGE, true);
- if (mSnapshot->transform->isPureTranslate()) {
+ if (CC_LIKELY(mSnapshot->transform->isPureTranslate())) {
const float x = (int) floorf(dstLeft + mSnapshot->transform->getTranslateX() + 0.5f);
const float y = (int) floorf(dstTop + mSnapshot->transform->getTranslateY() + 0.5f);
@@ -1570,7 +1587,7 @@
const Patch* mesh = mCaches.patchCache.get(bitmap->width(), bitmap->height(),
right - left, bottom - top, xDivs, yDivs, colors, width, height, numColors);
- if (mesh && mesh->verticesCount > 0) {
+ if (CC_LIKELY(mesh && mesh->verticesCount > 0)) {
const bool pureTranslate = mSnapshot->transform->isPureTranslate();
#if RENDER_LAYERS_AS_REGIONS
// Mark the current layer dirty where we are going to draw the patch
@@ -1580,7 +1597,7 @@
const size_t count = mesh->quads.size();
for (size_t i = 0; i < count; i++) {
const Rect& bounds = mesh->quads.itemAt(i);
- if (pureTranslate) {
+ if (CC_LIKELY(pureTranslate)) {
const float x = (int) floorf(bounds.left + offsetX + 0.5f);
const float y = (int) floorf(bounds.top + offsetY + 0.5f);
dirtyLayer(x, y, x + bounds.getWidth(), y + bounds.getHeight());
@@ -1592,7 +1609,7 @@
}
#endif
- if (pureTranslate) {
+ if (CC_LIKELY(pureTranslate)) {
const float x = (int) floorf(left + mSnapshot->transform->getTranslateX() + 0.5f);
const float y = (int) floorf(top + mSnapshot->transform->getTranslateY() + 0.5f);
@@ -1620,7 +1637,7 @@
float inverseScaleX = 1.0f;
float inverseScaleY = 1.0f;
// The quad that we use needs to account for scaling.
- if (!mSnapshot->transform->isPureTranslate()) {
+ if (CC_UNLIKELY(!mSnapshot->transform->isPureTranslate())) {
Matrix4 *mat = mSnapshot->transform;
float m00 = mat->data[Matrix4::kScaleX];
float m01 = mat->data[Matrix4::kSkewY];
@@ -1726,7 +1743,7 @@
// The quad that we use for AA and hairlines needs to account for scaling. For hairlines
// the line on the screen should always be one pixel wide regardless of scale. For
// AA lines, we only want one pixel of translucent boundary around the quad.
- if (!mSnapshot->transform->isPureTranslate()) {
+ if (CC_UNLIKELY(!mSnapshot->transform->isPureTranslate())) {
Matrix4 *mat = mSnapshot->transform;
float m00 = mat->data[Matrix4::kScaleX];
float m01 = mat->data[Matrix4::kSkewY];
@@ -1734,8 +1751,8 @@
float m10 = mat->data[Matrix4::kSkewX];
float m11 = mat->data[Matrix4::kScaleX];
float m12 = mat->data[6];
- float scaleX = sqrt(m00*m00 + m01*m01);
- float scaleY = sqrt(m10*m10 + m11*m11);
+ float scaleX = sqrtf(m00 * m00 + m01 * m01);
+ float scaleY = sqrtf(m10 * m10 + m11 * m11);
inverseScaleX = (scaleX != 0) ? (inverseScaleX / scaleX) : 0;
inverseScaleY = (scaleY != 0) ? (inverseScaleY / scaleY) : 0;
if (inverseScaleX != 1.0f || inverseScaleY != 1.0f) {
@@ -1753,11 +1770,7 @@
setupDrawColor(paint->getColor(), alpha);
setupDrawColorFilter();
setupDrawShader();
- if (isAA) {
- setupDrawBlending(true, mode);
- } else {
- setupDrawBlending(mode);
- }
+ setupDrawBlending(isAA, mode);
setupDrawProgram();
setupDrawModelViewIdentity(true);
setupDrawColorUniforms();
@@ -1775,7 +1788,7 @@
Vertex* vertices = &lines[0];
AAVertex wLines[verticesCount];
AAVertex* aaVertices = &wLines[0];
- if (!isAA) {
+ if (CC_UNLIKELY(!isAA)) {
setupDrawVertices(vertices);
} else {
void* widthCoords = ((GLbyte*) aaVertices) + gVertexAAWidthOffset;
@@ -2135,9 +2148,9 @@
Rect bounds(FLT_MAX / 2.0f, FLT_MAX / 2.0f, FLT_MIN / 2.0f, FLT_MIN / 2.0f);
#if RENDER_LAYERS_AS_REGIONS
- bool hasActiveLayer = hasLayer();
+ const bool hasActiveLayer = hasLayer();
#else
- bool hasActiveLayer = false;
+ const bool hasActiveLayer = false;
#endif
if (fontRenderer.renderPosText(paint, clip, text, 0, bytesCount, count, x, y,
@@ -2184,7 +2197,7 @@
const float oldX = x;
const float oldY = y;
const bool pureTranslate = mSnapshot->transform->isPureTranslate();
- if (pureTranslate) {
+ if (CC_LIKELY(pureTranslate)) {
x = (int) floorf(x + mSnapshot->transform->getTranslateX() + 0.5f);
y = (int) floorf(y + mSnapshot->transform->getTranslateY() + 0.5f);
}
@@ -2201,7 +2214,7 @@
SkXfermode::Mode mode;
getAlphaAndMode(paint, &alpha, &mode);
- if (mHasShadow) {
+ if (CC_UNLIKELY(mHasShadow)) {
mCaches.activeTexture(0);
mCaches.dropShadowCache.setFontRenderer(fontRenderer);
@@ -2260,9 +2273,9 @@
Rect bounds(FLT_MAX / 2.0f, FLT_MAX / 2.0f, FLT_MIN / 2.0f, FLT_MIN / 2.0f);
#if RENDER_LAYERS_AS_REGIONS
- bool hasActiveLayer = hasLayer();
+ const bool hasActiveLayer = hasLayer();
#else
- bool hasActiveLayer = false;
+ const bool hasActiveLayer = false;
#endif
if (fontRenderer.renderText(paint, clip, text, 0, bytesCount, count, x, y,
@@ -2309,7 +2322,7 @@
layer->setAlpha(alpha, mode);
#if RENDER_LAYERS_AS_REGIONS
- if (!layer->region.isEmpty()) {
+ if (CC_LIKELY(!layer->region.isEmpty())) {
if (layer->region.isRect()) {
composeLayerRect(layer, layer->regionRect);
} else if (layer->mesh) {
@@ -2325,7 +2338,7 @@
setupDrawPureColorUniforms();
setupDrawColorFilterUniforms();
setupDrawTexture(layer->getTexture());
- if (mSnapshot->transform->isPureTranslate()) {
+ if (CC_LIKELY(mSnapshot->transform->isPureTranslate())) {
x = (int) floorf(x + mSnapshot->transform->getTranslateX() + 0.5f);
y = (int) floorf(y + mSnapshot->transform->getTranslateY() + 0.5f);
@@ -2399,6 +2412,31 @@
}
///////////////////////////////////////////////////////////////////////////////
+// Draw filters
+///////////////////////////////////////////////////////////////////////////////
+
+void OpenGLRenderer::resetPaintFilter() {
+ mHasDrawFilter = false;
+}
+
+void OpenGLRenderer::setupPaintFilter(int clearBits, int setBits) {
+ mHasDrawFilter = true;
+ mPaintFilterClearBits = clearBits & SkPaint::kAllFlags;
+ mPaintFilterSetBits = setBits & SkPaint::kAllFlags;
+}
+
+SkPaint* OpenGLRenderer::filterPaint(SkPaint* paint) {
+ if (!mHasDrawFilter || !paint) return paint;
+
+ uint32_t flags = paint->getFlags();
+
+ mFilteredPaint = *paint;
+ mFilteredPaint.setFlags((flags & ~mPaintFilterClearBits) | mPaintFilterSetBits);
+
+ return &mFilteredPaint;
+}
+
+///////////////////////////////////////////////////////////////////////////////
// Drawing implementation
///////////////////////////////////////////////////////////////////////////////
@@ -2460,7 +2498,7 @@
break;
}
- if (underlineWidth > 0.0f) {
+ if (CC_LIKELY(underlineWidth > 0.0f)) {
const float textSize = paintCopy.getTextSize();
const float strokeWidth = fmax(textSize * kStdUnderline_Thickness, 1.0f);
@@ -2529,7 +2567,7 @@
texture->setWrap(GL_CLAMP_TO_EDGE, true);
- if (mSnapshot->transform->isPureTranslate()) {
+ if (CC_LIKELY(mSnapshot->transform->isPureTranslate())) {
const float x = (int) floorf(left + mSnapshot->transform->getTranslateX() + 0.5f);
const float y = (int) floorf(top + mSnapshot->transform->getTranslateY() + 0.5f);
@@ -2589,8 +2627,8 @@
// the blending, turn blending off here
// If the blend mode cannot be implemented using shaders, fall
// back to the default SrcOver blend mode instead
- if (mode > SkXfermode::kScreen_Mode) {
- if (mCaches.extensions.hasFramebufferFetch()) {
+ if CC_UNLIKELY((mode > SkXfermode::kScreen_Mode)) {
+ if (CC_UNLIKELY(mCaches.extensions.hasFramebufferFetch())) {
description.framebufferMode = mode;
description.swapSrcDst = swapSrcDst;
diff --git a/libs/hwui/OpenGLRenderer.h b/libs/hwui/OpenGLRenderer.h
index a9cda47..3c2d09e 100644
--- a/libs/hwui/OpenGLRenderer.h
+++ b/libs/hwui/OpenGLRenderer.h
@@ -136,6 +136,16 @@
virtual void resetShadow();
virtual void setupShadow(float radius, float dx, float dy, int color);
+ virtual void resetPaintFilter();
+ virtual void setupPaintFilter(int clearBits, int setBits);
+
+ SkPaint* filterPaint(SkPaint* paint);
+
+ ANDROID_API static uint32_t getStencilSize();
+
+ void startMark(const char* name) const;
+ void endMark() const;
+
protected:
/**
* Compose the layer defined in the current snapshot with the layer
@@ -581,6 +591,12 @@
float mShadowDy;
int mShadowColor;
+ // Draw filters
+ bool mHasDrawFilter;
+ int mPaintFilterClearBits;
+ int mPaintFilterSetBits;
+ SkPaint mFilteredPaint;
+
// Various caches
Caches& mCaches;
diff --git a/libs/hwui/Properties.h b/libs/hwui/Properties.h
index 2eae0f1..7854729 100644
--- a/libs/hwui/Properties.h
+++ b/libs/hwui/Properties.h
@@ -37,6 +37,11 @@
// Textures used by layers must have dimensions multiples of this number
#define LAYER_SIZE 64
+// Defines the size in bits of the stencil buffer
+// Note: Only 1 bit is required for clipping but more bits are required
+// to properly implement the winding fill rule when rasterizing paths
+#define STENCIL_BUFFER_SIZE 0
+
/**
* Debug level for app developers.
*/
diff --git a/libs/hwui/Snapshot.cpp b/libs/hwui/Snapshot.cpp
new file mode 100644
index 0000000..a85362d
--- /dev/null
+++ b/libs/hwui/Snapshot.cpp
@@ -0,0 +1,154 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "Snapshot.h"
+
+#include <SkCanvas.h>
+
+namespace android {
+namespace uirenderer {
+
+///////////////////////////////////////////////////////////////////////////////
+// Constructors
+///////////////////////////////////////////////////////////////////////////////
+
+Snapshot::Snapshot(): flags(0), previous(NULL), layer(NULL), fbo(0),
+ invisible(false), empty(false) {
+
+ transform = &mTransformRoot;
+ clipRect = &mClipRectRoot;
+ region = NULL;
+}
+
+/**
+ * Copies the specified snapshot/ The specified snapshot is stored as
+ * the previous snapshot.
+ */
+Snapshot::Snapshot(const sp<Snapshot>& s, int saveFlags):
+ flags(0), previous(s), layer(NULL), fbo(s->fbo),
+ invisible(s->invisible), empty(false),
+ viewport(s->viewport), height(s->height) {
+
+ if (saveFlags & SkCanvas::kMatrix_SaveFlag) {
+ mTransformRoot.load(*s->transform);
+ transform = &mTransformRoot;
+ } else {
+ transform = s->transform;
+ }
+
+ if (saveFlags & SkCanvas::kClip_SaveFlag) {
+ mClipRectRoot.set(*s->clipRect);
+ clipRect = &mClipRectRoot;
+ } else {
+ clipRect = s->clipRect;
+ }
+
+ if (s->flags & Snapshot::kFlagFboTarget) {
+ flags |= Snapshot::kFlagFboTarget;
+ region = s->region;
+ } else {
+ region = NULL;
+ }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// Clipping
+///////////////////////////////////////////////////////////////////////////////
+
+bool Snapshot::clip(float left, float top, float right, float bottom, SkRegion::Op op) {
+ Rect r(left, top, right, bottom);
+ transform->mapRect(r);
+ return clipTransformed(r, op);
+}
+
+bool Snapshot::clipTransformed(const Rect& r, SkRegion::Op op) {
+ bool clipped = false;
+
+ // NOTE: The unimplemented operations require support for regions
+ // Supporting regions would require using a stencil buffer instead
+ // of the scissor. The stencil buffer itself is not too expensive
+ // (memory cost excluded) but on fillrate limited devices, managing
+ // the stencil might have a negative impact on the framerate.
+ switch (op) {
+ case SkRegion::kDifference_Op:
+ break;
+ case SkRegion::kIntersect_Op:
+ clipped = clipRect->intersect(r);
+ if (!clipped) {
+ clipRect->setEmpty();
+ clipped = true;
+ }
+ break;
+ case SkRegion::kUnion_Op:
+ clipped = clipRect->unionWith(r);
+ break;
+ case SkRegion::kXOR_Op:
+ break;
+ case SkRegion::kReverseDifference_Op:
+ break;
+ case SkRegion::kReplace_Op:
+ clipRect->set(r);
+ clipped = true;
+ break;
+ }
+
+ if (clipped) {
+ flags |= Snapshot::kFlagClipSet;
+ }
+
+ return clipped;
+}
+
+void Snapshot::setClip(float left, float top, float right, float bottom) {
+ clipRect->set(left, top, right, bottom);
+ flags |= Snapshot::kFlagClipSet;
+}
+
+const Rect& Snapshot::getLocalClip() {
+ mat4 inverse;
+ inverse.loadInverse(*transform);
+
+ mLocalClip.set(*clipRect);
+ inverse.mapRect(mLocalClip);
+
+ return mLocalClip;
+}
+
+void Snapshot::resetClip(float left, float top, float right, float bottom) {
+ clipRect = &mClipRectRoot;
+ clipRect->set(left, top, right, bottom);
+ flags |= Snapshot::kFlagClipSet;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// Transforms
+///////////////////////////////////////////////////////////////////////////////
+
+void Snapshot::resetTransform(float x, float y, float z) {
+ transform = &mTransformRoot;
+ transform->loadTranslate(x, y, z);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// Queries
+///////////////////////////////////////////////////////////////////////////////
+
+bool Snapshot::isIgnored() const {
+ return invisible || empty;
+}
+
+}; // namespace uirenderer
+}; // namespace android
diff --git a/libs/hwui/Snapshot.h b/libs/hwui/Snapshot.h
index aff7b93..c94af7e 100644
--- a/libs/hwui/Snapshot.h
+++ b/libs/hwui/Snapshot.h
@@ -23,7 +23,7 @@
#include <utils/RefBase.h>
#include <ui/Region.h>
-#include <SkCanvas.h>
+#include <SkRegion.h>
#include "Layer.h"
#include "Matrix.h"
@@ -43,43 +43,12 @@
*/
class Snapshot: public LightRefBase<Snapshot> {
public:
- Snapshot(): flags(0), previous(NULL), layer(NULL), fbo(0), invisible(false), empty(false) {
- transform = &mTransformRoot;
- clipRect = &mClipRectRoot;
- region = NULL;
- }
+
+ Snapshot();
+ Snapshot(const sp<Snapshot>& s, int saveFlags);
/**
- * Copies the specified snapshot/ The specified snapshot is stored as
- * the previous snapshot.
- */
- Snapshot(const sp<Snapshot>& s, int saveFlags):
- flags(0), previous(s), layer(NULL), fbo(s->fbo),
- invisible(s->invisible), empty(false), viewport(s->viewport), height(s->height) {
- if (saveFlags & SkCanvas::kMatrix_SaveFlag) {
- mTransformRoot.load(*s->transform);
- transform = &mTransformRoot;
- } else {
- transform = s->transform;
- }
-
- if (saveFlags & SkCanvas::kClip_SaveFlag) {
- mClipRectRoot.set(*s->clipRect);
- clipRect = &mClipRectRoot;
- } else {
- clipRect = s->clipRect;
- }
-
- if (s->flags & Snapshot::kFlagFboTarget) {
- flags |= Snapshot::kFlagFboTarget;
- region = s->region;
- } else {
- region = NULL;
- }
- }
-
- /**
- * Various flags set on #flags.
+ * Various flags set on ::flags.
*/
enum Flags {
/**
@@ -115,87 +84,41 @@
* by this snapshot's trasnformation.
*/
bool clip(float left, float top, float right, float bottom,
- SkRegion::Op op = SkRegion::kIntersect_Op) {
- Rect r(left, top, right, bottom);
- transform->mapRect(r);
- return clipTransformed(r, op);
- }
+ SkRegion::Op op = SkRegion::kIntersect_Op);
/**
* Modifies the current clip with the new clip rectangle and
* the specified operation. The specified rectangle is considered
* already transformed.
*/
- bool clipTransformed(const Rect& r, SkRegion::Op op = SkRegion::kIntersect_Op) {
- bool clipped = false;
-
- // NOTE: The unimplemented operations require support for regions
- // Supporting regions would require using a stencil buffer instead
- // of the scissor. The stencil buffer itself is not too expensive
- // (memory cost excluded) but on fillrate limited devices, managing
- // the stencil might have a negative impact on the framerate.
- switch (op) {
- case SkRegion::kDifference_Op:
- break;
- case SkRegion::kIntersect_Op:
- clipped = clipRect->intersect(r);
- if (!clipped) {
- clipRect->setEmpty();
- clipped = true;
- }
- break;
- case SkRegion::kUnion_Op:
- clipped = clipRect->unionWith(r);
- break;
- case SkRegion::kXOR_Op:
- break;
- case SkRegion::kReverseDifference_Op:
- break;
- case SkRegion::kReplace_Op:
- clipRect->set(r);
- clipped = true;
- break;
- }
-
- if (clipped) {
- flags |= Snapshot::kFlagClipSet;
- }
-
- return clipped;
- }
+ bool clipTransformed(const Rect& r, SkRegion::Op op = SkRegion::kIntersect_Op);
/**
* Sets the current clip.
*/
- void setClip(float left, float top, float right, float bottom) {
- clipRect->set(left, top, right, bottom);
- flags |= Snapshot::kFlagClipSet;
- }
+ void setClip(float left, float top, float right, float bottom);
- const Rect& getLocalClip() {
- mat4 inverse;
- inverse.loadInverse(*transform);
+ /**
+ * Returns the current clip in local coordinates. The clip rect is
+ * transformed by the inverse transform matrix.
+ */
+ const Rect& getLocalClip();
- mLocalClip.set(*clipRect);
- inverse.mapRect(mLocalClip);
+ /**
+ * Resets the clip to the specified rect.
+ */
+ void resetClip(float left, float top, float right, float bottom);
- return mLocalClip;
- }
+ /**
+ * Resets the current transform to a pure 3D translation.
+ */
+ void resetTransform(float x, float y, float z);
- void resetTransform(float x, float y, float z) {
- transform = &mTransformRoot;
- transform->loadTranslate(x, y, z);
- }
-
- void resetClip(float left, float top, float right, float bottom) {
- clipRect = &mClipRectRoot;
- clipRect->set(left, top, right, bottom);
- flags |= Snapshot::kFlagClipSet;
- }
-
- bool isIgnored() const {
- return invisible || empty;
- }
+ /**
+ * Indicates whether this snapshot should be ignored. A snapshot
+ * is typicalled ignored if its layer is invisible or empty.
+ */
+ bool isIgnored() const;
/**
* Dirty flags.
@@ -209,6 +132,8 @@
/**
* Only set when the flag kFlagIsLayer is set.
+ *
+ * This snapshot does not own the layer, this pointer must not be freed.
*/
Layer* layer;
@@ -249,17 +174,26 @@
/**
* Local transformation. Holds the current translation, scale and
* rotation values.
+ *
+ * This is a reference to a matrix owned by this snapshot or another
+ * snapshot. This pointer must not be freed. See ::mTransformRoot.
*/
mat4* transform;
/**
* Current clip region. The clip is stored in canvas-space coordinates,
* (screen-space coordinates in the regular case.)
+ *
+ * This is a reference to a rect owned by this snapshot or another
+ * snapshot. This pointer must not be freed. See ::mClipRectRoot.
*/
Rect* clipRect;
/**
* The ancestor layer's dirty region.
+ *
+ * This is a reference to a region owned by a layer. This pointer must
+ * not be freed.
*/
Region* region;
diff --git a/libs/rs/driver/rsdGL.cpp b/libs/rs/driver/rsdGL.cpp
index b53a68cf..7acc054 100644
--- a/libs/rs/driver/rsdGL.cpp
+++ b/libs/rs/driver/rsdGL.cpp
@@ -340,9 +340,9 @@
dc->gl.gl.OES_texture_npot = NULL != strstr((const char *)dc->gl.gl.extensions,
"GL_OES_texture_npot");
- dc->gl.gl.GL_IMG_texture_npot = NULL != strstr((const char *)dc->gl.gl.extensions,
+ dc->gl.gl.IMG_texture_npot = NULL != strstr((const char *)dc->gl.gl.extensions,
"GL_IMG_texture_npot");
- dc->gl.gl.GL_NV_texture_npot_2D_mipmap = NULL != strstr((const char *)dc->gl.gl.extensions,
+ dc->gl.gl.NV_texture_npot_2D_mipmap = NULL != strstr((const char *)dc->gl.gl.extensions,
"GL_NV_texture_npot_2D_mipmap");
dc->gl.gl.EXT_texture_max_aniso = 1.0f;
bool hasAniso = NULL != strstr((const char *)dc->gl.gl.extensions,
diff --git a/libs/rs/driver/rsdGL.h b/libs/rs/driver/rsdGL.h
index fc33885..51893c3 100644
--- a/libs/rs/driver/rsdGL.h
+++ b/libs/rs/driver/rsdGL.h
@@ -61,8 +61,8 @@
int32_t maxVertexTextureUnits;
bool OES_texture_npot;
- bool GL_IMG_texture_npot;
- bool GL_NV_texture_npot_2D_mipmap;
+ bool IMG_texture_npot;
+ bool NV_texture_npot_2D_mipmap;
float EXT_texture_max_aniso;
} gl;
diff --git a/libs/rs/driver/rsdRuntimeMath.cpp b/libs/rs/driver/rsdRuntimeMath.cpp
index e315539..753ef73 100644
--- a/libs/rs/driver/rsdRuntimeMath.cpp
+++ b/libs/rs/driver/rsdRuntimeMath.cpp
@@ -329,6 +329,16 @@
return prev;
}
+static uint32_t SC_AtomicUMin(volatile uint32_t *ptr, uint32_t value) {
+ uint32_t prev, status;
+ do {
+ prev = *ptr;
+ uint32_t n = rsMin(value, prev);
+ status = android_atomic_release_cas((int32_t) prev, (int32_t)n, (volatile int32_t*) ptr);
+ } while (CC_UNLIKELY(status != 0));
+ return prev;
+}
+
static int32_t SC_AtomicMin(volatile int32_t *ptr, int32_t value) {
int32_t prev, status;
do {
@@ -339,6 +349,16 @@
return prev;
}
+static uint32_t SC_AtomicUMax(volatile uint32_t *ptr, uint32_t value) {
+ uint32_t prev, status;
+ do {
+ prev = *ptr;
+ uint32_t n = rsMax(value, prev);
+ status = android_atomic_release_cas((int32_t) prev, (int32_t) n, (volatile int32_t*) ptr);
+ } while (CC_UNLIKELY(status != 0));
+ return prev;
+}
+
static int32_t SC_AtomicMax(volatile int32_t *ptr, int32_t value) {
int32_t prev, status;
do {
@@ -524,9 +544,9 @@
{ "_Z11rsAtomicXorPVii", (void *)&SC_AtomicXor, true },
{ "_Z11rsAtomicXorPVjj", (void *)&SC_AtomicXor, true },
{ "_Z11rsAtomicMinPVii", (void *)&SC_AtomicMin, true },
- { "_Z11rsAtomicMinPVjj", (void *)&SC_AtomicMin, true },
+ { "_Z11rsAtomicMinPVjj", (void *)&SC_AtomicUMin, true },
{ "_Z11rsAtomicMaxPVii", (void *)&SC_AtomicMax, true },
- { "_Z11rsAtomicMaxPVjj", (void *)&SC_AtomicMax, true },
+ { "_Z11rsAtomicMaxPVjj", (void *)&SC_AtomicUMax, true },
{ "_Z11rsAtomicCasPViii", (void *)&SC_AtomicCas, true },
{ "_Z11rsAtomicCasPVjjj", (void *)&SC_AtomicCas, true },
diff --git a/libs/rs/driver/rsdShader.cpp b/libs/rs/driver/rsdShader.cpp
index a10deb4..c70193ae 100644
--- a/libs/rs/driver/rsdShader.cpp
+++ b/libs/rs/driver/rsdShader.cpp
@@ -349,8 +349,8 @@
if (!dc->gl.gl.OES_texture_npot && tex->getType()->getIsNp2()) {
if (tex->getHasGraphicsMipmaps() &&
- (dc->gl.gl.GL_NV_texture_npot_2D_mipmap || dc->gl.gl.GL_IMG_texture_npot)) {
- if (dc->gl.gl.GL_NV_texture_npot_2D_mipmap) {
+ (dc->gl.gl.NV_texture_npot_2D_mipmap || dc->gl.gl.IMG_texture_npot)) {
+ if (dc->gl.gl.NV_texture_npot_2D_mipmap) {
RSD_CALL_GL(glTexParameteri, target, GL_TEXTURE_MIN_FILTER,
trans[s->mHal.state.minFilter]);
} else {
diff --git a/libs/rs/rs.spec b/libs/rs/rs.spec
index 20b1f52..6887b22 100644
--- a/libs/rs/rs.spec
+++ b/libs/rs/rs.spec
@@ -162,7 +162,7 @@
param uint32_t x
param uint32_t lod
param const void *data
- param uint32_t comp_offset
+ param size_t comp_offset
}
Allocation2DData {
@@ -183,7 +183,7 @@
param uint32_t lod
param RsAllocationCubemapFace face
param const void *data
- param uint32_t element_offset
+ param size_t element_offset
}
AllocationGenerateMipmaps {
diff --git a/libs/rs/rsAllocation.cpp b/libs/rs/rsAllocation.cpp
index 2773d5c..fd85b07 100644
--- a/libs/rs/rsAllocation.cpp
+++ b/libs/rs/rsAllocation.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2009 The Android Open Source Project
+ * Copyright (C) 2009-2012 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -71,11 +71,11 @@
}
void Allocation::data(Context *rsc, uint32_t xoff, uint32_t lod,
- uint32_t count, const void *data, uint32_t sizeBytes) {
- const uint32_t eSize = mHal.state.type->getElementSizeBytes();
+ uint32_t count, const void *data, size_t sizeBytes) {
+ const size_t eSize = mHal.state.type->getElementSizeBytes();
if ((count * eSize) != sizeBytes) {
- ALOGE("Allocation::subData called with mismatched size expected %i, got %i",
+ ALOGE("Allocation::subData called with mismatched size expected %zu, got %zu",
(count * eSize), sizeBytes);
mHal.state.type->dumpLOGV("type info");
return;
@@ -86,14 +86,14 @@
}
void Allocation::data(Context *rsc, uint32_t xoff, uint32_t yoff, uint32_t lod, RsAllocationCubemapFace face,
- uint32_t w, uint32_t h, const void *data, uint32_t sizeBytes) {
- const uint32_t eSize = mHal.state.elementSizeBytes;
- const uint32_t lineSize = eSize * w;
+ uint32_t w, uint32_t h, const void *data, size_t sizeBytes) {
+ const size_t eSize = mHal.state.elementSizeBytes;
+ const size_t lineSize = eSize * w;
//ALOGE("data2d %p, %i %i %i %i %i %i %p %i", this, xoff, yoff, lod, face, w, h, data, sizeBytes);
if ((lineSize * h) != sizeBytes) {
- ALOGE("Allocation size mismatch, expected %i, got %i", (lineSize * h), sizeBytes);
+ ALOGE("Allocation size mismatch, expected %zu, got %zu", (lineSize * h), sizeBytes);
rsAssert(!"Allocation::subData called with mismatched size");
return;
}
@@ -104,12 +104,12 @@
void Allocation::data(Context *rsc, uint32_t xoff, uint32_t yoff, uint32_t zoff,
uint32_t lod, RsAllocationCubemapFace face,
- uint32_t w, uint32_t h, uint32_t d, const void *data, uint32_t sizeBytes) {
+ uint32_t w, uint32_t h, uint32_t d, const void *data, size_t sizeBytes) {
}
void Allocation::elementData(Context *rsc, uint32_t x, const void *data,
- uint32_t cIdx, uint32_t sizeBytes) {
- uint32_t eSize = mHal.state.elementSizeBytes;
+ uint32_t cIdx, size_t sizeBytes) {
+ size_t eSize = mHal.state.elementSizeBytes;
if (cIdx >= mHal.state.type->getElement()->getFieldCount()) {
ALOGE("Error Allocation::subElementData component %i out of range.", cIdx);
@@ -124,8 +124,9 @@
}
const Element * e = mHal.state.type->getElement()->getField(cIdx);
- if (sizeBytes != e->getSizeBytes()) {
- ALOGE("Error Allocation::subElementData data size %i does not match field size %zu.", sizeBytes, e->getSizeBytes());
+ uint32_t elemArraySize = mHal.state.type->getElement()->getFieldArraySize(cIdx);
+ if (sizeBytes != e->getSizeBytes() * elemArraySize) {
+ ALOGE("Error Allocation::subElementData data size %zu does not match field size %zu.", sizeBytes, e->getSizeBytes());
rsc->setError(RS_ERROR_BAD_VALUE, "subElementData bad size.");
return;
}
@@ -135,8 +136,8 @@
}
void Allocation::elementData(Context *rsc, uint32_t x, uint32_t y,
- const void *data, uint32_t cIdx, uint32_t sizeBytes) {
- uint32_t eSize = mHal.state.elementSizeBytes;
+ const void *data, uint32_t cIdx, size_t sizeBytes) {
+ size_t eSize = mHal.state.elementSizeBytes;
if (x >= mHal.state.dimensionX) {
ALOGE("Error Allocation::subElementData X offset %i out of range.", x);
@@ -157,9 +158,9 @@
}
const Element * e = mHal.state.type->getElement()->getField(cIdx);
-
- if (sizeBytes != e->getSizeBytes()) {
- ALOGE("Error Allocation::subElementData data size %i does not match field size %zu.", sizeBytes, e->getSizeBytes());
+ uint32_t elemArraySize = mHal.state.type->getElement()->getFieldArraySize(cIdx);
+ if (sizeBytes != e->getSizeBytes() * elemArraySize) {
+ ALOGE("Error Allocation::subElementData data size %zu does not match field size %zu.", sizeBytes, e->getSizeBytes());
rsc->setError(RS_ERROR_BAD_VALUE, "subElementData bad size.");
return;
}
@@ -249,7 +250,7 @@
delete[] sizeUnpadded;
}
-void Allocation::unpackVec3Allocation(const void *data, uint32_t dataSize) {
+void Allocation::unpackVec3Allocation(const void *data, size_t dataSize) {
const uint8_t *src = (const uint8_t*)data;
uint8_t *dst = (uint8_t*)getPtr();
@@ -519,13 +520,13 @@
}
void rsi_Allocation2DElementData(Context *rsc, RsAllocation va, uint32_t x, uint32_t y, uint32_t lod, RsAllocationCubemapFace face,
- const void *data, size_t eoff, uint32_t sizeBytes) { // TODO: this seems wrong, eoff and sizeBytes may be swapped
+ const void *data, size_t sizeBytes, size_t eoff) {
Allocation *a = static_cast<Allocation *>(va);
a->elementData(rsc, x, y, data, eoff, sizeBytes);
}
void rsi_Allocation1DElementData(Context *rsc, RsAllocation va, uint32_t x, uint32_t lod,
- const void *data, size_t eoff, uint32_t sizeBytes) { // TODO: this seems wrong, eoff and sizeBytes may be swapped
+ const void *data, size_t sizeBytes, size_t eoff) {
Allocation *a = static_cast<Allocation *>(va);
a->elementData(rsc, x, data, eoff, sizeBytes);
}
diff --git a/libs/rs/rsAllocation.h b/libs/rs/rsAllocation.h
index 4ce863a..20201ca 100644
--- a/libs/rs/rsAllocation.h
+++ b/libs/rs/rsAllocation.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2009 The Android Open Source Project
+ * Copyright (C) 2009-2012 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -80,16 +80,16 @@
void resize1D(Context *rsc, uint32_t dimX);
void resize2D(Context *rsc, uint32_t dimX, uint32_t dimY);
- void data(Context *rsc, uint32_t xoff, uint32_t lod, uint32_t count, const void *data, uint32_t sizeBytes);
+ void data(Context *rsc, uint32_t xoff, uint32_t lod, uint32_t count, const void *data, size_t sizeBytes);
void data(Context *rsc, uint32_t xoff, uint32_t yoff, uint32_t lod, RsAllocationCubemapFace face,
- uint32_t w, uint32_t h, const void *data, uint32_t sizeBytes);
+ uint32_t w, uint32_t h, const void *data, size_t sizeBytes);
void data(Context *rsc, uint32_t xoff, uint32_t yoff, uint32_t zoff, uint32_t lod, RsAllocationCubemapFace face,
- uint32_t w, uint32_t h, uint32_t d, const void *data, uint32_t sizeBytes);
+ uint32_t w, uint32_t h, uint32_t d, const void *data, size_t sizeBytes);
void elementData(Context *rsc, uint32_t x,
- const void *data, uint32_t elementOff, uint32_t sizeBytes);
+ const void *data, uint32_t elementOff, size_t sizeBytes);
void elementData(Context *rsc, uint32_t x, uint32_t y,
- const void *data, uint32_t elementOff, uint32_t sizeBytes);
+ const void *data, uint32_t elementOff, size_t sizeBytes);
void read(void *data);
@@ -138,7 +138,7 @@
uint32_t getPackedSize() const;
static void writePackedData(const Type *type, uint8_t *dst, const uint8_t *src, bool dstPadded);
- void unpackVec3Allocation(const void *data, uint32_t dataSize);
+ void unpackVec3Allocation(const void *data, size_t dataSize);
void packVec3Allocation(OStream *stream) const;
};
diff --git a/libs/rs/rsScriptC.cpp b/libs/rs/rsScriptC.cpp
index afc8ba0..b4eb995 100644
--- a/libs/rs/rsScriptC.cpp
+++ b/libs/rs/rsScriptC.cpp
@@ -206,7 +206,6 @@
return false;
}
- rsAssert(bcWrapper.getHeaderVersion() == 0);
if (bcWrapper.getBCFileType() == bcinfo::BC_WRAPPER) {
sdkVersion = bcWrapper.getTargetAPI();
}
@@ -323,7 +322,7 @@
if (!s->runCompiler(rsc, resName, cacheDir, (uint8_t *)text, text_length)) {
// Error during compile, destroy s and return null.
- delete s;
+ ObjectBase::checkDelete(s);
return NULL;
}
diff --git a/libs/rs/rsThreadIO.cpp b/libs/rs/rsThreadIO.cpp
index 8ba1a0e..1917774 100644
--- a/libs/rs/rsThreadIO.cpp
+++ b/libs/rs/rsThreadIO.cpp
@@ -124,7 +124,6 @@
while (!mToCore.isEmpty() || waitForCommand) {
uint32_t cmdID = 0;
uint32_t cmdSize = 0;
- ret = true;
if (con->props.mLogTimes) {
con->timerSet(Context::RS_TIMER_IDLE);
}
@@ -136,11 +135,17 @@
delay = 0;
}
}
+
+ if (delay == 0 && timeToWait != 0 && mToCore.isEmpty()) {
+ break;
+ }
+
const void * data = mToCore.get(&cmdID, &cmdSize, delay);
if (!cmdSize) {
// exception or timeout occurred.
- return false;
+ break;
}
+ ret = true;
if (con->props.mLogTimes) {
con->timerSet(Context::RS_TIMER_INTERNAL);
}
diff --git a/libs/rs/scriptc/rs_atomic.rsh b/libs/rs/scriptc/rs_atomic.rsh
index 87c6c02..a455edd 100644
--- a/libs/rs/scriptc/rs_atomic.rsh
+++ b/libs/rs/scriptc/rs_atomic.rsh
@@ -242,7 +242,7 @@
* @return old value
*/
extern uint32_t __attribute__((overloadable))
- rsAtomicCas(volatile uint32_t* addr, int32_t compareValue, int32_t newValue);
+ rsAtomicCas(volatile uint32_t* addr, uint32_t compareValue, uint32_t newValue);
#endif //defined(RS_VERSION) && (RS_VERSION >= 14)
diff --git a/libs/utils/Android.mk b/libs/utils/Android.mk
index 544ab74..24cf504 100644
--- a/libs/utils/Android.mk
+++ b/libs/utils/Android.mk
@@ -98,7 +98,8 @@
LOCAL_C_INCLUDES += \
external/zlib \
- external/icu4c/common
+ external/icu4c/common \
+ bionic/libc/private
LOCAL_LDLIBS += -lpthread
@@ -114,7 +115,10 @@
ifeq ($(TARGET_OS),linux)
include $(CLEAR_VARS)
-LOCAL_C_INCLUDES += external/zlib external/icu4c/common
+LOCAL_C_INCLUDES += \
+ external/zlib \
+ external/icu4c/common \
+ bionic/libc/private
LOCAL_LDLIBS := -lrt -ldl -lpthread
LOCAL_MODULE := libutils
LOCAL_SRC_FILES := $(commonSources) BackupData.cpp BackupHelpers.cpp
diff --git a/libs/utils/ResourceTypes.cpp b/libs/utils/ResourceTypes.cpp
index 15b83bb..3fa562e 100644
--- a/libs/utils/ResourceTypes.cpp
+++ b/libs/utils/ResourceTypes.cpp
@@ -221,7 +221,7 @@
static bool assertIdmapHeader(const uint32_t* map, size_t sizeBytes)
{
if (sizeBytes < ResTable::IDMAP_HEADER_SIZE_BYTES) {
- ALOGW("idmap assertion failed: size=%d bytes\n", sizeBytes);
+ ALOGW("idmap assertion failed: size=%d bytes\n", (int)sizeBytes);
return false;
}
if (*map != htodl(IDMAP_MAGIC)) { // htodl: map data expected to be in correct endianess
@@ -250,7 +250,7 @@
return UNKNOWN_ERROR;
}
if (typeCount > size) {
- ALOGW("Resource ID map: number of types=%d exceeds size of map=%d\n", typeCount, size);
+ ALOGW("Resource ID map: number of types=%d exceeds size of map=%d\n", typeCount, (int)size);
return UNKNOWN_ERROR;
}
const uint32_t typeOffset = map[type];
@@ -260,7 +260,7 @@
}
if (typeOffset + 1 > size) {
ALOGW("Resource ID map: type offset=%d exceeds reasonable value, size of map=%d\n",
- typeOffset, size);
+ typeOffset, (int)size);
return UNKNOWN_ERROR;
}
const uint32_t entryCount = map[typeOffset];
@@ -271,7 +271,7 @@
}
const uint32_t index = typeOffset + 2 + entry - entryOffset;
if (index > size) {
- ALOGW("Resource ID map: entry index=%d exceeds size of map=%d\n", index, size);
+ ALOGW("Resource ID map: entry index=%d exceeds size of map=%d\n", index, (int)size);
*outValue = 0;
return NO_ERROR;
}
@@ -659,6 +659,16 @@
return NULL;
}
+const String8 ResStringPool::string8ObjectAt(size_t idx) const
+{
+ size_t len;
+ const char *str = (const char*)string8At(idx, &len);
+ if (str != NULL) {
+ return String8(str);
+ }
+ return String8(stringAt(idx, &len));
+}
+
const ResStringPool_span* ResStringPool::styleAt(const ResStringPool_ref& ref) const
{
return styleAt(ref.index);
@@ -738,12 +748,25 @@
return (mError == NO_ERROR) ? mHeader->stringCount : 0;
}
-#ifndef HAVE_ANDROID_OS
+size_t ResStringPool::styleCount() const
+{
+ return (mError == NO_ERROR) ? mHeader->styleCount : 0;
+}
+
+size_t ResStringPool::bytes() const
+{
+ return (mError == NO_ERROR) ? mHeader->header.size : 0;
+}
+
+bool ResStringPool::isSorted() const
+{
+ return (mHeader->flags&ResStringPool_header::SORTED_FLAG)!=0;
+}
+
bool ResStringPool::isUTF8() const
{
return (mHeader->flags&ResStringPool_header::UTF8_FLAG)!=0;
}
-#endif
// --------------------------------------------------------------------
// --------------------------------------------------------------------
@@ -1367,6 +1390,873 @@
// --------------------------------------------------------------------
// --------------------------------------------------------------------
+void ResTable_config::copyFromDeviceNoSwap(const ResTable_config& o) {
+ const size_t size = dtohl(o.size);
+ if (size >= sizeof(ResTable_config)) {
+ *this = o;
+ } else {
+ memcpy(this, &o, size);
+ memset(((uint8_t*)this)+size, 0, sizeof(ResTable_config)-size);
+ }
+}
+
+void ResTable_config::copyFromDtoH(const ResTable_config& o) {
+ copyFromDeviceNoSwap(o);
+ size = sizeof(ResTable_config);
+ mcc = dtohs(mcc);
+ mnc = dtohs(mnc);
+ density = dtohs(density);
+ screenWidth = dtohs(screenWidth);
+ screenHeight = dtohs(screenHeight);
+ sdkVersion = dtohs(sdkVersion);
+ minorVersion = dtohs(minorVersion);
+ smallestScreenWidthDp = dtohs(smallestScreenWidthDp);
+ screenWidthDp = dtohs(screenWidthDp);
+ screenHeightDp = dtohs(screenHeightDp);
+}
+
+void ResTable_config::swapHtoD() {
+ size = htodl(size);
+ mcc = htods(mcc);
+ mnc = htods(mnc);
+ density = htods(density);
+ screenWidth = htods(screenWidth);
+ screenHeight = htods(screenHeight);
+ sdkVersion = htods(sdkVersion);
+ minorVersion = htods(minorVersion);
+ smallestScreenWidthDp = htods(smallestScreenWidthDp);
+ screenWidthDp = htods(screenWidthDp);
+ screenHeightDp = htods(screenHeightDp);
+}
+
+int ResTable_config::compare(const ResTable_config& o) const {
+ int32_t diff = (int32_t)(imsi - o.imsi);
+ if (diff != 0) return diff;
+ diff = (int32_t)(locale - o.locale);
+ if (diff != 0) return diff;
+ diff = (int32_t)(screenType - o.screenType);
+ if (diff != 0) return diff;
+ diff = (int32_t)(input - o.input);
+ if (diff != 0) return diff;
+ diff = (int32_t)(screenSize - o.screenSize);
+ if (diff != 0) return diff;
+ diff = (int32_t)(version - o.version);
+ if (diff != 0) return diff;
+ diff = (int32_t)(screenLayout - o.screenLayout);
+ if (diff != 0) return diff;
+ diff = (int32_t)(uiMode - o.uiMode);
+ if (diff != 0) return diff;
+ diff = (int32_t)(smallestScreenWidthDp - o.smallestScreenWidthDp);
+ if (diff != 0) return diff;
+ diff = (int32_t)(screenSizeDp - o.screenSizeDp);
+ return (int)diff;
+}
+
+int ResTable_config::compareLogical(const ResTable_config& o) const {
+ if (mcc != o.mcc) {
+ return mcc < o.mcc ? -1 : 1;
+ }
+ if (mnc != o.mnc) {
+ return mnc < o.mnc ? -1 : 1;
+ }
+ if (language[0] != o.language[0]) {
+ return language[0] < o.language[0] ? -1 : 1;
+ }
+ if (language[1] != o.language[1]) {
+ return language[1] < o.language[1] ? -1 : 1;
+ }
+ if (country[0] != o.country[0]) {
+ return country[0] < o.country[0] ? -1 : 1;
+ }
+ if (country[1] != o.country[1]) {
+ return country[1] < o.country[1] ? -1 : 1;
+ }
+ if (smallestScreenWidthDp != o.smallestScreenWidthDp) {
+ return smallestScreenWidthDp < o.smallestScreenWidthDp ? -1 : 1;
+ }
+ if (screenWidthDp != o.screenWidthDp) {
+ return screenWidthDp < o.screenWidthDp ? -1 : 1;
+ }
+ if (screenHeightDp != o.screenHeightDp) {
+ return screenHeightDp < o.screenHeightDp ? -1 : 1;
+ }
+ if (screenWidth != o.screenWidth) {
+ return screenWidth < o.screenWidth ? -1 : 1;
+ }
+ if (screenHeight != o.screenHeight) {
+ return screenHeight < o.screenHeight ? -1 : 1;
+ }
+ if (density != o.density) {
+ return density < o.density ? -1 : 1;
+ }
+ if (orientation != o.orientation) {
+ return orientation < o.orientation ? -1 : 1;
+ }
+ if (touchscreen != o.touchscreen) {
+ return touchscreen < o.touchscreen ? -1 : 1;
+ }
+ if (input != o.input) {
+ return input < o.input ? -1 : 1;
+ }
+ if (screenLayout != o.screenLayout) {
+ return screenLayout < o.screenLayout ? -1 : 1;
+ }
+ if (uiMode != o.uiMode) {
+ return uiMode < o.uiMode ? -1 : 1;
+ }
+ if (version != o.version) {
+ return version < o.version ? -1 : 1;
+ }
+ return 0;
+}
+
+int ResTable_config::diff(const ResTable_config& o) const {
+ int diffs = 0;
+ if (mcc != o.mcc) diffs |= CONFIG_MCC;
+ if (mnc != o.mnc) diffs |= CONFIG_MNC;
+ if (locale != o.locale) diffs |= CONFIG_LOCALE;
+ if (orientation != o.orientation) diffs |= CONFIG_ORIENTATION;
+ if (density != o.density) diffs |= CONFIG_DENSITY;
+ if (touchscreen != o.touchscreen) diffs |= CONFIG_TOUCHSCREEN;
+ if (((inputFlags^o.inputFlags)&(MASK_KEYSHIDDEN|MASK_NAVHIDDEN)) != 0)
+ diffs |= CONFIG_KEYBOARD_HIDDEN;
+ if (keyboard != o.keyboard) diffs |= CONFIG_KEYBOARD;
+ if (navigation != o.navigation) diffs |= CONFIG_NAVIGATION;
+ if (screenSize != o.screenSize) diffs |= CONFIG_SCREEN_SIZE;
+ if (version != o.version) diffs |= CONFIG_VERSION;
+ if (screenLayout != o.screenLayout) diffs |= CONFIG_SCREEN_LAYOUT;
+ if (uiMode != o.uiMode) diffs |= CONFIG_UI_MODE;
+ if (smallestScreenWidthDp != o.smallestScreenWidthDp) diffs |= CONFIG_SMALLEST_SCREEN_SIZE;
+ if (screenSizeDp != o.screenSizeDp) diffs |= CONFIG_SCREEN_SIZE;
+ return diffs;
+}
+
+bool ResTable_config::isMoreSpecificThan(const ResTable_config& o) const {
+ // The order of the following tests defines the importance of one
+ // configuration parameter over another. Those tests first are more
+ // important, trumping any values in those following them.
+ if (imsi || o.imsi) {
+ if (mcc != o.mcc) {
+ if (!mcc) return false;
+ if (!o.mcc) return true;
+ }
+
+ if (mnc != o.mnc) {
+ if (!mnc) return false;
+ if (!o.mnc) return true;
+ }
+ }
+
+ if (locale || o.locale) {
+ if (language[0] != o.language[0]) {
+ if (!language[0]) return false;
+ if (!o.language[0]) return true;
+ }
+
+ if (country[0] != o.country[0]) {
+ if (!country[0]) return false;
+ if (!o.country[0]) return true;
+ }
+ }
+
+ if (smallestScreenWidthDp || o.smallestScreenWidthDp) {
+ if (smallestScreenWidthDp != o.smallestScreenWidthDp) {
+ if (!smallestScreenWidthDp) return false;
+ if (!o.smallestScreenWidthDp) return true;
+ }
+ }
+
+ if (screenSizeDp || o.screenSizeDp) {
+ if (screenWidthDp != o.screenWidthDp) {
+ if (!screenWidthDp) return false;
+ if (!o.screenWidthDp) return true;
+ }
+
+ if (screenHeightDp != o.screenHeightDp) {
+ if (!screenHeightDp) return false;
+ if (!o.screenHeightDp) return true;
+ }
+ }
+
+ if (screenLayout || o.screenLayout) {
+ if (((screenLayout^o.screenLayout) & MASK_SCREENSIZE) != 0) {
+ if (!(screenLayout & MASK_SCREENSIZE)) return false;
+ if (!(o.screenLayout & MASK_SCREENSIZE)) return true;
+ }
+ if (((screenLayout^o.screenLayout) & MASK_SCREENLONG) != 0) {
+ if (!(screenLayout & MASK_SCREENLONG)) return false;
+ if (!(o.screenLayout & MASK_SCREENLONG)) return true;
+ }
+ }
+
+ if (orientation != o.orientation) {
+ if (!orientation) return false;
+ if (!o.orientation) return true;
+ }
+
+ if (uiMode || o.uiMode) {
+ if (((uiMode^o.uiMode) & MASK_UI_MODE_TYPE) != 0) {
+ if (!(uiMode & MASK_UI_MODE_TYPE)) return false;
+ if (!(o.uiMode & MASK_UI_MODE_TYPE)) return true;
+ }
+ if (((uiMode^o.uiMode) & MASK_UI_MODE_NIGHT) != 0) {
+ if (!(uiMode & MASK_UI_MODE_NIGHT)) return false;
+ if (!(o.uiMode & MASK_UI_MODE_NIGHT)) return true;
+ }
+ }
+
+ // density is never 'more specific'
+ // as the default just equals 160
+
+ if (touchscreen != o.touchscreen) {
+ if (!touchscreen) return false;
+ if (!o.touchscreen) return true;
+ }
+
+ if (input || o.input) {
+ if (((inputFlags^o.inputFlags) & MASK_KEYSHIDDEN) != 0) {
+ if (!(inputFlags & MASK_KEYSHIDDEN)) return false;
+ if (!(o.inputFlags & MASK_KEYSHIDDEN)) return true;
+ }
+
+ if (((inputFlags^o.inputFlags) & MASK_NAVHIDDEN) != 0) {
+ if (!(inputFlags & MASK_NAVHIDDEN)) return false;
+ if (!(o.inputFlags & MASK_NAVHIDDEN)) return true;
+ }
+
+ if (keyboard != o.keyboard) {
+ if (!keyboard) return false;
+ if (!o.keyboard) return true;
+ }
+
+ if (navigation != o.navigation) {
+ if (!navigation) return false;
+ if (!o.navigation) return true;
+ }
+ }
+
+ if (screenSize || o.screenSize) {
+ if (screenWidth != o.screenWidth) {
+ if (!screenWidth) return false;
+ if (!o.screenWidth) return true;
+ }
+
+ if (screenHeight != o.screenHeight) {
+ if (!screenHeight) return false;
+ if (!o.screenHeight) return true;
+ }
+ }
+
+ if (version || o.version) {
+ if (sdkVersion != o.sdkVersion) {
+ if (!sdkVersion) return false;
+ if (!o.sdkVersion) return true;
+ }
+
+ if (minorVersion != o.minorVersion) {
+ if (!minorVersion) return false;
+ if (!o.minorVersion) return true;
+ }
+ }
+ return false;
+}
+
+bool ResTable_config::isBetterThan(const ResTable_config& o,
+ const ResTable_config* requested) const {
+ if (requested) {
+ if (imsi || o.imsi) {
+ if ((mcc != o.mcc) && requested->mcc) {
+ return (mcc);
+ }
+
+ if ((mnc != o.mnc) && requested->mnc) {
+ return (mnc);
+ }
+ }
+
+ if (locale || o.locale) {
+ if ((language[0] != o.language[0]) && requested->language[0]) {
+ return (language[0]);
+ }
+
+ if ((country[0] != o.country[0]) && requested->country[0]) {
+ return (country[0]);
+ }
+ }
+
+ if (smallestScreenWidthDp || o.smallestScreenWidthDp) {
+ // The configuration closest to the actual size is best.
+ // We assume that larger configs have already been filtered
+ // out at this point. That means we just want the largest one.
+ return smallestScreenWidthDp >= o.smallestScreenWidthDp;
+ }
+
+ if (screenSizeDp || o.screenSizeDp) {
+ // "Better" is based on the sum of the difference between both
+ // width and height from the requested dimensions. We are
+ // assuming the invalid configs (with smaller dimens) have
+ // already been filtered. Note that if a particular dimension
+ // is unspecified, we will end up with a large value (the
+ // difference between 0 and the requested dimension), which is
+ // good since we will prefer a config that has specified a
+ // dimension value.
+ int myDelta = 0, otherDelta = 0;
+ if (requested->screenWidthDp) {
+ myDelta += requested->screenWidthDp - screenWidthDp;
+ otherDelta += requested->screenWidthDp - o.screenWidthDp;
+ }
+ if (requested->screenHeightDp) {
+ myDelta += requested->screenHeightDp - screenHeightDp;
+ otherDelta += requested->screenHeightDp - o.screenHeightDp;
+ }
+ //ALOGI("Comparing this %dx%d to other %dx%d in %dx%d: myDelta=%d otherDelta=%d",
+ // screenWidthDp, screenHeightDp, o.screenWidthDp, o.screenHeightDp,
+ // requested->screenWidthDp, requested->screenHeightDp, myDelta, otherDelta);
+ return (myDelta <= otherDelta);
+ }
+
+ if (screenLayout || o.screenLayout) {
+ if (((screenLayout^o.screenLayout) & MASK_SCREENSIZE) != 0
+ && (requested->screenLayout & MASK_SCREENSIZE)) {
+ // A little backwards compatibility here: undefined is
+ // considered equivalent to normal. But only if the
+ // requested size is at least normal; otherwise, small
+ // is better than the default.
+ int mySL = (screenLayout & MASK_SCREENSIZE);
+ int oSL = (o.screenLayout & MASK_SCREENSIZE);
+ int fixedMySL = mySL;
+ int fixedOSL = oSL;
+ if ((requested->screenLayout & MASK_SCREENSIZE) >= SCREENSIZE_NORMAL) {
+ if (fixedMySL == 0) fixedMySL = SCREENSIZE_NORMAL;
+ if (fixedOSL == 0) fixedOSL = SCREENSIZE_NORMAL;
+ }
+ // For screen size, the best match is the one that is
+ // closest to the requested screen size, but not over
+ // (the not over part is dealt with in match() below).
+ if (fixedMySL == fixedOSL) {
+ // If the two are the same, but 'this' is actually
+ // undefined, then the other is really a better match.
+ if (mySL == 0) return false;
+ return true;
+ }
+ return fixedMySL >= fixedOSL;
+ }
+ if (((screenLayout^o.screenLayout) & MASK_SCREENLONG) != 0
+ && (requested->screenLayout & MASK_SCREENLONG)) {
+ return (screenLayout & MASK_SCREENLONG);
+ }
+ }
+
+ if ((orientation != o.orientation) && requested->orientation) {
+ return (orientation);
+ }
+
+ if (uiMode || o.uiMode) {
+ if (((uiMode^o.uiMode) & MASK_UI_MODE_TYPE) != 0
+ && (requested->uiMode & MASK_UI_MODE_TYPE)) {
+ return (uiMode & MASK_UI_MODE_TYPE);
+ }
+ if (((uiMode^o.uiMode) & MASK_UI_MODE_NIGHT) != 0
+ && (requested->uiMode & MASK_UI_MODE_NIGHT)) {
+ return (uiMode & MASK_UI_MODE_NIGHT);
+ }
+ }
+
+ if (screenType || o.screenType) {
+ if (density != o.density) {
+ // density is tough. Any density is potentially useful
+ // because the system will scale it. Scaling down
+ // is generally better than scaling up.
+ // Default density counts as 160dpi (the system default)
+ // TODO - remove 160 constants
+ int h = (density?density:160);
+ int l = (o.density?o.density:160);
+ bool bImBigger = true;
+ if (l > h) {
+ int t = h;
+ h = l;
+ l = t;
+ bImBigger = false;
+ }
+
+ int reqValue = (requested->density?requested->density:160);
+ if (reqValue >= h) {
+ // requested value higher than both l and h, give h
+ return bImBigger;
+ }
+ if (l >= reqValue) {
+ // requested value lower than both l and h, give l
+ return !bImBigger;
+ }
+ // saying that scaling down is 2x better than up
+ if (((2 * l) - reqValue) * h > reqValue * reqValue) {
+ return !bImBigger;
+ } else {
+ return bImBigger;
+ }
+ }
+
+ if ((touchscreen != o.touchscreen) && requested->touchscreen) {
+ return (touchscreen);
+ }
+ }
+
+ if (input || o.input) {
+ const int keysHidden = inputFlags & MASK_KEYSHIDDEN;
+ const int oKeysHidden = o.inputFlags & MASK_KEYSHIDDEN;
+ if (keysHidden != oKeysHidden) {
+ const int reqKeysHidden =
+ requested->inputFlags & MASK_KEYSHIDDEN;
+ if (reqKeysHidden) {
+
+ if (!keysHidden) return false;
+ if (!oKeysHidden) return true;
+ // For compatibility, we count KEYSHIDDEN_NO as being
+ // the same as KEYSHIDDEN_SOFT. Here we disambiguate
+ // these by making an exact match more specific.
+ if (reqKeysHidden == keysHidden) return true;
+ if (reqKeysHidden == oKeysHidden) return false;
+ }
+ }
+
+ const int navHidden = inputFlags & MASK_NAVHIDDEN;
+ const int oNavHidden = o.inputFlags & MASK_NAVHIDDEN;
+ if (navHidden != oNavHidden) {
+ const int reqNavHidden =
+ requested->inputFlags & MASK_NAVHIDDEN;
+ if (reqNavHidden) {
+
+ if (!navHidden) return false;
+ if (!oNavHidden) return true;
+ }
+ }
+
+ if ((keyboard != o.keyboard) && requested->keyboard) {
+ return (keyboard);
+ }
+
+ if ((navigation != o.navigation) && requested->navigation) {
+ return (navigation);
+ }
+ }
+
+ if (screenSize || o.screenSize) {
+ // "Better" is based on the sum of the difference between both
+ // width and height from the requested dimensions. We are
+ // assuming the invalid configs (with smaller sizes) have
+ // already been filtered. Note that if a particular dimension
+ // is unspecified, we will end up with a large value (the
+ // difference between 0 and the requested dimension), which is
+ // good since we will prefer a config that has specified a
+ // size value.
+ int myDelta = 0, otherDelta = 0;
+ if (requested->screenWidth) {
+ myDelta += requested->screenWidth - screenWidth;
+ otherDelta += requested->screenWidth - o.screenWidth;
+ }
+ if (requested->screenHeight) {
+ myDelta += requested->screenHeight - screenHeight;
+ otherDelta += requested->screenHeight - o.screenHeight;
+ }
+ return (myDelta <= otherDelta);
+ }
+
+ if (version || o.version) {
+ if ((sdkVersion != o.sdkVersion) && requested->sdkVersion) {
+ return (sdkVersion > o.sdkVersion);
+ }
+
+ if ((minorVersion != o.minorVersion) &&
+ requested->minorVersion) {
+ return (minorVersion);
+ }
+ }
+
+ return false;
+ }
+ return isMoreSpecificThan(o);
+}
+
+bool ResTable_config::match(const ResTable_config& settings) const {
+ if (imsi != 0) {
+ if (mcc != 0 && mcc != settings.mcc) {
+ return false;
+ }
+ if (mnc != 0 && mnc != settings.mnc) {
+ return false;
+ }
+ }
+ if (locale != 0) {
+ if (language[0] != 0
+ && (language[0] != settings.language[0]
+ || language[1] != settings.language[1])) {
+ return false;
+ }
+ if (country[0] != 0
+ && (country[0] != settings.country[0]
+ || country[1] != settings.country[1])) {
+ return false;
+ }
+ }
+ if (screenConfig != 0) {
+ const int screenSize = screenLayout&MASK_SCREENSIZE;
+ const int setScreenSize = settings.screenLayout&MASK_SCREENSIZE;
+ // Any screen sizes for larger screens than the setting do not
+ // match.
+ if (screenSize != 0 && screenSize > setScreenSize) {
+ return false;
+ }
+
+ const int screenLong = screenLayout&MASK_SCREENLONG;
+ const int setScreenLong = settings.screenLayout&MASK_SCREENLONG;
+ if (screenLong != 0 && screenLong != setScreenLong) {
+ return false;
+ }
+
+ const int uiModeType = uiMode&MASK_UI_MODE_TYPE;
+ const int setUiModeType = settings.uiMode&MASK_UI_MODE_TYPE;
+ if (uiModeType != 0 && uiModeType != setUiModeType) {
+ return false;
+ }
+
+ const int uiModeNight = uiMode&MASK_UI_MODE_NIGHT;
+ const int setUiModeNight = settings.uiMode&MASK_UI_MODE_NIGHT;
+ if (uiModeNight != 0 && uiModeNight != setUiModeNight) {
+ return false;
+ }
+
+ if (smallestScreenWidthDp != 0
+ && smallestScreenWidthDp > settings.smallestScreenWidthDp) {
+ return false;
+ }
+ }
+ if (screenSizeDp != 0) {
+ if (screenWidthDp != 0 && screenWidthDp > settings.screenWidthDp) {
+ //ALOGI("Filtering out width %d in requested %d", screenWidthDp, settings.screenWidthDp);
+ return false;
+ }
+ if (screenHeightDp != 0 && screenHeightDp > settings.screenHeightDp) {
+ //ALOGI("Filtering out height %d in requested %d", screenHeightDp, settings.screenHeightDp);
+ return false;
+ }
+ }
+ if (screenType != 0) {
+ if (orientation != 0 && orientation != settings.orientation) {
+ return false;
+ }
+ // density always matches - we can scale it. See isBetterThan
+ if (touchscreen != 0 && touchscreen != settings.touchscreen) {
+ return false;
+ }
+ }
+ if (input != 0) {
+ const int keysHidden = inputFlags&MASK_KEYSHIDDEN;
+ const int setKeysHidden = settings.inputFlags&MASK_KEYSHIDDEN;
+ if (keysHidden != 0 && keysHidden != setKeysHidden) {
+ // For compatibility, we count a request for KEYSHIDDEN_NO as also
+ // matching the more recent KEYSHIDDEN_SOFT. Basically
+ // KEYSHIDDEN_NO means there is some kind of keyboard available.
+ //ALOGI("Matching keysHidden: have=%d, config=%d\n", keysHidden, setKeysHidden);
+ if (keysHidden != KEYSHIDDEN_NO || setKeysHidden != KEYSHIDDEN_SOFT) {
+ //ALOGI("No match!");
+ return false;
+ }
+ }
+ const int navHidden = inputFlags&MASK_NAVHIDDEN;
+ const int setNavHidden = settings.inputFlags&MASK_NAVHIDDEN;
+ if (navHidden != 0 && navHidden != setNavHidden) {
+ return false;
+ }
+ if (keyboard != 0 && keyboard != settings.keyboard) {
+ return false;
+ }
+ if (navigation != 0 && navigation != settings.navigation) {
+ return false;
+ }
+ }
+ if (screenSize != 0) {
+ if (screenWidth != 0 && screenWidth > settings.screenWidth) {
+ return false;
+ }
+ if (screenHeight != 0 && screenHeight > settings.screenHeight) {
+ return false;
+ }
+ }
+ if (version != 0) {
+ if (sdkVersion != 0 && sdkVersion > settings.sdkVersion) {
+ return false;
+ }
+ if (minorVersion != 0 && minorVersion != settings.minorVersion) {
+ return false;
+ }
+ }
+ return true;
+}
+
+void ResTable_config::getLocale(char str[6]) const {
+ memset(str, 0, 6);
+ if (language[0]) {
+ str[0] = language[0];
+ str[1] = language[1];
+ if (country[0]) {
+ str[2] = '_';
+ str[3] = country[0];
+ str[4] = country[1];
+ }
+ }
+}
+
+String8 ResTable_config::toString() const {
+ String8 res;
+
+ if (mcc != 0) {
+ if (res.size() > 0) res.append("-");
+ res.appendFormat("%dmcc", dtohs(mcc));
+ }
+ if (mnc != 0) {
+ if (res.size() > 0) res.append("-");
+ res.appendFormat("%dmnc", dtohs(mnc));
+ }
+ if (language[0] != 0) {
+ if (res.size() > 0) res.append("-");
+ res.append(language, 2);
+ }
+ if (country[0] != 0) {
+ if (res.size() > 0) res.append("-");
+ res.append(country, 2);
+ }
+ if (smallestScreenWidthDp != 0) {
+ if (res.size() > 0) res.append("-");
+ res.appendFormat("sw%ddp", dtohs(smallestScreenWidthDp));
+ }
+ if (screenWidthDp != 0) {
+ if (res.size() > 0) res.append("-");
+ res.appendFormat("w%ddp", dtohs(screenWidthDp));
+ }
+ if (screenHeightDp != 0) {
+ if (res.size() > 0) res.append("-");
+ res.appendFormat("h%ddp", dtohs(screenHeightDp));
+ }
+ if ((screenLayout&MASK_SCREENSIZE) != SCREENSIZE_ANY) {
+ if (res.size() > 0) res.append("-");
+ switch (screenLayout&ResTable_config::MASK_SCREENSIZE) {
+ case ResTable_config::SCREENSIZE_SMALL:
+ res.append("small");
+ break;
+ case ResTable_config::SCREENSIZE_NORMAL:
+ res.append("normal");
+ break;
+ case ResTable_config::SCREENSIZE_LARGE:
+ res.append("large");
+ break;
+ case ResTable_config::SCREENSIZE_XLARGE:
+ res.append("xlarge");
+ break;
+ default:
+ res.appendFormat("screenLayoutSize=%d",
+ dtohs(screenLayout&ResTable_config::MASK_SCREENSIZE));
+ break;
+ }
+ }
+ if ((screenLayout&MASK_SCREENLONG) != 0) {
+ if (res.size() > 0) res.append("-");
+ switch (screenLayout&ResTable_config::MASK_SCREENLONG) {
+ case ResTable_config::SCREENLONG_NO:
+ res.append("notlong");
+ break;
+ case ResTable_config::SCREENLONG_YES:
+ res.append("long");
+ break;
+ default:
+ res.appendFormat("screenLayoutLong=%d",
+ dtohs(screenLayout&ResTable_config::MASK_SCREENLONG));
+ break;
+ }
+ }
+ if (orientation != ORIENTATION_ANY) {
+ if (res.size() > 0) res.append("-");
+ switch (orientation) {
+ case ResTable_config::ORIENTATION_PORT:
+ res.append("port");
+ break;
+ case ResTable_config::ORIENTATION_LAND:
+ res.append("land");
+ break;
+ case ResTable_config::ORIENTATION_SQUARE:
+ res.append("square");
+ break;
+ default:
+ res.appendFormat("orientation=%d", dtohs(orientation));
+ break;
+ }
+ }
+ if ((uiMode&MASK_UI_MODE_TYPE) != UI_MODE_TYPE_ANY) {
+ if (res.size() > 0) res.append("-");
+ switch (uiMode&ResTable_config::MASK_UI_MODE_TYPE) {
+ case ResTable_config::UI_MODE_TYPE_DESK:
+ res.append("desk");
+ break;
+ case ResTable_config::UI_MODE_TYPE_CAR:
+ res.append("car");
+ break;
+ case ResTable_config::UI_MODE_TYPE_TELEVISION:
+ res.append("television");
+ break;
+ case ResTable_config::UI_MODE_TYPE_APPLIANCE:
+ res.append("appliance");
+ break;
+ default:
+ res.appendFormat("uiModeType=%d",
+ dtohs(screenLayout&ResTable_config::MASK_UI_MODE_TYPE));
+ break;
+ }
+ }
+ if ((uiMode&MASK_UI_MODE_NIGHT) != 0) {
+ if (res.size() > 0) res.append("-");
+ switch (uiMode&ResTable_config::MASK_UI_MODE_NIGHT) {
+ case ResTable_config::UI_MODE_NIGHT_NO:
+ res.append("notnight");
+ break;
+ case ResTable_config::UI_MODE_NIGHT_YES:
+ res.append("night");
+ break;
+ default:
+ res.appendFormat("uiModeNight=%d",
+ dtohs(uiMode&MASK_UI_MODE_NIGHT));
+ break;
+ }
+ }
+ if (density != DENSITY_DEFAULT) {
+ if (res.size() > 0) res.append("-");
+ switch (density) {
+ case ResTable_config::DENSITY_LOW:
+ res.append("ldpi");
+ break;
+ case ResTable_config::DENSITY_MEDIUM:
+ res.append("mdpi");
+ break;
+ case ResTable_config::DENSITY_TV:
+ res.append("tvdpi");
+ break;
+ case ResTable_config::DENSITY_HIGH:
+ res.append("hdpi");
+ break;
+ case ResTable_config::DENSITY_XHIGH:
+ res.append("xhdpi");
+ break;
+ case ResTable_config::DENSITY_XXHIGH:
+ res.append("xxhdpi");
+ break;
+ case ResTable_config::DENSITY_NONE:
+ res.append("nodpi");
+ break;
+ default:
+ res.appendFormat("density=%d", dtohs(density));
+ break;
+ }
+ }
+ if (touchscreen != TOUCHSCREEN_ANY) {
+ if (res.size() > 0) res.append("-");
+ switch (touchscreen) {
+ case ResTable_config::TOUCHSCREEN_NOTOUCH:
+ res.append("notouch");
+ break;
+ case ResTable_config::TOUCHSCREEN_FINGER:
+ res.append("finger");
+ break;
+ case ResTable_config::TOUCHSCREEN_STYLUS:
+ res.append("stylus");
+ break;
+ default:
+ res.appendFormat("touchscreen=%d", dtohs(touchscreen));
+ break;
+ }
+ }
+ if (keyboard != KEYBOARD_ANY) {
+ if (res.size() > 0) res.append("-");
+ switch (keyboard) {
+ case ResTable_config::KEYBOARD_NOKEYS:
+ res.append("nokeys");
+ break;
+ case ResTable_config::KEYBOARD_QWERTY:
+ res.append("qwerty");
+ break;
+ case ResTable_config::KEYBOARD_12KEY:
+ res.append("12key");
+ break;
+ default:
+ res.appendFormat("keyboard=%d", dtohs(keyboard));
+ break;
+ }
+ }
+ if ((inputFlags&MASK_KEYSHIDDEN) != 0) {
+ if (res.size() > 0) res.append("-");
+ switch (inputFlags&MASK_KEYSHIDDEN) {
+ case ResTable_config::KEYSHIDDEN_NO:
+ res.append("keysexposed");
+ break;
+ case ResTable_config::KEYSHIDDEN_YES:
+ res.append("keyshidden");
+ break;
+ case ResTable_config::KEYSHIDDEN_SOFT:
+ res.append("keyssoft");
+ break;
+ }
+ }
+ if (navigation != NAVIGATION_ANY) {
+ if (res.size() > 0) res.append("-");
+ switch (navigation) {
+ case ResTable_config::NAVIGATION_NONAV:
+ res.append("nonav");
+ break;
+ case ResTable_config::NAVIGATION_DPAD:
+ res.append("dpad");
+ break;
+ case ResTable_config::NAVIGATION_TRACKBALL:
+ res.append("trackball");
+ break;
+ case ResTable_config::NAVIGATION_WHEEL:
+ res.append("wheel");
+ break;
+ default:
+ res.appendFormat("navigation=%d", dtohs(navigation));
+ break;
+ }
+ }
+ if ((inputFlags&MASK_NAVHIDDEN) != 0) {
+ if (res.size() > 0) res.append("-");
+ switch (inputFlags&MASK_NAVHIDDEN) {
+ case ResTable_config::NAVHIDDEN_NO:
+ res.append("navsexposed");
+ break;
+ case ResTable_config::NAVHIDDEN_YES:
+ res.append("navhidden");
+ break;
+ default:
+ res.appendFormat("inputFlagsNavHidden=%d",
+ dtohs(inputFlags&MASK_NAVHIDDEN));
+ break;
+ }
+ }
+ if (screenSize != 0) {
+ if (res.size() > 0) res.append("-");
+ res.appendFormat("%dx%d", dtohs(screenWidth), dtohs(screenHeight));
+ }
+ if (version != 0) {
+ if (res.size() > 0) res.append("-");
+ res.appendFormat("v%d", dtohs(sdkVersion));
+ if (minorVersion != 0) {
+ res.appendFormat(".%d", dtohs(minorVersion));
+ }
+ }
+
+ return res;
+}
+
+// --------------------------------------------------------------------
+// --------------------------------------------------------------------
+// --------------------------------------------------------------------
+
struct ResTable::Header
{
Header(ResTable* _owner) : owner(_owner), ownedData(NULL), header(NULL),
@@ -3953,43 +4843,9 @@
ResTable_config thisConfig;
thisConfig.copyFromDtoH(thisType->config);
- TABLE_GETENTRY(LOGI("Match entry 0x%x in type 0x%x (sz 0x%x): imsi:%d/%d=%d/%d "
- "lang:%c%c=%c%c cnt:%c%c=%c%c orien:%d=%d touch:%d=%d "
- "density:%d=%d key:%d=%d inp:%d=%d nav:%d=%d w:%d=%d h:%d=%d "
- "swdp:%d=%d wdp:%d=%d hdp:%d=%d\n",
+ TABLE_GETENTRY(LOGI("Match entry 0x%x in type 0x%x (sz 0x%x): %s\n",
entryIndex, typeIndex+1, dtohl(thisType->config.size),
- thisConfig.mcc, thisConfig.mnc,
- config ? config->mcc : 0, config ? config->mnc : 0,
- thisConfig.language[0] ? thisConfig.language[0] : '-',
- thisConfig.language[1] ? thisConfig.language[1] : '-',
- config && config->language[0] ? config->language[0] : '-',
- config && config->language[1] ? config->language[1] : '-',
- thisConfig.country[0] ? thisConfig.country[0] : '-',
- thisConfig.country[1] ? thisConfig.country[1] : '-',
- config && config->country[0] ? config->country[0] : '-',
- config && config->country[1] ? config->country[1] : '-',
- thisConfig.orientation,
- config ? config->orientation : 0,
- thisConfig.touchscreen,
- config ? config->touchscreen : 0,
- thisConfig.density,
- config ? config->density : 0,
- thisConfig.keyboard,
- config ? config->keyboard : 0,
- thisConfig.inputFlags,
- config ? config->inputFlags : 0,
- thisConfig.navigation,
- config ? config->navigation : 0,
- thisConfig.screenWidth,
- config ? config->screenWidth : 0,
- thisConfig.screenHeight,
- config ? config->screenHeight : 0,
- thisConfig.smallestScreenWidthDp,
- config ? config->smallestScreenWidthDp : 0,
- thisConfig.screenWidthDp,
- config ? config->screenWidthDp : 0,
- thisConfig.screenHeightDp,
- config ? config->screenHeightDp : 0));
+ thisConfig.toString().string()));
// Check to make sure this one is valid for the current parameters.
if (config && !thisConfig.match(*config)) {
@@ -4273,26 +5129,8 @@
TABLE_GETENTRY(
ResTable_config thisConfig;
thisConfig.copyFromDtoH(type->config);
- ALOGI("Adding config to type %d: imsi:%d/%d lang:%c%c cnt:%c%c "
- "orien:%d touch:%d density:%d key:%d inp:%d nav:%d w:%d h:%d "
- "swdp:%d wdp:%d hdp:%d\n",
- type->id,
- thisConfig.mcc, thisConfig.mnc,
- thisConfig.language[0] ? thisConfig.language[0] : '-',
- thisConfig.language[1] ? thisConfig.language[1] : '-',
- thisConfig.country[0] ? thisConfig.country[0] : '-',
- thisConfig.country[1] ? thisConfig.country[1] : '-',
- thisConfig.orientation,
- thisConfig.touchscreen,
- thisConfig.density,
- thisConfig.keyboard,
- thisConfig.inputFlags,
- thisConfig.navigation,
- thisConfig.screenWidth,
- thisConfig.screenHeight,
- thisConfig.smallestScreenWidthDp,
- thisConfig.screenWidthDp,
- thisConfig.screenHeightDp));
+ ALOGI("Adding config to type %d: %s\n",
+ type->id, thisConfig.toString().string()));
t->configs.add(type);
} else {
status_t err = validate_chunk(chunk, sizeof(ResChunk_header),
@@ -4622,186 +5460,9 @@
printf(" NON-INTEGER ResTable_type ADDRESS: %p\n", type);
continue;
}
- char density[16];
- uint16_t dval = dtohs(type->config.density);
- if (dval == ResTable_config::DENSITY_DEFAULT) {
- strcpy(density, "def");
- } else if (dval == ResTable_config::DENSITY_NONE) {
- strcpy(density, "no");
- } else {
- sprintf(density, "%d", (int)dval);
- }
- printf(" config %d", (int)configIndex);
- if (type->config.mcc != 0) {
- printf(" mcc=%d", dtohs(type->config.mcc));
- }
- if (type->config.mnc != 0) {
- printf(" mnc=%d", dtohs(type->config.mnc));
- }
- if (type->config.locale != 0) {
- printf(" lang=%c%c cnt=%c%c",
- type->config.language[0] ? type->config.language[0] : '-',
- type->config.language[1] ? type->config.language[1] : '-',
- type->config.country[0] ? type->config.country[0] : '-',
- type->config.country[1] ? type->config.country[1] : '-');
- }
- if (type->config.screenLayout != 0) {
- printf(" sz=%d",
- type->config.screenLayout&ResTable_config::MASK_SCREENSIZE);
- switch (type->config.screenLayout&ResTable_config::MASK_SCREENSIZE) {
- case ResTable_config::SCREENSIZE_SMALL:
- printf(" (small)");
- break;
- case ResTable_config::SCREENSIZE_NORMAL:
- printf(" (normal)");
- break;
- case ResTable_config::SCREENSIZE_LARGE:
- printf(" (large)");
- break;
- case ResTable_config::SCREENSIZE_XLARGE:
- printf(" (xlarge)");
- break;
- }
- printf(" lng=%d",
- type->config.screenLayout&ResTable_config::MASK_SCREENLONG);
- switch (type->config.screenLayout&ResTable_config::MASK_SCREENLONG) {
- case ResTable_config::SCREENLONG_NO:
- printf(" (notlong)");
- break;
- case ResTable_config::SCREENLONG_YES:
- printf(" (long)");
- break;
- }
- }
- if (type->config.orientation != 0) {
- printf(" orient=%d", type->config.orientation);
- switch (type->config.orientation) {
- case ResTable_config::ORIENTATION_PORT:
- printf(" (port)");
- break;
- case ResTable_config::ORIENTATION_LAND:
- printf(" (land)");
- break;
- case ResTable_config::ORIENTATION_SQUARE:
- printf(" (square)");
- break;
- }
- }
- if (type->config.uiMode != 0) {
- printf(" type=%d",
- type->config.uiMode&ResTable_config::MASK_UI_MODE_TYPE);
- switch (type->config.uiMode&ResTable_config::MASK_UI_MODE_TYPE) {
- case ResTable_config::UI_MODE_TYPE_NORMAL:
- printf(" (normal)");
- break;
- case ResTable_config::UI_MODE_TYPE_CAR:
- printf(" (car)");
- break;
- }
- printf(" night=%d",
- type->config.uiMode&ResTable_config::MASK_UI_MODE_NIGHT);
- switch (type->config.uiMode&ResTable_config::MASK_UI_MODE_NIGHT) {
- case ResTable_config::UI_MODE_NIGHT_NO:
- printf(" (no)");
- break;
- case ResTable_config::UI_MODE_NIGHT_YES:
- printf(" (yes)");
- break;
- }
- }
- if (dval != 0) {
- printf(" density=%s", density);
- }
- if (type->config.touchscreen != 0) {
- printf(" touch=%d", type->config.touchscreen);
- switch (type->config.touchscreen) {
- case ResTable_config::TOUCHSCREEN_NOTOUCH:
- printf(" (notouch)");
- break;
- case ResTable_config::TOUCHSCREEN_STYLUS:
- printf(" (stylus)");
- break;
- case ResTable_config::TOUCHSCREEN_FINGER:
- printf(" (finger)");
- break;
- }
- }
- if (type->config.inputFlags != 0) {
- printf(" keyhid=%d", type->config.inputFlags&ResTable_config::MASK_KEYSHIDDEN);
- switch (type->config.inputFlags&ResTable_config::MASK_KEYSHIDDEN) {
- case ResTable_config::KEYSHIDDEN_NO:
- printf(" (no)");
- break;
- case ResTable_config::KEYSHIDDEN_YES:
- printf(" (yes)");
- break;
- case ResTable_config::KEYSHIDDEN_SOFT:
- printf(" (soft)");
- break;
- }
- printf(" navhid=%d", type->config.inputFlags&ResTable_config::MASK_NAVHIDDEN);
- switch (type->config.inputFlags&ResTable_config::MASK_NAVHIDDEN) {
- case ResTable_config::NAVHIDDEN_NO:
- printf(" (no)");
- break;
- case ResTable_config::NAVHIDDEN_YES:
- printf(" (yes)");
- break;
- }
- }
- if (type->config.keyboard != 0) {
- printf(" kbd=%d", type->config.keyboard);
- switch (type->config.keyboard) {
- case ResTable_config::KEYBOARD_NOKEYS:
- printf(" (nokeys)");
- break;
- case ResTable_config::KEYBOARD_QWERTY:
- printf(" (qwerty)");
- break;
- case ResTable_config::KEYBOARD_12KEY:
- printf(" (12key)");
- break;
- }
- }
- if (type->config.navigation != 0) {
- printf(" nav=%d", type->config.navigation);
- switch (type->config.navigation) {
- case ResTable_config::NAVIGATION_NONAV:
- printf(" (nonav)");
- break;
- case ResTable_config::NAVIGATION_DPAD:
- printf(" (dpad)");
- break;
- case ResTable_config::NAVIGATION_TRACKBALL:
- printf(" (trackball)");
- break;
- case ResTable_config::NAVIGATION_WHEEL:
- printf(" (wheel)");
- break;
- }
- }
- if (type->config.screenWidth != 0) {
- printf(" w=%d", dtohs(type->config.screenWidth));
- }
- if (type->config.screenHeight != 0) {
- printf(" h=%d", dtohs(type->config.screenHeight));
- }
- if (type->config.smallestScreenWidthDp != 0) {
- printf(" swdp=%d", dtohs(type->config.smallestScreenWidthDp));
- }
- if (type->config.screenWidthDp != 0) {
- printf(" wdp=%d", dtohs(type->config.screenWidthDp));
- }
- if (type->config.screenHeightDp != 0) {
- printf(" hdp=%d", dtohs(type->config.screenHeightDp));
- }
- if (type->config.sdkVersion != 0) {
- printf(" sdk=%d", dtohs(type->config.sdkVersion));
- }
- if (type->config.minorVersion != 0) {
- printf(" mver=%d", dtohs(type->config.minorVersion));
- }
- printf("\n");
+ String8 configStr = type->config.toString();
+ printf(" config %s:\n", configStr.size() > 0
+ ? configStr.string() : "(default)");
size_t entryCount = dtohl(type->entryCount);
uint32_t entriesStart = dtohl(type->entriesStart);
if ((entriesStart&0x3) != 0) {
diff --git a/libs/utils/Threads.cpp b/libs/utils/Threads.cpp
index e343c62..ab207f5 100644
--- a/libs/utils/Threads.cpp
+++ b/libs/utils/Threads.cpp
@@ -34,6 +34,9 @@
# include <pthread.h>
# include <sched.h>
# include <sys/resource.h>
+#ifdef HAVE_ANDROID_OS
+# include <bionic_pthread.h>
+#endif
#elif defined(HAVE_WIN32_THREADS)
# include <windows.h>
# include <stdint.h>
@@ -86,7 +89,7 @@
char * threadName;
// we use this trampoline when we need to set the priority with
- // nice/setpriority.
+ // nice/setpriority, and name with prctl.
static int trampoline(const thread_data_t* t) {
thread_func_t f = t->entryFunction;
void* u = t->userData;
@@ -141,8 +144,13 @@
#ifdef HAVE_ANDROID_OS /* valgrind is rejecting RT-priority create reqs */
if (threadPriority != PRIORITY_DEFAULT || threadName != NULL) {
- // We could avoid the trampoline if there was a way to get to the
- // android_thread_id_t (pid) from pthread_t
+ // Now that the pthread_t has a method to find the associated
+ // android_thread_id_t (pid) from pthread_t, it would be possible to avoid
+ // this trampoline in some cases as the parent could set the properties
+ // for the child. However, there would be a race condition because the
+ // child becomes ready immediately, and it doesn't work for the name.
+ // prctl(PR_SET_NAME) only works for self; prctl(PR_SET_THREAD_NAME) was
+ // proposed but not yet accepted.
thread_data_t* t = new thread_data_t;
t->priority = threadPriority;
t->threadName = threadName ? strdup(threadName) : NULL;
@@ -178,6 +186,13 @@
return 1;
}
+#ifdef HAVE_ANDROID_OS
+static pthread_t android_thread_id_t_to_pthread(android_thread_id_t thread)
+{
+ return (pthread_t) thread;
+}
+#endif
+
android_thread_id_t androidGetThreadId()
{
return (android_thread_id_t)pthread_self();
@@ -909,6 +924,23 @@
return mStatus;
}
+#ifdef HAVE_ANDROID_OS
+pid_t Thread::getTid() const
+{
+ // mTid is not defined until the child initializes it, and the caller may need it earlier
+ Mutex::Autolock _l(mLock);
+ pid_t tid;
+ if (mRunning) {
+ pthread_t pthread = android_thread_id_t_to_pthread(mThread);
+ tid = __pthread_gettid(pthread);
+ } else {
+ ALOGW("Thread (this=%p): getTid() is undefined before run()", this);
+ tid = -1;
+ }
+ return tid;
+}
+#endif
+
bool Thread::exitPending() const
{
Mutex::Autolock _l(mLock);
diff --git a/media/java/android/media/AmrInputStream.java b/media/java/android/media/AmrInputStream.java
index bc68472..8b7eee2 100644
--- a/media/java/android/media/AmrInputStream.java
+++ b/media/java/android/media/AmrInputStream.java
@@ -44,7 +44,7 @@
private int mGae;
// result amr stream
- private byte[] mBuf = new byte[SAMPLES_PER_FRAME * 2];
+ private final byte[] mBuf = new byte[SAMPLES_PER_FRAME * 2];
private int mBufIn = 0;
private int mBufOut = 0;
diff --git a/media/java/android/media/AsyncPlayer.java b/media/java/android/media/AsyncPlayer.java
index 09aec2e..804528e 100644
--- a/media/java/android/media/AsyncPlayer.java
+++ b/media/java/android/media/AsyncPlayer.java
@@ -49,7 +49,7 @@
}
}
- private LinkedList<Command> mCmdQueue = new LinkedList();
+ private final LinkedList<Command> mCmdQueue = new LinkedList();
private void startSound(Command cmd) {
// Preparing can be slow, so if there is something else
diff --git a/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java
index 936ec0f..78eb89f 100644
--- a/media/java/android/media/AudioManager.java
+++ b/media/java/android/media/AudioManager.java
@@ -1509,7 +1509,7 @@
* Map to convert focus event listener IDs, as used in the AudioService audio focus stack,
* to actual listener objects.
*/
- private HashMap<String, OnAudioFocusChangeListener> mAudioFocusIdListenerMap =
+ private final HashMap<String, OnAudioFocusChangeListener> mAudioFocusIdListenerMap =
new HashMap<String, OnAudioFocusChangeListener>();
/**
* Lock to prevent concurrent changes to the list of focus listeners for this AudioManager
@@ -1524,7 +1524,7 @@
/**
* Handler for audio focus events coming from the audio service.
*/
- private FocusEventHandlerDelegate mAudioFocusEventHandlerDelegate =
+ private final FocusEventHandlerDelegate mAudioFocusEventHandlerDelegate =
new FocusEventHandlerDelegate();
/**
@@ -1563,7 +1563,7 @@
}
}
- private IAudioFocusDispatcher mAudioFocusDispatcher = new IAudioFocusDispatcher.Stub() {
+ private final IAudioFocusDispatcher mAudioFocusDispatcher = new IAudioFocusDispatcher.Stub() {
public void dispatchAudioFocusChange(int focusChange, String id) {
Message m = mAudioFocusEventHandlerDelegate.getHandler().obtainMessage(focusChange, id);
@@ -1649,11 +1649,46 @@
mAudioFocusDispatcher, getIdForAudioFocusListener(l),
mContext.getPackageName() /* package name */);
} catch (RemoteException e) {
- Log.e(TAG, "Can't call requestAudioFocus() from AudioService due to "+e);
+ Log.e(TAG, "Can't call requestAudioFocus() on AudioService due to "+e);
}
return status;
}
+ /**
+ * @hide
+ * Used internally by telephony package to request audio focus. Will cause the focus request
+ * to be associated with the "voice communication" identifier only used in AudioService
+ * to identify this use case.
+ * @param streamType use STREAM_RING for focus requests when ringing, VOICE_CALL for
+ * the establishment of the call
+ * @param durationHint the type of focus request. AUDIOFOCUS_GAIN_TRANSIENT is recommended so
+ * media applications resume after a call
+ */
+ public void requestAudioFocusForCall(int streamType, int durationHint) {
+ IAudioService service = getService();
+ try {
+ service.requestAudioFocus(streamType, durationHint, mICallBack, null,
+ AudioService.IN_VOICE_COMM_FOCUS_ID,
+ "system" /* dump-friendly package name */);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Can't call requestAudioFocusForCall() on AudioService due to "+e);
+ }
+ }
+
+ /**
+ * @hide
+ * Used internally by telephony package to abandon audio focus, typically after a call or
+ * when ringing ends and the call is rejected or not answered.
+ * Should match one or more calls to {@link #requestAudioFocusForCall(int, int)}.
+ */
+ public void abandonAudioFocusForCall() {
+ IAudioService service = getService();
+ try {
+ service.abandonAudioFocus(null, AudioService.IN_VOICE_COMM_FOCUS_ID);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Can't call abandonAudioFocusForCall() on AudioService due to "+e);
+ }
+ }
/**
* Abandon audio focus. Causes the previous focus owner, if any, to receive focus.
@@ -1668,7 +1703,7 @@
status = service.abandonAudioFocus(mAudioFocusDispatcher,
getIdForAudioFocusListener(l));
} catch (RemoteException e) {
- Log.e(TAG, "Can't call abandonAudioFocus() from AudioService due to "+e);
+ Log.e(TAG, "Can't call abandonAudioFocus() on AudioService due to "+e);
}
return status;
}
@@ -1920,7 +1955,7 @@
/**
* {@hide}
*/
- private IBinder mICallBack = new Binder();
+ private final IBinder mICallBack = new Binder();
/**
* Checks whether the phone is in silent mode, with or without vibrate.
diff --git a/media/java/android/media/AudioRecord.java b/media/java/android/media/AudioRecord.java
index 855e831..5cc24c0 100644
--- a/media/java/android/media/AudioRecord.java
+++ b/media/java/android/media/AudioRecord.java
@@ -161,7 +161,7 @@
/**
* Lock to make sure mRecordingState updates are reflecting the actual state of the object.
*/
- private Object mRecordingStateLock = new Object();
+ private final Object mRecordingStateLock = new Object();
/**
* The listener the AudioRecord notifies when the record position reaches a marker
* or for periodic updates during the progression of the record head.
diff --git a/media/java/android/media/AudioService.java b/media/java/android/media/AudioService.java
index 2eafd68..13e3982 100644
--- a/media/java/android/media/AudioService.java
+++ b/media/java/android/media/AudioService.java
@@ -151,7 +151,7 @@
private boolean mMediaServerOk;
private SoundPool mSoundPool;
- private Object mSoundEffectsLock = new Object();
+ private final Object mSoundEffectsLock = new Object();
private static final int NUM_SOUNDPOOL_CHANNELS = 4;
private static final int SOUND_EFFECT_VOLUME = 1000;
@@ -168,7 +168,7 @@
/* Sound effect file name mapping sound effect id (AudioManager.FX_xxx) to
* file index in SOUND_EFFECT_FILES[] (first column) and indicating if effect
* uses soundpool (second column) */
- private int[][] SOUND_EFFECT_FILES_MAP = new int[][] {
+ private final int[][] SOUND_EFFECT_FILES_MAP = new int[][] {
{0, -1}, // FX_KEY_CLICK
{0, -1}, // FX_FOCUS_NAVIGATION_UP
{0, -1}, // FX_FOCUS_NAVIGATION_DOWN
@@ -181,7 +181,7 @@
};
/** @hide Maximum volume index values for audio streams */
- private int[] MAX_STREAM_VOLUME = new int[] {
+ private final int[] MAX_STREAM_VOLUME = new int[] {
5, // STREAM_VOICE_CALL
7, // STREAM_SYSTEM
7, // STREAM_RING
@@ -197,7 +197,7 @@
* of another stream: This avoids multiplying the volume settings for hidden
* stream types that follow other stream behavior for volume settings
* NOTE: do not create loops in aliases! */
- private int[] STREAM_VOLUME_ALIAS = new int[] {
+ private final int[] STREAM_VOLUME_ALIAS = new int[] {
AudioSystem.STREAM_VOICE_CALL, // STREAM_VOICE_CALL
AudioSystem.STREAM_SYSTEM, // STREAM_SYSTEM
AudioSystem.STREAM_RING, // STREAM_RING
@@ -210,7 +210,7 @@
AudioSystem.STREAM_MUSIC // STREAM_TTS
};
- private AudioSystem.ErrorCallback mAudioSystemCallback = new AudioSystem.ErrorCallback() {
+ private final AudioSystem.ErrorCallback mAudioSystemCallback = new AudioSystem.ErrorCallback() {
public void onError(int error) {
switch (error) {
case AudioSystem.AUDIO_STATUS_SERVER_DIED:
@@ -270,17 +270,17 @@
private boolean mIsRinging = false;
// Devices currently connected
- private HashMap <Integer, String> mConnectedDevices = new HashMap <Integer, String>();
+ private final HashMap <Integer, String> mConnectedDevices = new HashMap <Integer, String>();
// Forced device usage for communications
private int mForcedUseForComm;
// List of binder death handlers for setMode() client processes.
// The last process to have called setMode() is at the top of the list.
- private ArrayList <SetModeDeathHandler> mSetModeDeathHandlers = new ArrayList <SetModeDeathHandler>();
+ private final ArrayList <SetModeDeathHandler> mSetModeDeathHandlers = new ArrayList <SetModeDeathHandler>();
// List of clients having issued a SCO start request
- private ArrayList <ScoClient> mScoClients = new ArrayList <ScoClient>();
+ private final ArrayList <ScoClient> mScoClients = new ArrayList <ScoClient>();
// BluetoothHeadset API to control SCO connection
private BluetoothHeadset mBluetoothHeadset;
@@ -992,8 +992,6 @@
if (mode != mMode) {
status = AudioSystem.setPhoneState(mode);
if (status == AudioSystem.AUDIO_STATUS_OK) {
- // automatically handle audio focus for mode changes
- handleFocusForCalls(mMode, mode, cb);
mMode = mode;
} else {
if (hdlr != null) {
@@ -1024,40 +1022,6 @@
return newModeOwnerPid;
}
- /** pre-condition: oldMode != newMode */
- private void handleFocusForCalls(int oldMode, int newMode, IBinder cb) {
- // if ringing
- if (newMode == AudioSystem.MODE_RINGTONE) {
- // if not ringing silently
- int ringVolume = AudioService.this.getStreamVolume(AudioManager.STREAM_RING);
- if (ringVolume > 0) {
- // request audio focus for the communication focus entry
- requestAudioFocus(AudioManager.STREAM_RING,
- AudioManager.AUDIOFOCUS_GAIN_TRANSIENT, cb,
- null /* IAudioFocusDispatcher allowed to be null only for this clientId */,
- IN_VOICE_COMM_FOCUS_ID /*clientId*/,
- "system");
-
- }
- }
- // if entering call
- else if ((newMode == AudioSystem.MODE_IN_CALL)
- || (newMode == AudioSystem.MODE_IN_COMMUNICATION)) {
- // request audio focus for the communication focus entry
- // (it's ok if focus was already requested during ringing)
- requestAudioFocus(AudioManager.STREAM_RING,
- AudioManager.AUDIOFOCUS_GAIN_TRANSIENT, cb,
- null /* IAudioFocusDispatcher allowed to be null only for this clientId */,
- IN_VOICE_COMM_FOCUS_ID /*clientId*/,
- "system");
- }
- // if exiting call
- else if (newMode == AudioSystem.MODE_NORMAL) {
- // abandon audio focus for communication focus entry
- abandonAudioFocus(null, IN_VOICE_COMM_FOCUS_ID);
- }
- }
-
/** @see AudioManager#getMode() */
public int getMode() {
return mMode;
@@ -2896,9 +2860,10 @@
//==========================================================================================
/* constant to identify focus stack entry that is used to hold the focus while the phone
- * is ringing or during a call
+ * is ringing or during a call. Used by com.android.internal.telephony.CallManager when
+ * entering and exiting calls.
*/
- private final static String IN_VOICE_COMM_FOCUS_ID = "AudioFocus_For_Phone_Ring_And_Calls";
+ public final static String IN_VOICE_COMM_FOCUS_ID = "AudioFocus_For_Phone_Ring_And_Calls";
private final static Object mAudioFocusLock = new Object();
@@ -2980,7 +2945,7 @@
}
}
- private Stack<FocusStackEntry> mFocusStack = new Stack<FocusStackEntry>();
+ private final Stack<FocusStackEntry> mFocusStack = new Stack<FocusStackEntry>();
/**
* Helper function:
@@ -3357,7 +3322,7 @@
* synchronized on mRCStack, but also BEFORE on mFocusLock as any change in either
* stack, audio focus or RC, can lead to a change in the remote control display
*/
- private Stack<RemoteControlStackEntry> mRCStack = new Stack<RemoteControlStackEntry>();
+ private final Stack<RemoteControlStackEntry> mRCStack = new Stack<RemoteControlStackEntry>();
/**
* Helper function:
diff --git a/media/java/android/media/AudioTrack.java b/media/java/android/media/AudioTrack.java
index 7b2f1b7..7d4c282 100644
--- a/media/java/android/media/AudioTrack.java
+++ b/media/java/android/media/AudioTrack.java
@@ -840,7 +840,10 @@
/**
* Stops playing the audio data.
- *
+ * When used on an instance created in {@link #MODE_STREAM} mode, audio will stop playing
+ * after the last buffer that was written has been played. For an immediate stop, use
+ * {@link #pause()}, followed by {@link #flush()} to discard audio data that hasn't been played
+ * back yet.
* @throws IllegalStateException
*/
public void stop()
@@ -859,7 +862,7 @@
/**
* Pauses the playback of the audio data. Data that has not been played
* back will not be discarded. Subsequent calls to {@link #play} will play
- * this data back.
+ * this data back. See {@link #flush()} to discard this data.
*
* @throws IllegalStateException
*/
diff --git a/media/java/android/media/ExifInterface.java b/media/java/android/media/ExifInterface.java
index 925f965..9d6c9f6 100644
--- a/media/java/android/media/ExifInterface.java
+++ b/media/java/android/media/ExifInterface.java
@@ -111,7 +111,7 @@
// there can only be one user at a time for the native functions (and
// they cannot keep state in the native code across function calls). We
// use sLock to serialize the accesses.
- private static Object sLock = new Object();
+ private static final Object sLock = new Object();
/**
* Reads Exif tags from the specified JPEG file.
diff --git a/media/java/android/media/MediaFile.java b/media/java/android/media/MediaFile.java
index e275aa6..7f7e284 100644
--- a/media/java/android/media/MediaFile.java
+++ b/media/java/android/media/MediaFile.java
@@ -120,18 +120,18 @@
}
}
- private static HashMap<String, MediaFileType> sFileTypeMap
+ private static final HashMap<String, MediaFileType> sFileTypeMap
= new HashMap<String, MediaFileType>();
- private static HashMap<String, Integer> sMimeTypeMap
+ private static final HashMap<String, Integer> sMimeTypeMap
= new HashMap<String, Integer>();
// maps file extension to MTP format code
- private static HashMap<String, Integer> sFileTypeToFormatMap
+ private static final HashMap<String, Integer> sFileTypeToFormatMap
= new HashMap<String, Integer>();
// maps mime type to MTP format code
- private static HashMap<String, Integer> sMimeTypeToFormatMap
+ private static final HashMap<String, Integer> sMimeTypeToFormatMap
= new HashMap<String, Integer>();
// maps MTP format code to mime type
- private static HashMap<Integer, String> sFormatToMimeTypeMap
+ private static final HashMap<Integer, String> sFormatToMimeTypeMap
= new HashMap<Integer, String>();
static void addFileType(String extension, int fileType, String mimeType) {
diff --git a/media/java/android/media/MediaInserter.java b/media/java/android/media/MediaInserter.java
index a998407..e92c710 100644
--- a/media/java/android/media/MediaInserter.java
+++ b/media/java/android/media/MediaInserter.java
@@ -32,7 +32,7 @@
* {@hide}
*/
public class MediaInserter {
- private HashMap<Uri, List<ContentValues>> mRowMap =
+ private final HashMap<Uri, List<ContentValues>> mRowMap =
new HashMap<Uri, List<ContentValues>>();
private IContentProvider mProvider;
diff --git a/media/java/android/media/MediaRecorder.java b/media/java/android/media/MediaRecorder.java
index 08e6032..85d99c1 100644
--- a/media/java/android/media/MediaRecorder.java
+++ b/media/java/android/media/MediaRecorder.java
@@ -138,10 +138,13 @@
*/
public final class AudioSource {
/* Do not change these values without updating their counterparts
- * in include/media/mediarecorder.h!
+ * in system/core/include/system/audio.h!
*/
private AudioSource() {}
+
+ /** Default audio source **/
public static final int DEFAULT = 0;
+
/** Microphone audio source */
public static final int MIC = 1;
@@ -201,18 +204,24 @@
/** MPEG4 media file format*/
public static final int MPEG_4 = 2;
- /** The following formats are audio only .aac or .amr formats **/
- /** @deprecated Deprecated in favor of AMR_NB */
- /** Deprecated in favor of MediaRecorder.OutputFormat.AMR_NB */
- /** AMR NB file format */
+ /** The following formats are audio only .aac or .amr formats */
+
+ /**
+ * AMR NB file format
+ * @deprecated Deprecated in favor of MediaRecorder.OutputFormat.AMR_NB
+ */
public static final int RAW_AMR = 3;
+
/** AMR NB file format */
public static final int AMR_NB = 3;
+
/** AMR WB file format */
public static final int AMR_WB = 4;
+
/** @hide AAC ADIF file format */
public static final int AAC_ADIF = 5;
- /** @hide AAC ADTS file format */
+
+ /** AAC ADTS file format */
public static final int AAC_ADTS = 6;
/** @hide Stream over a socket, limited to a single stream */
diff --git a/media/java/android/media/MediaScanner.java b/media/java/android/media/MediaScanner.java
index b06ef95..1c13fff 100644
--- a/media/java/android/media/MediaScanner.java
+++ b/media/java/android/media/MediaScanner.java
@@ -35,6 +35,7 @@
import android.os.RemoteException;
import android.os.SystemProperties;
import android.provider.MediaStore;
+import android.provider.MediaStore.Files.FileColumns;
import android.provider.Settings;
import android.provider.MediaStore.Audio;
import android.provider.MediaStore.Files;
@@ -58,6 +59,7 @@
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
+import java.util.Locale;
/**
* Internal service helper that no-one should use directly.
@@ -312,10 +314,8 @@
private final String mExternalStoragePath;
- // WARNING: Bulk inserts sounded like a great idea and gave us a good performance improvement,
- // but unfortunately it also introduced a number of bugs. All the known bugs were fixed,
- // but we need more testing before enabling.
- private static final boolean ENABLE_BULK_INSERTS = false;
+ /** whether to use bulk inserts or individual inserts for each item */
+ private static final boolean ENABLE_BULK_INSERTS = true;
// used when scanning the image database so we know whether we have to prune
// old thumbnail files
@@ -345,7 +345,7 @@
// this should be set when scanning files on a case insensitive file system.
private boolean mCaseInsensitivePaths;
- private BitmapFactory.Options mBitmapOptions = new BitmapFactory.Options();
+ private final BitmapFactory.Options mBitmapOptions = new BitmapFactory.Options();
private static class FileCacheEntry {
long mRowId;
@@ -401,7 +401,7 @@
+ Settings.System.ALARM_ALERT);
}
- private MyMediaScannerClient mClient = new MyMediaScannerClient();
+ private final MyMediaScannerClient mClient = new MyMediaScannerClient();
private boolean isDrmEnabled() {
String prop = SystemProperties.get("drm.service.enabled");
@@ -946,6 +946,22 @@
// path should never change, and we want to avoid replacing mixed cased paths
// with squashed lower case paths
values.remove(MediaStore.MediaColumns.DATA);
+
+ int mediaType = 0;
+ if (!MediaScanner.isNoMediaPath(entry.mPath)) {
+ int fileType = MediaFile.getFileTypeForMimeType(mMimeType);
+ if (MediaFile.isAudioFileType(fileType)) {
+ mediaType = FileColumns.MEDIA_TYPE_AUDIO;
+ } else if (MediaFile.isVideoFileType(fileType)) {
+ mediaType = FileColumns.MEDIA_TYPE_VIDEO;
+ } else if (MediaFile.isImageFileType(fileType)) {
+ mediaType = FileColumns.MEDIA_TYPE_IMAGE;
+ } else if (MediaFile.isPlayListFileType(fileType)) {
+ mediaType = FileColumns.MEDIA_TYPE_PLAYLIST;
+ }
+ values.put(FileColumns.MEDIA_TYPE, mediaType);
+ }
+
mMediaProvider.update(result, values, null, null);
}
@@ -1035,7 +1051,7 @@
// First read existing files from the files table
c = mMediaProvider.query(mFilesUri, FILES_PRESCAN_PROJECTION,
- where, selectionArgs, null);
+ where, selectionArgs, null, null);
if (c != null) {
mWasEmptyPriorToScan = c.getCount() == 0;
@@ -1072,7 +1088,7 @@
// compute original size of images
mOriginalCount = 0;
- c = mMediaProvider.query(mImagesUri, ID_PROJECTION, null, null, null);
+ c = mMediaProvider.query(mImagesUri, ID_PROJECTION, null, null, null, null);
if (c != null) {
mOriginalCount = c.getCount();
c.close();
@@ -1107,7 +1123,7 @@
new String [] { "_data" },
null,
null,
- null);
+ null, null);
Log.v(TAG, "pruneDeadThumbnailFiles... " + c);
if (c != null && c.moveToFirst()) {
do {
@@ -1180,6 +1196,10 @@
mMediaProvider.delete(ContentUris.withAppendedId(mFilesUri, entry.mRowId),
null, null);
iterator.remove();
+ if (entry.mPath.toLowerCase(Locale.US).endsWith("/.nomedia")) {
+ File f = new File(path);
+ mMediaProvider.call(MediaStore.UNHIDE_CALL, f.getParent(), null);
+ }
}
}
}
@@ -1472,7 +1492,7 @@
if (bestMatch.mRowId == 0) {
Cursor c = mMediaProvider.query(mAudioUri, ID_PROJECTION,
MediaStore.Files.FileColumns.DATA + "=?",
- new String[] { bestMatch.mPath }, null);
+ new String[] { bestMatch.mPath }, null, null);
if (c != null) {
if (c.moveToNext()) {
bestMatch.mRowId = c.getLong(0);
diff --git a/media/java/android/media/MediaScannerConnection.java b/media/java/android/media/MediaScannerConnection.java
index 969da39..21b6e14 100644
--- a/media/java/android/media/MediaScannerConnection.java
+++ b/media/java/android/media/MediaScannerConnection.java
@@ -46,7 +46,7 @@
private IMediaScannerService mService;
private boolean mConnected; // true if connect() has been called since last disconnect()
- private IMediaScannerListener.Stub mListener = new IMediaScannerListener.Stub() {
+ private final IMediaScannerListener.Stub mListener = new IMediaScannerListener.Stub() {
public void scanCompleted(String path, Uri uri) {
MediaScannerConnectionClient client = mClient;
if (client != null) {
diff --git a/media/java/android/media/MiniThumbFile.java b/media/java/android/media/MiniThumbFile.java
index df141c1..63b149c 100644
--- a/media/java/android/media/MiniThumbFile.java
+++ b/media/java/android/media/MiniThumbFile.java
@@ -52,7 +52,7 @@
private RandomAccessFile mMiniThumbFile;
private FileChannel mChannel;
private ByteBuffer mBuffer;
- private static Hashtable<String, MiniThumbFile> sThumbFiles =
+ private static final Hashtable<String, MiniThumbFile> sThumbFiles =
new Hashtable<String, MiniThumbFile>();
/**
diff --git a/media/java/android/media/RemoteControlClient.java b/media/java/android/media/RemoteControlClient.java
index 77acfe6..18b4ee6 100644
--- a/media/java/android/media/RemoteControlClient.java
+++ b/media/java/android/media/RemoteControlClient.java
@@ -576,6 +576,7 @@
/**
* Cache for the metadata strings.
* Access synchronized on mCacheLock
+ * This is re-initialized in apply() and so cannot be final.
*/
private Bundle mMetadata = new Bundle();
@@ -621,7 +622,7 @@
/**
* The IRemoteControlClient implementation
*/
- private IRemoteControlClient mIRCC = new IRemoteControlClient.Stub() {
+ private final IRemoteControlClient mIRCC = new IRemoteControlClient.Stub() {
public void onInformationRequested(int clientGeneration, int infoFlags,
int artWidth, int artHeight) {
diff --git a/media/java/android/media/RingtoneManager.java b/media/java/android/media/RingtoneManager.java
index 9c0819f..7aaf4aa 100644
--- a/media/java/android/media/RingtoneManager.java
+++ b/media/java/android/media/RingtoneManager.java
@@ -224,7 +224,7 @@
* If a column (item from this list) exists in the Cursor, its value must
* be true (value of 1) for the row to be returned.
*/
- private List<String> mFilterColumns = new ArrayList<String>();
+ private final List<String> mFilterColumns = new ArrayList<String>();
private boolean mStopPreviousRingtone = true;
private Ringtone mPreviousRingtone;
diff --git a/media/java/android/mtp/MtpDatabase.java b/media/java/android/mtp/MtpDatabase.java
index 19db1c0..18aa4b3 100755
--- a/media/java/android/mtp/MtpDatabase.java
+++ b/media/java/android/mtp/MtpDatabase.java
@@ -266,7 +266,7 @@
Cursor c = null;
try {
c = mMediaProvider.query(mObjectsUri, ID_PROJECTION, PATH_WHERE,
- new String[] { path }, null);
+ new String[] { path }, null, null);
if (c != null && c.getCount() > 0) {
Log.w(TAG, "file already exists in beginSendObject: " + path);
return -1;
@@ -433,7 +433,7 @@
}
}
- return mMediaProvider.query(mObjectsUri, ID_PROJECTION, where, whereArgs, null);
+ return mMediaProvider.query(mObjectsUri, ID_PROJECTION, where, whereArgs, null, null);
}
private int[] getObjectList(int storageID, int format, int parent) {
@@ -699,7 +699,7 @@
String path = null;
String[] whereArgs = new String[] { Integer.toString(handle) };
try {
- c = mMediaProvider.query(mObjectsUri, PATH_PROJECTION, ID_WHERE, whereArgs, null);
+ c = mMediaProvider.query(mObjectsUri, PATH_PROJECTION, ID_WHERE, whereArgs, null, null);
if (c != null && c.moveToNext()) {
path = c.getString(1);
}
@@ -752,6 +752,29 @@
return MtpConstants.RESPONSE_GENERAL_ERROR;
}
+ // check if nomedia status changed
+ if (newFile.isDirectory()) {
+ // for directories, check if renamed from something hidden to something non-hidden
+ if (oldFile.getName().startsWith(".") && !newPath.startsWith(".")) {
+ // directory was unhidden
+ try {
+ mMediaProvider.call(MediaStore.UNHIDE_CALL, newPath, null);
+ } catch (RemoteException e) {
+ Log.e(TAG, "failed to unhide/rescan for " + newPath);
+ }
+ }
+ } else {
+ // for files, check if renamed from .nomedia to something else
+ if (oldFile.getName().toLowerCase(Locale.US).equals(".nomedia")
+ && !newPath.toLowerCase(Locale.US).equals(".nomedia")) {
+ try {
+ mMediaProvider.call(MediaStore.UNHIDE_CALL, oldFile.getParent(), null);
+ } catch (RemoteException e) {
+ Log.e(TAG, "failed to unhide/rescan for " + newPath);
+ }
+ }
+ }
+
return MtpConstants.RESPONSE_OK;
}
@@ -815,7 +838,7 @@
Cursor c = null;
try {
c = mMediaProvider.query(mObjectsUri, OBJECT_INFO_PROJECTION,
- ID_WHERE, new String[] { Integer.toString(handle) }, null);
+ ID_WHERE, new String[] { Integer.toString(handle) }, null, null);
if (c != null && c.moveToNext()) {
outStorageFormatParent[0] = c.getInt(1);
outStorageFormatParent[1] = c.getInt(2);
@@ -858,7 +881,7 @@
Cursor c = null;
try {
c = mMediaProvider.query(mObjectsUri, PATH_SIZE_FORMAT_PROJECTION,
- ID_WHERE, new String[] { Integer.toString(handle) }, null);
+ ID_WHERE, new String[] { Integer.toString(handle) }, null, null);
if (c != null && c.moveToNext()) {
String path = c.getString(1);
path.getChars(0, path.length(), outFilePath, 0);
@@ -887,7 +910,7 @@
Cursor c = null;
try {
c = mMediaProvider.query(mObjectsUri, PATH_SIZE_FORMAT_PROJECTION,
- ID_WHERE, new String[] { Integer.toString(handle) }, null);
+ ID_WHERE, new String[] { Integer.toString(handle) }, null, null);
if (c != null && c.moveToNext()) {
// don't convert to media path here, since we will be matching
// against paths in the database matching /data/media
@@ -915,6 +938,15 @@
Uri uri = Files.getMtpObjectsUri(mVolumeName, handle);
if (mMediaProvider.delete(uri, null, null) > 0) {
+ if (format != MtpConstants.FORMAT_ASSOCIATION
+ && path.toLowerCase(Locale.US).endsWith("/.nomedia")) {
+ try {
+ String parentPath = path.substring(0, path.lastIndexOf("/"));
+ mMediaProvider.call(MediaStore.UNHIDE_CALL, parentPath, null);
+ } catch (RemoteException e) {
+ Log.e(TAG, "failed to unhide/rescan for " + path);
+ }
+ }
return MtpConstants.RESPONSE_OK;
} else {
return MtpConstants.RESPONSE_INVALID_OBJECT_HANDLE;
@@ -933,7 +965,7 @@
Uri uri = Files.getMtpReferencesUri(mVolumeName, handle);
Cursor c = null;
try {
- c = mMediaProvider.query(uri, ID_PROJECTION, null, null, null);
+ c = mMediaProvider.query(uri, ID_PROJECTION, null, null, null, null);
if (c == null) {
return null;
}
diff --git a/media/java/android/mtp/MtpPropertyGroup.java b/media/java/android/mtp/MtpPropertyGroup.java
index 76c8569..dab5454 100644
--- a/media/java/android/mtp/MtpPropertyGroup.java
+++ b/media/java/android/mtp/MtpPropertyGroup.java
@@ -191,7 +191,7 @@
// for now we are only reading properties from the "objects" table
c = mProvider.query(mUri,
new String [] { Files.FileColumns._ID, column },
- ID_WHERE, new String[] { Integer.toString(id) }, null);
+ ID_WHERE, new String[] { Integer.toString(id) }, null, null);
if (c != null && c.moveToNext()) {
return c.getString(1);
} else {
@@ -211,7 +211,7 @@
try {
c = mProvider.query(Audio.Media.getContentUri(mVolumeName),
new String [] { Files.FileColumns._ID, column },
- ID_WHERE, new String[] { Integer.toString(id) }, null);
+ ID_WHERE, new String[] { Integer.toString(id) }, null, null);
if (c != null && c.moveToNext()) {
return c.getString(1);
} else {
@@ -232,7 +232,7 @@
Uri uri = Audio.Genres.getContentUriForAudioId(mVolumeName, id);
c = mProvider.query(uri,
new String [] { Files.FileColumns._ID, Audio.GenresColumns.NAME },
- null, null, null);
+ null, null, null, null);
if (c != null && c.moveToNext()) {
return c.getString(1);
} else {
@@ -254,7 +254,7 @@
// for now we are only reading properties from the "objects" table
c = mProvider.query(mUri,
new String [] { Files.FileColumns._ID, column },
- ID_WHERE, new String[] { Integer.toString(id) }, null);
+ ID_WHERE, new String[] { Integer.toString(id) }, null, null);
if (c != null && c.moveToNext()) {
return new Long(c.getLong(1));
}
@@ -323,7 +323,7 @@
try {
// don't query if not necessary
if (depth > 0 || handle == 0xFFFFFFFF || mColumns.length > 1) {
- c = mProvider.query(mUri, mColumns, where, whereArgs, null);
+ c = mProvider.query(mUri, mColumns, where, whereArgs, null, null);
if (c == null) {
return new MtpPropertyList(0, MtpConstants.RESPONSE_INVALID_OBJECT_HANDLE);
}
diff --git a/media/jni/Android.mk b/media/jni/Android.mk
index ee96a95..23cc0e2 100644
--- a/media/jni/Android.mk
+++ b/media/jni/Android.mk
@@ -28,7 +28,11 @@
libcamera_client \
libmtp \
libusbhost \
- libexif
+ libexif \
+ libstagefright_amrnb_common \
+
+LOCAL_STATIC_LIBRARIES := \
+ libstagefright_amrnbenc
LOCAL_C_INCLUDES += \
external/jhead \
diff --git a/media/libeffects/preprocessing/Android.mk b/media/libeffects/preprocessing/Android.mk
index 77d40b6..7f7c7e1 100755
--- a/media/libeffects/preprocessing/Android.mk
+++ b/media/libeffects/preprocessing/Android.mk
@@ -13,7 +13,7 @@
LOCAL_C_INCLUDES += \
external/webrtc/src \
external/webrtc/src/modules/interface \
- external/webrtc/src/modules/audio_processing/main/interface \
+ external/webrtc/src/modules/audio_processing/interface \
system/media/audio_effects/include
LOCAL_C_INCLUDES += $(call include-path-for, speex)
diff --git a/media/libeffects/preprocessing/PreProcessing.cpp b/media/libeffects/preprocessing/PreProcessing.cpp
index e988e06..9fd6764 100755
--- a/media/libeffects/preprocessing/PreProcessing.cpp
+++ b/media/libeffects/preprocessing/PreProcessing.cpp
@@ -24,8 +24,8 @@
#include <audio_effects/effect_aec.h>
#include <audio_effects/effect_agc.h>
#include <audio_effects/effect_ns.h>
-#include "modules/interface/module_common_types.h"
-#include "modules/audio_processing/main/interface/audio_processing.h"
+#include <module_common_types.h>
+#include <audio_processing.h>
#include "speex/speex_resampler.h"
@@ -220,8 +220,8 @@
// Automatic Gain Control (AGC)
//------------------------------------------------------------------------------
-static const int kAgcDefaultTargetLevel = 0;
-static const int kAgcDefaultCompGain = 90;
+static const int kAgcDefaultTargetLevel = 3;
+static const int kAgcDefaultCompGain = 9;
static const bool kAgcDefaultLimiter = true;
int AgcInit (preproc_effect_t *effect)
diff --git a/media/libmedia/AudioRecord.cpp b/media/libmedia/AudioRecord.cpp
index 5b5b076..2b3ea38 100644
--- a/media/libmedia/AudioRecord.cpp
+++ b/media/libmedia/AudioRecord.cpp
@@ -84,7 +84,7 @@
}
AudioRecord::AudioRecord(
- int inputSource,
+ audio_source_t inputSource,
uint32_t sampleRate,
audio_format_t format,
uint32_t channelMask,
@@ -119,7 +119,7 @@
}
status_t AudioRecord::set(
- int inputSource,
+ audio_source_t inputSource,
uint32_t sampleRate,
audio_format_t format,
uint32_t channelMask,
@@ -228,7 +228,7 @@
mMarkerReached = false;
mNewPosition = 0;
mUpdatePeriod = 0;
- mInputSource = (uint8_t)inputSource;
+ mInputSource = inputSource;
mFlags = flags;
mInput = input;
AudioSystem::acquireAudioSessionId(mSessionId);
@@ -272,9 +272,9 @@
}
}
-int AudioRecord::inputSource() const
+audio_source_t AudioRecord::inputSource() const
{
- return (int)mInputSource;
+ return mInputSource;
}
// -------------------------------------------------------------------------
diff --git a/media/libmedia/AudioSystem.cpp b/media/libmedia/AudioSystem.cpp
index 952d634..df5017b 100644
--- a/media/libmedia/AudioSystem.cpp
+++ b/media/libmedia/AudioSystem.cpp
@@ -35,7 +35,8 @@
sp<AudioSystem::AudioFlingerClient> AudioSystem::gAudioFlingerClient;
audio_error_callback AudioSystem::gAudioErrorCallback = NULL;
// Cached values
-DefaultKeyedVector<int, audio_io_handle_t> AudioSystem::gStreamOutputMap(0);
+
+DefaultKeyedVector<audio_stream_type_t, audio_io_handle_t> AudioSystem::gStreamOutputMap(0);
DefaultKeyedVector<audio_io_handle_t, AudioSystem::OutputDescriptor *> AudioSystem::gOutputs(0);
// Cached values for recording queries, all protected by gLock
@@ -404,7 +405,7 @@
void AudioSystem::AudioFlingerClient::ioConfigChanged(int event, int ioHandle, void *param2) {
ALOGV("ioConfigChanged() event %d", event);
OutputDescriptor *desc;
- uint32_t stream;
+ audio_stream_type_t stream;
if (ioHandle == 0) return;
@@ -413,7 +414,7 @@
switch (event) {
case STREAM_CONFIG_CHANGED:
if (param2 == 0) break;
- stream = *(uint32_t *)param2;
+ stream = *(audio_stream_type_t *)param2;
ALOGV("ioConfigChanged() STREAM_CONFIG_CHANGED stream %d, output %d", stream, ioHandle);
if (gStreamOutputMap.indexOfKey(stream) >= 0) {
gStreamOutputMap.replaceValueFor(stream, ioHandle);
@@ -630,7 +631,7 @@
aps->releaseOutput(output);
}
-audio_io_handle_t AudioSystem::getInput(int inputSource,
+audio_io_handle_t AudioSystem::getInput(audio_source_t inputSource,
uint32_t samplingRate,
audio_format_t format,
uint32_t channels,
diff --git a/media/libmedia/IAudioPolicyService.cpp b/media/libmedia/IAudioPolicyService.cpp
index b5c857f..99385aa4 100644
--- a/media/libmedia/IAudioPolicyService.cpp
+++ b/media/libmedia/IAudioPolicyService.cpp
@@ -172,7 +172,7 @@
}
virtual audio_io_handle_t getInput(
- int inputSource,
+ audio_source_t inputSource,
uint32_t samplingRate,
audio_format_t format,
uint32_t channels,
@@ -181,7 +181,7 @@
{
Parcel data, reply;
data.writeInterfaceToken(IAudioPolicyService::getInterfaceDescriptor());
- data.writeInt32(inputSource);
+ data.writeInt32((int32_t) inputSource);
data.writeInt32(samplingRate);
data.writeInt32(static_cast <uint32_t>(format));
data.writeInt32(channels);
@@ -461,7 +461,7 @@
case GET_INPUT: {
CHECK_INTERFACE(IAudioPolicyService, data, reply);
- int inputSource = data.readInt32();
+ audio_source_t inputSource = (audio_source_t) data.readInt32();
uint32_t samplingRate = data.readInt32();
audio_format_t format = (audio_format_t) data.readInt32();
uint32_t channels = data.readInt32();
diff --git a/media/libmedia/IOMX.cpp b/media/libmedia/IOMX.cpp
index d2f5f71..27c7e03 100644
--- a/media/libmedia/IOMX.cpp
+++ b/media/libmedia/IOMX.cpp
@@ -59,9 +59,10 @@
: BpInterface<IOMX>(impl) {
}
- virtual bool livesLocally(pid_t pid) {
+ virtual bool livesLocally(node_id node, pid_t pid) {
Parcel data, reply;
data.writeInterfaceToken(IOMX::getInterfaceDescriptor());
+ data.writeIntPtr((intptr_t)node);
data.writeInt32(pid);
remote()->transact(LIVES_LOCALLY, data, &reply);
@@ -417,7 +418,9 @@
case LIVES_LOCALLY:
{
CHECK_INTERFACE(IOMX, data, reply);
- reply->writeInt32(livesLocally((pid_t)data.readInt32()));
+ node_id node = (void *)data.readIntPtr();
+ pid_t pid = (pid_t)data.readInt32();
+ reply->writeInt32(livesLocally(node, pid));
return OK;
}
diff --git a/media/libmedia/autodetect.cpp b/media/libmedia/autodetect.cpp
index dfcc6a0..be5c3b2 100644
--- a/media/libmedia/autodetect.cpp
+++ b/media/libmedia/autodetect.cpp
@@ -16,7 +16,7 @@
#include "autodetect.h"
-typedef struct CharRange {
+struct CharRange {
uint16_t first;
uint16_t last;
};
diff --git a/media/libstagefright/Android.mk b/media/libstagefright/Android.mk
index 0aeb515..03e8a06 100644
--- a/media/libstagefright/Android.mk
+++ b/media/libstagefright/Android.mk
@@ -74,12 +74,10 @@
libcrypto \
libssl \
libgui \
+ libstagefright_omx \
LOCAL_STATIC_LIBRARIES := \
libstagefright_color_conversion \
- libstagefright_aacenc \
- libstagefright_amrnbenc \
- libstagefright_amrwbenc \
libstagefright_avcenc \
libstagefright_m4vh263enc \
libstagefright_matroska \
@@ -141,7 +139,6 @@
################################################################################
LOCAL_SHARED_LIBRARIES += \
- libstagefright_amrnb_common \
libstagefright_enc_common \
libstagefright_avc_common \
libstagefright_foundation \
diff --git a/media/libstagefright/AudioSource.cpp b/media/libstagefright/AudioSource.cpp
index 2172cc0..8bdb7c5 100644
--- a/media/libstagefright/AudioSource.cpp
+++ b/media/libstagefright/AudioSource.cpp
@@ -47,7 +47,7 @@
}
AudioSource::AudioSource(
- int inputSource, uint32_t sampleRate, uint32_t channels)
+ audio_source_t inputSource, uint32_t sampleRate, uint32_t channels)
: mStarted(false),
mSampleRate(sampleRate),
mPrevSampleTimeUs(0),
diff --git a/media/libstagefright/AwesomePlayer.cpp b/media/libstagefright/AwesomePlayer.cpp
index 8480b6d..8073af8 100644
--- a/media/libstagefright/AwesomePlayer.cpp
+++ b/media/libstagefright/AwesomePlayer.cpp
@@ -30,7 +30,7 @@
#include "include/MPEG2TSExtractor.h"
#include "include/WVMExtractor.h"
-#include "timedtext/TimedTextPlayer.h"
+#include "timedtext/TimedTextDriver.h"
#include <binder/IPCThreadState.h>
#include <binder/IServiceManager.h>
@@ -192,7 +192,7 @@
mVideoBuffer(NULL),
mDecryptHandle(NULL),
mLastVideoTimeUs(-1),
- mTextPlayer(NULL) {
+ mTextDriver(NULL) {
CHECK_EQ(mClient.connect(), (status_t)OK);
DataSource::RegisterDefaultSniffers();
@@ -530,9 +530,9 @@
delete mAudioPlayer;
mAudioPlayer = NULL;
- if (mTextPlayer != NULL) {
- delete mTextPlayer;
- mTextPlayer = NULL;
+ if (mTextDriver != NULL) {
+ delete mTextDriver;
+ mTextDriver = NULL;
}
mVideoRenderer.clear();
@@ -1118,7 +1118,7 @@
}
if (mFlags & TEXTPLAYER_STARTED) {
- mTextPlayer->pause();
+ mTextDriver->pause();
modifyFlags(TEXT_RUNNING, CLEAR);
}
@@ -1272,9 +1272,9 @@
}
status_t AwesomePlayer::setTimedTextTrackIndex(int32_t index) {
- if (mTextPlayer != NULL) {
+ if (mTextDriver != NULL) {
if (index >= 0) { // to turn on a text track
- status_t err = mTextPlayer->setTimedTextTrackIndex(index);
+ status_t err = mTextDriver->setTimedTextTrackIndex(index);
if (err != OK) {
return err;
}
@@ -1290,7 +1290,7 @@
modifyFlags(TEXTPLAYER_STARTED, CLEAR);
}
- return mTextPlayer->setTimedTextTrackIndex(index);
+ return mTextDriver->setTimedTextTrackIndex(index);
}
} else {
return INVALID_OPERATION;
@@ -1319,7 +1319,7 @@
seekAudioIfNecessary_l();
if (mFlags & TEXTPLAYER_STARTED) {
- mTextPlayer->seekTo(mSeekTimeUs);
+ mTextDriver->seekToAsync(mSeekTimeUs);
}
if (!(mFlags & PLAYING)) {
@@ -1364,11 +1364,11 @@
Mutex::Autolock autoLock(mTimedTextLock);
CHECK(source != NULL);
- if (mTextPlayer == NULL) {
- mTextPlayer = new TimedTextPlayer(this, mListener, &mQueue);
+ if (mTextDriver == NULL) {
+ mTextDriver = new TimedTextDriver(mListener);
}
- mTextPlayer->addTextSource(source);
+ mTextDriver->addInBandTextSource(source);
}
status_t AwesomePlayer::initAudioDecoder() {
@@ -1695,7 +1695,7 @@
}
if ((mFlags & TEXTPLAYER_STARTED) && !(mFlags & (TEXT_RUNNING | SEEK_PREVIEW))) {
- mTextPlayer->resume();
+ mTextDriver->resume();
modifyFlags(TEXT_RUNNING, SET);
}
@@ -2241,11 +2241,11 @@
case KEY_PARAMETER_TIMED_TEXT_ADD_OUT_OF_BAND_SOURCE:
{
Mutex::Autolock autoLock(mTimedTextLock);
- if (mTextPlayer == NULL) {
- mTextPlayer = new TimedTextPlayer(this, mListener, &mQueue);
+ if (mTextDriver == NULL) {
+ mTextDriver = new TimedTextDriver(mListener);
}
- return mTextPlayer->setParameter(key, request);
+ return mTextDriver->addOutOfBandTextSource(request);
}
case KEY_PARAMETER_CACHE_STAT_COLLECT_FREQ_MS:
{
diff --git a/media/libstagefright/MPEG4Extractor.cpp b/media/libstagefright/MPEG4Extractor.cpp
index bc88015..6c95d4e 100644
--- a/media/libstagefright/MPEG4Extractor.cpp
+++ b/media/libstagefright/MPEG4Extractor.cpp
@@ -20,7 +20,6 @@
#include "include/MPEG4Extractor.h"
#include "include/SampleTable.h"
#include "include/ESDS.h"
-#include "timedtext/TimedTextPlayer.h"
#include <arpa/inet.h>
@@ -2430,4 +2429,3 @@
}
} // namespace android
-
diff --git a/media/libstagefright/OMXClient.cpp b/media/libstagefright/OMXClient.cpp
index 9de873e..7a805aa 100644
--- a/media/libstagefright/OMXClient.cpp
+++ b/media/libstagefright/OMXClient.cpp
@@ -20,11 +20,299 @@
#include <binder/IServiceManager.h>
#include <media/IMediaPlayerService.h>
-#include <media/stagefright/MediaDebug.h>
+#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/OMXClient.h>
+#include <utils/KeyedVector.h>
+
+#include "include/OMX.h"
namespace android {
+struct MuxOMX : public IOMX {
+ MuxOMX(const sp<IOMX> &remoteOMX);
+ virtual ~MuxOMX();
+
+ virtual IBinder *onAsBinder() { return NULL; }
+
+ virtual bool livesLocally(node_id node, pid_t pid);
+
+ virtual status_t listNodes(List<ComponentInfo> *list);
+
+ virtual status_t allocateNode(
+ const char *name, const sp<IOMXObserver> &observer,
+ node_id *node);
+
+ virtual status_t freeNode(node_id node);
+
+ virtual status_t sendCommand(
+ node_id node, OMX_COMMANDTYPE cmd, OMX_S32 param);
+
+ virtual status_t getParameter(
+ node_id node, OMX_INDEXTYPE index,
+ void *params, size_t size);
+
+ virtual status_t setParameter(
+ node_id node, OMX_INDEXTYPE index,
+ const void *params, size_t size);
+
+ virtual status_t getConfig(
+ node_id node, OMX_INDEXTYPE index,
+ void *params, size_t size);
+
+ virtual status_t setConfig(
+ node_id node, OMX_INDEXTYPE index,
+ const void *params, size_t size);
+
+ virtual status_t getState(
+ node_id node, OMX_STATETYPE* state);
+
+ virtual status_t storeMetaDataInBuffers(
+ node_id node, OMX_U32 port_index, OMX_BOOL enable);
+
+ virtual status_t enableGraphicBuffers(
+ node_id node, OMX_U32 port_index, OMX_BOOL enable);
+
+ virtual status_t getGraphicBufferUsage(
+ node_id node, OMX_U32 port_index, OMX_U32* usage);
+
+ virtual status_t useBuffer(
+ node_id node, OMX_U32 port_index, const sp<IMemory> ¶ms,
+ buffer_id *buffer);
+
+ virtual status_t useGraphicBuffer(
+ node_id node, OMX_U32 port_index,
+ const sp<GraphicBuffer> &graphicBuffer, buffer_id *buffer);
+
+ virtual status_t allocateBuffer(
+ node_id node, OMX_U32 port_index, size_t size,
+ buffer_id *buffer, void **buffer_data);
+
+ virtual status_t allocateBufferWithBackup(
+ node_id node, OMX_U32 port_index, const sp<IMemory> ¶ms,
+ buffer_id *buffer);
+
+ virtual status_t freeBuffer(
+ node_id node, OMX_U32 port_index, buffer_id buffer);
+
+ virtual status_t fillBuffer(node_id node, buffer_id buffer);
+
+ virtual status_t emptyBuffer(
+ node_id node,
+ buffer_id buffer,
+ OMX_U32 range_offset, OMX_U32 range_length,
+ OMX_U32 flags, OMX_TICKS timestamp);
+
+ virtual status_t getExtensionIndex(
+ node_id node,
+ const char *parameter_name,
+ OMX_INDEXTYPE *index);
+
+private:
+ mutable Mutex mLock;
+
+ sp<IOMX> mRemoteOMX;
+ sp<IOMX> mLocalOMX;
+
+ KeyedVector<node_id, bool> mIsLocalNode;
+
+ bool isLocalNode(node_id node) const;
+ bool isLocalNode_l(node_id node) const;
+ const sp<IOMX> &getOMX(node_id node) const;
+ const sp<IOMX> &getOMX_l(node_id node) const;
+
+ static bool IsSoftwareComponent(const char *name);
+
+ DISALLOW_EVIL_CONSTRUCTORS(MuxOMX);
+};
+
+MuxOMX::MuxOMX(const sp<IOMX> &remoteOMX)
+ : mRemoteOMX(remoteOMX) {
+}
+
+MuxOMX::~MuxOMX() {
+}
+
+bool MuxOMX::isLocalNode(node_id node) const {
+ Mutex::Autolock autoLock(mLock);
+
+ return isLocalNode_l(node);
+}
+
+bool MuxOMX::isLocalNode_l(node_id node) const {
+ return mIsLocalNode.indexOfKey(node) >= 0;
+}
+
+// static
+bool MuxOMX::IsSoftwareComponent(const char *name) {
+ return !strncasecmp(name, "OMX.google.", 11);
+}
+
+const sp<IOMX> &MuxOMX::getOMX(node_id node) const {
+ return isLocalNode(node) ? mLocalOMX : mRemoteOMX;
+}
+
+const sp<IOMX> &MuxOMX::getOMX_l(node_id node) const {
+ return isLocalNode_l(node) ? mLocalOMX : mRemoteOMX;
+}
+
+bool MuxOMX::livesLocally(node_id node, pid_t pid) {
+ return getOMX(node)->livesLocally(node, pid);
+}
+
+status_t MuxOMX::listNodes(List<ComponentInfo> *list) {
+ Mutex::Autolock autoLock(mLock);
+
+ if (mLocalOMX == NULL) {
+ mLocalOMX = new OMX;
+ }
+
+ return mLocalOMX->listNodes(list);
+}
+
+status_t MuxOMX::allocateNode(
+ const char *name, const sp<IOMXObserver> &observer,
+ node_id *node) {
+ Mutex::Autolock autoLock(mLock);
+
+ sp<IOMX> omx;
+
+ if (IsSoftwareComponent(name)) {
+ if (mLocalOMX == NULL) {
+ mLocalOMX = new OMX;
+ }
+ omx = mLocalOMX;
+ } else {
+ omx = mRemoteOMX;
+ }
+
+ status_t err = omx->allocateNode(name, observer, node);
+
+ if (err != OK) {
+ return err;
+ }
+
+ if (omx == mLocalOMX) {
+ mIsLocalNode.add(*node, true);
+ }
+
+ return OK;
+}
+
+status_t MuxOMX::freeNode(node_id node) {
+ Mutex::Autolock autoLock(mLock);
+
+ status_t err = getOMX_l(node)->freeNode(node);
+
+ if (err != OK) {
+ return err;
+ }
+
+ mIsLocalNode.removeItem(node);
+
+ return OK;
+}
+
+status_t MuxOMX::sendCommand(
+ node_id node, OMX_COMMANDTYPE cmd, OMX_S32 param) {
+ return getOMX(node)->sendCommand(node, cmd, param);
+}
+
+status_t MuxOMX::getParameter(
+ node_id node, OMX_INDEXTYPE index,
+ void *params, size_t size) {
+ return getOMX(node)->getParameter(node, index, params, size);
+}
+
+status_t MuxOMX::setParameter(
+ node_id node, OMX_INDEXTYPE index,
+ const void *params, size_t size) {
+ return getOMX(node)->setParameter(node, index, params, size);
+}
+
+status_t MuxOMX::getConfig(
+ node_id node, OMX_INDEXTYPE index,
+ void *params, size_t size) {
+ return getOMX(node)->getConfig(node, index, params, size);
+}
+
+status_t MuxOMX::setConfig(
+ node_id node, OMX_INDEXTYPE index,
+ const void *params, size_t size) {
+ return getOMX(node)->setConfig(node, index, params, size);
+}
+
+status_t MuxOMX::getState(
+ node_id node, OMX_STATETYPE* state) {
+ return getOMX(node)->getState(node, state);
+}
+
+status_t MuxOMX::storeMetaDataInBuffers(
+ node_id node, OMX_U32 port_index, OMX_BOOL enable) {
+ return getOMX(node)->storeMetaDataInBuffers(node, port_index, enable);
+}
+
+status_t MuxOMX::enableGraphicBuffers(
+ node_id node, OMX_U32 port_index, OMX_BOOL enable) {
+ return getOMX(node)->enableGraphicBuffers(node, port_index, enable);
+}
+
+status_t MuxOMX::getGraphicBufferUsage(
+ node_id node, OMX_U32 port_index, OMX_U32* usage) {
+ return getOMX(node)->getGraphicBufferUsage(node, port_index, usage);
+}
+
+status_t MuxOMX::useBuffer(
+ node_id node, OMX_U32 port_index, const sp<IMemory> ¶ms,
+ buffer_id *buffer) {
+ return getOMX(node)->useBuffer(node, port_index, params, buffer);
+}
+
+status_t MuxOMX::useGraphicBuffer(
+ node_id node, OMX_U32 port_index,
+ const sp<GraphicBuffer> &graphicBuffer, buffer_id *buffer) {
+ return getOMX(node)->useGraphicBuffer(
+ node, port_index, graphicBuffer, buffer);
+}
+
+status_t MuxOMX::allocateBuffer(
+ node_id node, OMX_U32 port_index, size_t size,
+ buffer_id *buffer, void **buffer_data) {
+ return getOMX(node)->allocateBuffer(
+ node, port_index, size, buffer, buffer_data);
+}
+
+status_t MuxOMX::allocateBufferWithBackup(
+ node_id node, OMX_U32 port_index, const sp<IMemory> ¶ms,
+ buffer_id *buffer) {
+ return getOMX(node)->allocateBufferWithBackup(
+ node, port_index, params, buffer);
+}
+
+status_t MuxOMX::freeBuffer(
+ node_id node, OMX_U32 port_index, buffer_id buffer) {
+ return getOMX(node)->freeBuffer(node, port_index, buffer);
+}
+
+status_t MuxOMX::fillBuffer(node_id node, buffer_id buffer) {
+ return getOMX(node)->fillBuffer(node, buffer);
+}
+
+status_t MuxOMX::emptyBuffer(
+ node_id node,
+ buffer_id buffer,
+ OMX_U32 range_offset, OMX_U32 range_length,
+ OMX_U32 flags, OMX_TICKS timestamp) {
+ return getOMX(node)->emptyBuffer(
+ node, buffer, range_offset, range_length, flags, timestamp);
+}
+
+status_t MuxOMX::getExtensionIndex(
+ node_id node,
+ const char *parameter_name,
+ OMX_INDEXTYPE *index) {
+ return getOMX(node)->getExtensionIndex(node, parameter_name, index);
+}
+
OMXClient::OMXClient() {
}
@@ -38,6 +326,11 @@
mOMX = service->getOMX();
CHECK(mOMX.get() != NULL);
+ if (!mOMX->livesLocally(NULL /* node */, getpid())) {
+ ALOGI("Using client-side OMX mux.");
+ mOMX = new MuxOMX(mOMX);
+ }
+
return OK;
}
diff --git a/media/libstagefright/OMXCodec.cpp b/media/libstagefright/OMXCodec.cpp
index 60d9bb7..af4aa79 100755
--- a/media/libstagefright/OMXCodec.cpp
+++ b/media/libstagefright/OMXCodec.cpp
@@ -18,9 +18,6 @@
#define LOG_TAG "OMXCodec"
#include <utils/Log.h>
-#include "include/AACEncoder.h"
-#include "include/AMRNBEncoder.h"
-#include "include/AMRWBEncoder.h"
#include "include/AVCEncoder.h"
#include "include/M4vH263Encoder.h"
@@ -71,9 +68,6 @@
#define FACTORY_REF(name) { #name, Make##name },
-FACTORY_CREATE_ENCODER(AMRNBEncoder)
-FACTORY_CREATE_ENCODER(AMRWBEncoder)
-FACTORY_CREATE_ENCODER(AACEncoder)
FACTORY_CREATE_ENCODER(AVCEncoder)
FACTORY_CREATE_ENCODER(M4vH263Encoder)
@@ -86,9 +80,6 @@
};
static const FactoryInfo kFactoryInfo[] = {
- FACTORY_REF(AMRNBEncoder)
- FACTORY_REF(AMRWBEncoder)
- FACTORY_REF(AACEncoder)
FACTORY_REF(AVCEncoder)
FACTORY_REF(M4vH263Encoder)
};
@@ -149,11 +140,11 @@
static const CodecInfo kEncoderInfo[] = {
{ MEDIA_MIMETYPE_AUDIO_AMR_NB, "OMX.TI.AMR.encode" },
- { MEDIA_MIMETYPE_AUDIO_AMR_NB, "AMRNBEncoder" },
+ { MEDIA_MIMETYPE_AUDIO_AMR_NB, "OMX.google.amrnb.encoder" },
{ MEDIA_MIMETYPE_AUDIO_AMR_WB, "OMX.TI.WBAMR.encode" },
- { MEDIA_MIMETYPE_AUDIO_AMR_WB, "AMRWBEncoder" },
+ { MEDIA_MIMETYPE_AUDIO_AMR_WB, "OMX.google.amrwb.encoder" },
{ MEDIA_MIMETYPE_AUDIO_AAC, "OMX.TI.AAC.encode" },
- { MEDIA_MIMETYPE_AUDIO_AAC, "AACEncoder" },
+ { MEDIA_MIMETYPE_AUDIO_AAC, "OMX.google.aac.encoder" },
{ MEDIA_MIMETYPE_VIDEO_MPEG4, "OMX.TI.DUCATI1.VIDEO.MPEG4E" },
{ MEDIA_MIMETYPE_VIDEO_MPEG4, "OMX.qcom.7x30.video.encoder.mpeg4" },
{ MEDIA_MIMETYPE_VIDEO_MPEG4, "OMX.qcom.video.encoder.mpeg4" },
@@ -1482,11 +1473,12 @@
const sp<MediaSource> &source,
const sp<ANativeWindow> &nativeWindow)
: mOMX(omx),
- mOMXLivesLocally(omx->livesLocally(getpid())),
+ mOMXLivesLocally(omx->livesLocally(node, getpid())),
mNode(node),
mQuirks(quirks),
mFlags(flags),
mIsEncoder(isEncoder),
+ mIsVideo(!strncasecmp("video/", mime, 6)),
mMIME(strdup(mime)),
mComponentName(strdup(componentName)),
mSource(source),
@@ -2192,7 +2184,7 @@
}
int64_t OMXCodec::retrieveDecodingTimeUs(bool isCodecSpecific) {
- CHECK(mIsEncoder);
+ CHECK(mIsEncoder && mIsVideo);
if (mDecodingTimeList.empty()) {
CHECK(mSignalledEOS || mNoMoreOutputData);
@@ -2387,7 +2379,7 @@
mNoMoreOutputData = true;
}
- if (mIsEncoder) {
+ if (mIsEncoder && mIsVideo) {
int64_t decodingTimeUs = retrieveDecodingTimeUs(isCodecSpecific);
buffer->meta_data()->setInt64(kKeyDecodingTime, decodingTimeUs);
}
@@ -3249,7 +3241,7 @@
int64_t lastBufferTimeUs;
CHECK(srcBuffer->meta_data()->findInt64(kKeyTime, &lastBufferTimeUs));
CHECK(lastBufferTimeUs >= 0);
- if (mIsEncoder) {
+ if (mIsEncoder && mIsVideo) {
mDecodingTimeList.push_back(lastBufferTimeUs);
}
diff --git a/media/libstagefright/codecs/aacdec/SoftAAC.cpp b/media/libstagefright/codecs/aacdec/SoftAAC.cpp
index da9d280..ea6c360 100644
--- a/media/libstagefright/codecs/aacdec/SoftAAC.cpp
+++ b/media/libstagefright/codecs/aacdec/SoftAAC.cpp
@@ -218,6 +218,18 @@
return OMX_ErrorNone;
}
+ case OMX_IndexParamAudioPcm:
+ {
+ const OMX_AUDIO_PARAM_PCMMODETYPE *pcmParams =
+ (OMX_AUDIO_PARAM_PCMMODETYPE *)params;
+
+ if (pcmParams->nPortIndex != 1) {
+ return OMX_ErrorUndefined;
+ }
+
+ return OMX_ErrorNone;
+ }
+
default:
return SimpleSoftOMXComponent::internalSetParameter(index, params);
}
diff --git a/media/libstagefright/codecs/aacenc/Android.mk b/media/libstagefright/codecs/aacenc/Android.mk
index 8318ba4..34a2796 100644
--- a/media/libstagefright/codecs/aacenc/Android.mk
+++ b/media/libstagefright/codecs/aacenc/Android.mk
@@ -85,3 +85,29 @@
endif
include $(BUILD_STATIC_LIBRARY)
+
+################################################################################
+
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := \
+ SoftAACEncoder.cpp
+
+LOCAL_C_INCLUDES := \
+ frameworks/base/media/libstagefright/include \
+ frameworks/base/include/media/stagefright/openmax \
+ frameworks/base/media/libstagefright/codecs/common/include \
+
+LOCAL_CFLAGS := -DOSCL_IMPORT_REF=
+
+LOCAL_STATIC_LIBRARIES := \
+ libstagefright_aacenc
+
+LOCAL_SHARED_LIBRARIES := \
+ libstagefright_omx libstagefright_foundation libutils \
+ libstagefright_enc_common
+
+LOCAL_MODULE := libstagefright_soft_aacenc
+LOCAL_MODULE_TAGS := optional
+
+include $(BUILD_SHARED_LIBRARY)
diff --git a/media/libstagefright/codecs/aacenc/SoftAACEncoder.cpp b/media/libstagefright/codecs/aacenc/SoftAACEncoder.cpp
new file mode 100644
index 0000000..c6724c26
--- /dev/null
+++ b/media/libstagefright/codecs/aacenc/SoftAACEncoder.cpp
@@ -0,0 +1,560 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "SoftAACEncoder"
+#include <utils/Log.h>
+
+#include "SoftAACEncoder.h"
+
+#include "voAAC.h"
+#include "cmnMemory.h"
+
+#include <media/stagefright/foundation/ADebug.h>
+#include <media/stagefright/foundation/hexdump.h>
+
+namespace android {
+
+template<class T>
+static void InitOMXParams(T *params) {
+ params->nSize = sizeof(T);
+ params->nVersion.s.nVersionMajor = 1;
+ params->nVersion.s.nVersionMinor = 0;
+ params->nVersion.s.nRevision = 0;
+ params->nVersion.s.nStep = 0;
+}
+
+SoftAACEncoder::SoftAACEncoder(
+ const char *name,
+ const OMX_CALLBACKTYPE *callbacks,
+ OMX_PTR appData,
+ OMX_COMPONENTTYPE **component)
+ : SimpleSoftOMXComponent(name, callbacks, appData, component),
+ mEncoderHandle(NULL),
+ mApiHandle(NULL),
+ mMemOperator(NULL),
+ mNumChannels(1),
+ mSampleRate(44100),
+ mBitRate(0),
+ mSentCodecSpecificData(false),
+ mInputSize(0),
+ mInputFrame(NULL),
+ mInputTimeUs(-1ll),
+ mSawInputEOS(false),
+ mSignalledError(false) {
+ initPorts();
+ CHECK_EQ(initEncoder(), (status_t)OK);
+
+ setAudioParams();
+}
+
+SoftAACEncoder::~SoftAACEncoder() {
+ delete[] mInputFrame;
+ mInputFrame = NULL;
+
+ if (mEncoderHandle) {
+ CHECK_EQ(VO_ERR_NONE, mApiHandle->Uninit(mEncoderHandle));
+ mEncoderHandle = NULL;
+ }
+
+ delete mApiHandle;
+ mApiHandle = NULL;
+
+ delete mMemOperator;
+ mMemOperator = NULL;
+}
+
+void SoftAACEncoder::initPorts() {
+ OMX_PARAM_PORTDEFINITIONTYPE def;
+ InitOMXParams(&def);
+
+ def.nPortIndex = 0;
+ def.eDir = OMX_DirInput;
+ def.nBufferCountMin = kNumBuffers;
+ def.nBufferCountActual = def.nBufferCountMin;
+ def.nBufferSize = kNumSamplesPerFrame * sizeof(int16_t) * 2;
+ def.bEnabled = OMX_TRUE;
+ def.bPopulated = OMX_FALSE;
+ def.eDomain = OMX_PortDomainAudio;
+ def.bBuffersContiguous = OMX_FALSE;
+ def.nBufferAlignment = 1;
+
+ def.format.audio.cMIMEType = const_cast<char *>("audio/raw");
+ def.format.audio.pNativeRender = NULL;
+ def.format.audio.bFlagErrorConcealment = OMX_FALSE;
+ def.format.audio.eEncoding = OMX_AUDIO_CodingPCM;
+
+ addPort(def);
+
+ def.nPortIndex = 1;
+ def.eDir = OMX_DirOutput;
+ def.nBufferCountMin = kNumBuffers;
+ def.nBufferCountActual = def.nBufferCountMin;
+ def.nBufferSize = 8192;
+ def.bEnabled = OMX_TRUE;
+ def.bPopulated = OMX_FALSE;
+ def.eDomain = OMX_PortDomainAudio;
+ def.bBuffersContiguous = OMX_FALSE;
+ def.nBufferAlignment = 2;
+
+ def.format.audio.cMIMEType = const_cast<char *>("audio/aac");
+ def.format.audio.pNativeRender = NULL;
+ def.format.audio.bFlagErrorConcealment = OMX_FALSE;
+ def.format.audio.eEncoding = OMX_AUDIO_CodingAAC;
+
+ addPort(def);
+}
+
+status_t SoftAACEncoder::initEncoder() {
+ mApiHandle = new VO_AUDIO_CODECAPI;
+
+ if (VO_ERR_NONE != voGetAACEncAPI(mApiHandle)) {
+ ALOGE("Failed to get api handle");
+ return UNKNOWN_ERROR;
+ }
+
+ mMemOperator = new VO_MEM_OPERATOR;
+ mMemOperator->Alloc = cmnMemAlloc;
+ mMemOperator->Copy = cmnMemCopy;
+ mMemOperator->Free = cmnMemFree;
+ mMemOperator->Set = cmnMemSet;
+ mMemOperator->Check = cmnMemCheck;
+
+ VO_CODEC_INIT_USERDATA userData;
+ memset(&userData, 0, sizeof(userData));
+ userData.memflag = VO_IMF_USERMEMOPERATOR;
+ userData.memData = (VO_PTR) mMemOperator;
+ if (VO_ERR_NONE !=
+ mApiHandle->Init(&mEncoderHandle, VO_AUDIO_CodingAAC, &userData)) {
+ ALOGE("Failed to init AAC encoder");
+ return UNKNOWN_ERROR;
+ }
+
+ return OK;
+}
+
+OMX_ERRORTYPE SoftAACEncoder::internalGetParameter(
+ OMX_INDEXTYPE index, OMX_PTR params) {
+ switch (index) {
+ case OMX_IndexParamAudioPortFormat:
+ {
+ OMX_AUDIO_PARAM_PORTFORMATTYPE *formatParams =
+ (OMX_AUDIO_PARAM_PORTFORMATTYPE *)params;
+
+ if (formatParams->nPortIndex > 1) {
+ return OMX_ErrorUndefined;
+ }
+
+ if (formatParams->nIndex > 0) {
+ return OMX_ErrorNoMore;
+ }
+
+ formatParams->eEncoding =
+ (formatParams->nPortIndex == 0)
+ ? OMX_AUDIO_CodingPCM : OMX_AUDIO_CodingAAC;
+
+ return OMX_ErrorNone;
+ }
+
+ case OMX_IndexParamAudioAac:
+ {
+ OMX_AUDIO_PARAM_AACPROFILETYPE *aacParams =
+ (OMX_AUDIO_PARAM_AACPROFILETYPE *)params;
+
+ if (aacParams->nPortIndex != 1) {
+ return OMX_ErrorUndefined;
+ }
+
+ aacParams->nBitRate = mBitRate;
+ aacParams->nAudioBandWidth = 0;
+ aacParams->nAACtools = 0;
+ aacParams->nAACERtools = 0;
+ aacParams->eAACProfile = OMX_AUDIO_AACObjectMain;
+ aacParams->eAACStreamFormat = OMX_AUDIO_AACStreamFormatMP4FF;
+ aacParams->eChannelMode = OMX_AUDIO_ChannelModeStereo;
+
+ aacParams->nChannels = mNumChannels;
+ aacParams->nSampleRate = mSampleRate;
+ aacParams->nFrameLength = 0;
+
+ return OMX_ErrorNone;
+ }
+
+ case OMX_IndexParamAudioPcm:
+ {
+ OMX_AUDIO_PARAM_PCMMODETYPE *pcmParams =
+ (OMX_AUDIO_PARAM_PCMMODETYPE *)params;
+
+ if (pcmParams->nPortIndex != 0) {
+ return OMX_ErrorUndefined;
+ }
+
+ pcmParams->eNumData = OMX_NumericalDataSigned;
+ pcmParams->eEndian = OMX_EndianBig;
+ pcmParams->bInterleaved = OMX_TRUE;
+ pcmParams->nBitPerSample = 16;
+ pcmParams->ePCMMode = OMX_AUDIO_PCMModeLinear;
+ pcmParams->eChannelMapping[0] = OMX_AUDIO_ChannelLF;
+ pcmParams->eChannelMapping[1] = OMX_AUDIO_ChannelRF;
+
+ pcmParams->nChannels = mNumChannels;
+ pcmParams->nSamplingRate = mSampleRate;
+
+ return OMX_ErrorNone;
+ }
+
+ default:
+ return SimpleSoftOMXComponent::internalGetParameter(index, params);
+ }
+}
+
+OMX_ERRORTYPE SoftAACEncoder::internalSetParameter(
+ OMX_INDEXTYPE index, const OMX_PTR params) {
+ switch (index) {
+ case OMX_IndexParamStandardComponentRole:
+ {
+ const OMX_PARAM_COMPONENTROLETYPE *roleParams =
+ (const OMX_PARAM_COMPONENTROLETYPE *)params;
+
+ if (strncmp((const char *)roleParams->cRole,
+ "audio_encoder.aac",
+ OMX_MAX_STRINGNAME_SIZE - 1)) {
+ return OMX_ErrorUndefined;
+ }
+
+ return OMX_ErrorNone;
+ }
+
+ case OMX_IndexParamAudioPortFormat:
+ {
+ const OMX_AUDIO_PARAM_PORTFORMATTYPE *formatParams =
+ (const OMX_AUDIO_PARAM_PORTFORMATTYPE *)params;
+
+ if (formatParams->nPortIndex > 1) {
+ return OMX_ErrorUndefined;
+ }
+
+ if (formatParams->nIndex > 0) {
+ return OMX_ErrorNoMore;
+ }
+
+ if ((formatParams->nPortIndex == 0
+ && formatParams->eEncoding != OMX_AUDIO_CodingPCM)
+ || (formatParams->nPortIndex == 1
+ && formatParams->eEncoding != OMX_AUDIO_CodingAAC)) {
+ return OMX_ErrorUndefined;
+ }
+
+ return OMX_ErrorNone;
+ }
+
+ case OMX_IndexParamAudioAac:
+ {
+ OMX_AUDIO_PARAM_AACPROFILETYPE *aacParams =
+ (OMX_AUDIO_PARAM_AACPROFILETYPE *)params;
+
+ if (aacParams->nPortIndex != 1) {
+ return OMX_ErrorUndefined;
+ }
+
+ mBitRate = aacParams->nBitRate;
+ mNumChannels = aacParams->nChannels;
+ mSampleRate = aacParams->nSampleRate;
+
+ if (setAudioParams() != OK) {
+ return OMX_ErrorUndefined;
+ }
+
+ return OMX_ErrorNone;
+ }
+
+ case OMX_IndexParamAudioPcm:
+ {
+ OMX_AUDIO_PARAM_PCMMODETYPE *pcmParams =
+ (OMX_AUDIO_PARAM_PCMMODETYPE *)params;
+
+ if (pcmParams->nPortIndex != 0) {
+ return OMX_ErrorUndefined;
+ }
+
+ mNumChannels = pcmParams->nChannels;
+ mSampleRate = pcmParams->nSamplingRate;
+
+ if (setAudioParams() != OK) {
+ return OMX_ErrorUndefined;
+ }
+
+ return OMX_ErrorNone;
+ }
+
+
+ default:
+ return SimpleSoftOMXComponent::internalSetParameter(index, params);
+ }
+}
+
+status_t SoftAACEncoder::setAudioParams() {
+ // We call this whenever sample rate, number of channels or bitrate change
+ // in reponse to setParameter calls.
+
+ ALOGV("setAudioParams: %lu Hz, %lu channels, %lu bps",
+ mSampleRate, mNumChannels, mBitRate);
+
+ status_t err = setAudioSpecificConfigData();
+
+ if (err != OK) {
+ return err;
+ }
+
+ AACENC_PARAM params;
+ memset(¶ms, 0, sizeof(params));
+ params.sampleRate = mSampleRate;
+ params.bitRate = mBitRate;
+ params.nChannels = mNumChannels;
+ params.adtsUsed = 0; // We add adts header in the file writer if needed.
+ if (VO_ERR_NONE != mApiHandle->SetParam(
+ mEncoderHandle, VO_PID_AAC_ENCPARAM, ¶ms)) {
+ ALOGE("Failed to set AAC encoder parameters");
+ return UNKNOWN_ERROR;
+ }
+
+ return OK;
+}
+
+static status_t getSampleRateTableIndex(int32_t sampleRate, int32_t &index) {
+ static const int32_t kSampleRateTable[] = {
+ 96000, 88200, 64000, 48000, 44100, 32000,
+ 24000, 22050, 16000, 12000, 11025, 8000
+ };
+ const int32_t tableSize =
+ sizeof(kSampleRateTable) / sizeof(kSampleRateTable[0]);
+
+ for (int32_t i = 0; i < tableSize; ++i) {
+ if (sampleRate == kSampleRateTable[i]) {
+ index = i;
+ return OK;
+ }
+ }
+
+ return UNKNOWN_ERROR;
+}
+
+status_t SoftAACEncoder::setAudioSpecificConfigData() {
+ // The AAC encoder's audio specific config really only encodes
+ // number of channels and the sample rate (mapped to an index into
+ // a fixed sample rate table).
+
+ int32_t index;
+ status_t err = getSampleRateTableIndex(mSampleRate, index);
+ if (err != OK) {
+ ALOGE("Unsupported sample rate (%lu Hz)", mSampleRate);
+ return err;
+ }
+
+ if (mNumChannels > 2 || mNumChannels <= 0) {
+ ALOGE("Unsupported number of channels(%lu)", mNumChannels);
+ return UNKNOWN_ERROR;
+ }
+
+ // OMX_AUDIO_AACObjectLC
+ mAudioSpecificConfigData[0] = ((0x02 << 3) | (index >> 1));
+ mAudioSpecificConfigData[1] = ((index & 0x01) << 7) | (mNumChannels << 3);
+
+ return OK;
+}
+
+void SoftAACEncoder::onQueueFilled(OMX_U32 portIndex) {
+ if (mSignalledError) {
+ return;
+ }
+
+ List<BufferInfo *> &inQueue = getPortQueue(0);
+ List<BufferInfo *> &outQueue = getPortQueue(1);
+
+ if (!mSentCodecSpecificData) {
+ // The very first thing we want to output is the codec specific
+ // data. It does not require any input data but we will need an
+ // output buffer to store it in.
+
+ if (outQueue.empty()) {
+ return;
+ }
+
+ BufferInfo *outInfo = *outQueue.begin();
+ OMX_BUFFERHEADERTYPE *outHeader = outInfo->mHeader;
+ outHeader->nFilledLen = sizeof(mAudioSpecificConfigData);
+ outHeader->nFlags = OMX_BUFFERFLAG_CODECCONFIG;
+
+ uint8_t *out = outHeader->pBuffer + outHeader->nOffset;
+ memcpy(out, mAudioSpecificConfigData, sizeof(mAudioSpecificConfigData));
+
+#if 0
+ ALOGI("sending codec specific data.");
+ hexdump(out, sizeof(mAudioSpecificConfigData));
+#endif
+
+ outQueue.erase(outQueue.begin());
+ outInfo->mOwnedByUs = false;
+ notifyFillBufferDone(outHeader);
+
+ mSentCodecSpecificData = true;
+ }
+
+ size_t numBytesPerInputFrame =
+ mNumChannels * kNumSamplesPerFrame * sizeof(int16_t);
+
+ for (;;) {
+ // We do the following until we run out of buffers.
+
+ while (mInputSize < numBytesPerInputFrame) {
+ // As long as there's still input data to be read we
+ // will drain "kNumSamplesPerFrame * mNumChannels" samples
+ // into the "mInputFrame" buffer and then encode those
+ // as a unit into an output buffer.
+
+ if (mSawInputEOS || inQueue.empty()) {
+ return;
+ }
+
+ BufferInfo *inInfo = *inQueue.begin();
+ OMX_BUFFERHEADERTYPE *inHeader = inInfo->mHeader;
+
+ const void *inData = inHeader->pBuffer + inHeader->nOffset;
+
+ size_t copy = numBytesPerInputFrame - mInputSize;
+ if (copy > inHeader->nFilledLen) {
+ copy = inHeader->nFilledLen;
+ }
+
+ if (mInputFrame == NULL) {
+ mInputFrame = new int16_t[kNumSamplesPerFrame * mNumChannels];
+ }
+
+ if (mInputSize == 0) {
+ mInputTimeUs = inHeader->nTimeStamp;
+ }
+
+ memcpy((uint8_t *)mInputFrame + mInputSize, inData, copy);
+ mInputSize += copy;
+
+ inHeader->nOffset += copy;
+ inHeader->nFilledLen -= copy;
+
+ // "Time" on the input buffer has in effect advanced by the
+ // number of audio frames we just advanced nOffset by.
+ inHeader->nTimeStamp +=
+ (copy * 1000000ll / mSampleRate)
+ / (mNumChannels * sizeof(int16_t));
+
+ if (inHeader->nFilledLen == 0) {
+ if (inHeader->nFlags & OMX_BUFFERFLAG_EOS) {
+ ALOGV("saw input EOS");
+ mSawInputEOS = true;
+
+ // Pad any remaining data with zeroes.
+ memset((uint8_t *)mInputFrame + mInputSize,
+ 0,
+ numBytesPerInputFrame - mInputSize);
+
+ mInputSize = numBytesPerInputFrame;
+ }
+
+ inQueue.erase(inQueue.begin());
+ inInfo->mOwnedByUs = false;
+ notifyEmptyBufferDone(inHeader);
+
+ inData = NULL;
+ inHeader = NULL;
+ inInfo = NULL;
+ }
+ }
+
+ // At this point we have all the input data necessary to encode
+ // a single frame, all we need is an output buffer to store the result
+ // in.
+
+ if (outQueue.empty()) {
+ return;
+ }
+
+ BufferInfo *outInfo = *outQueue.begin();
+ OMX_BUFFERHEADERTYPE *outHeader = outInfo->mHeader;
+
+ VO_CODECBUFFER inputData;
+ memset(&inputData, 0, sizeof(inputData));
+ inputData.Buffer = (unsigned char *)mInputFrame;
+ inputData.Length = numBytesPerInputFrame;
+ CHECK(VO_ERR_NONE ==
+ mApiHandle->SetInputData(mEncoderHandle, &inputData));
+
+ VO_CODECBUFFER outputData;
+ memset(&outputData, 0, sizeof(outputData));
+ VO_AUDIO_OUTPUTINFO outputInfo;
+ memset(&outputInfo, 0, sizeof(outputInfo));
+
+ uint8_t *outPtr = (uint8_t *)outHeader->pBuffer + outHeader->nOffset;
+ size_t outAvailable = outHeader->nAllocLen - outHeader->nOffset;
+
+ VO_U32 ret = VO_ERR_NONE;
+ size_t nOutputBytes = 0;
+ do {
+ outputData.Buffer = outPtr;
+ outputData.Length = outAvailable - nOutputBytes;
+ ret = mApiHandle->GetOutputData(
+ mEncoderHandle, &outputData, &outputInfo);
+ if (ret == VO_ERR_NONE) {
+ outPtr += outputData.Length;
+ nOutputBytes += outputData.Length;
+ }
+ } while (ret != VO_ERR_INPUT_BUFFER_SMALL);
+
+ outHeader->nFilledLen = nOutputBytes;
+
+ outHeader->nFlags = OMX_BUFFERFLAG_ENDOFFRAME;
+
+ if (mSawInputEOS) {
+ // We also tag this output buffer with EOS if it corresponds
+ // to the final input buffer.
+ outHeader->nFlags = OMX_BUFFERFLAG_EOS;
+ }
+
+ outHeader->nTimeStamp = mInputTimeUs;
+
+#if 0
+ ALOGI("sending %d bytes of data (time = %lld us, flags = 0x%08lx)",
+ nOutputBytes, mInputTimeUs, outHeader->nFlags);
+
+ hexdump(outHeader->pBuffer + outHeader->nOffset, outHeader->nFilledLen);
+#endif
+
+ outQueue.erase(outQueue.begin());
+ outInfo->mOwnedByUs = false;
+ notifyFillBufferDone(outHeader);
+
+ outHeader = NULL;
+ outInfo = NULL;
+
+ mInputSize = 0;
+ }
+}
+
+} // namespace android
+
+android::SoftOMXComponent *createSoftOMXComponent(
+ const char *name, const OMX_CALLBACKTYPE *callbacks,
+ OMX_PTR appData, OMX_COMPONENTTYPE **component) {
+ return new android::SoftAACEncoder(name, callbacks, appData, component);
+}
diff --git a/media/libstagefright/codecs/aacenc/SoftAACEncoder.h b/media/libstagefright/codecs/aacenc/SoftAACEncoder.h
new file mode 100644
index 0000000..d148eb7
--- /dev/null
+++ b/media/libstagefright/codecs/aacenc/SoftAACEncoder.h
@@ -0,0 +1,82 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef SOFT_AAC_ENCODER_H_
+
+#define SOFT_AAC_ENCODER_H_
+
+#include "SimpleSoftOMXComponent.h"
+
+struct VO_AUDIO_CODECAPI;
+struct VO_MEM_OPERATOR;
+
+namespace android {
+
+struct SoftAACEncoder : public SimpleSoftOMXComponent {
+ SoftAACEncoder(
+ const char *name,
+ const OMX_CALLBACKTYPE *callbacks,
+ OMX_PTR appData,
+ OMX_COMPONENTTYPE **component);
+
+protected:
+ virtual ~SoftAACEncoder();
+
+ virtual OMX_ERRORTYPE internalGetParameter(
+ OMX_INDEXTYPE index, OMX_PTR params);
+
+ virtual OMX_ERRORTYPE internalSetParameter(
+ OMX_INDEXTYPE index, const OMX_PTR params);
+
+ virtual void onQueueFilled(OMX_U32 portIndex);
+
+private:
+ enum {
+ kNumBuffers = 4,
+ kNumSamplesPerFrame = 1024,
+ };
+
+ void *mEncoderHandle;
+ VO_AUDIO_CODECAPI *mApiHandle;
+ VO_MEM_OPERATOR *mMemOperator;
+
+ OMX_U32 mNumChannels;
+ OMX_U32 mSampleRate;
+ OMX_U32 mBitRate;
+
+ bool mSentCodecSpecificData;
+ size_t mInputSize;
+ int16_t *mInputFrame;
+ int64_t mInputTimeUs;
+
+ bool mSawInputEOS;
+
+ uint8_t mAudioSpecificConfigData[2];
+
+ bool mSignalledError;
+
+ void initPorts();
+ status_t initEncoder();
+
+ status_t setAudioSpecificConfigData();
+ status_t setAudioParams();
+
+ DISALLOW_EVIL_CONSTRUCTORS(SoftAACEncoder);
+};
+
+} // namespace android
+
+#endif // SOFT_AAC_ENCODER_H_
diff --git a/media/libstagefright/codecs/aacenc/basic_op/oper_32b.c b/media/libstagefright/codecs/aacenc/basic_op/oper_32b.c
index e48af9d..982f4fd 100644
--- a/media/libstagefright/codecs/aacenc/basic_op/oper_32b.c
+++ b/media/libstagefright/codecs/aacenc/basic_op/oper_32b.c
@@ -358,4 +358,4 @@
res = pow2Table[(POW2_TABLE_SIZE*fPart)/y] >> iPart;
return(res);
-}
\ No newline at end of file
+}
diff --git a/media/libstagefright/codecs/aacenc/basic_op/typedefs.h b/media/libstagefright/codecs/aacenc/basic_op/typedefs.h
index c924e2c..2d5d956 100644
--- a/media/libstagefright/codecs/aacenc/basic_op/typedefs.h
+++ b/media/libstagefright/codecs/aacenc/basic_op/typedefs.h
@@ -77,12 +77,12 @@
/*
********* define 32 bit signed/unsigned types & constants
*/
-typedef long Word32;
-typedef unsigned long UWord32;
+typedef int Word32;
+typedef unsigned int UWord32;
-#ifdef LINUX
+#ifndef _MSC_VER
typedef long long Word64;
typedef unsigned long long UWord64;
#else
diff --git a/media/libstagefright/codecs/aacenc/inc/config.h b/media/libstagefright/codecs/aacenc/inc/config.h
index 3b29cef..b0b4c26 100644
--- a/media/libstagefright/codecs/aacenc/inc/config.h
+++ b/media/libstagefright/codecs/aacenc/inc/config.h
@@ -33,4 +33,4 @@
#define MINBITS_COEF 744
-#endif
\ No newline at end of file
+#endif
diff --git a/media/libstagefright/codecs/aacenc/inc/sf_estim.h b/media/libstagefright/codecs/aacenc/inc/sf_estim.h
index 9039f25..997eba5 100644
--- a/media/libstagefright/codecs/aacenc/inc/sf_estim.h
+++ b/media/libstagefright/codecs/aacenc/inc/sf_estim.h
@@ -43,4 +43,4 @@
Word16 logSfbFormFactor[MAX_CHANNELS][MAX_GROUPED_SFB],
Word16 sfbNRelevantLines[MAX_CHANNELS][MAX_GROUPED_SFB],
const Word16 nChannels);
-#endif
\ No newline at end of file
+#endif
diff --git a/media/libstagefright/codecs/aacenc/inc/transform.h b/media/libstagefright/codecs/aacenc/inc/transform.h
index fbac7aa..311cef5 100644
--- a/media/libstagefright/codecs/aacenc/inc/transform.h
+++ b/media/libstagefright/codecs/aacenc/inc/transform.h
@@ -33,4 +33,4 @@
Word16 windowSequence
);
-#endif
\ No newline at end of file
+#endif
diff --git a/media/libstagefright/codecs/aacenc/src/aac_rom.c b/media/libstagefright/codecs/aacenc/src/aac_rom.c
index 08792e8..127322d 100644
--- a/media/libstagefright/codecs/aacenc/src/aac_rom.c
+++ b/media/libstagefright/codecs/aacenc/src/aac_rom.c
@@ -2360,4 +2360,4 @@
0x4d, 0x59, 0x4f, 0x79, 0x53, 0x65, 0x57, 0x75, 0x5b, 0x6d, 0x5f, 0x7d, 0x67, 0x73, 0x6f, 0x7b,
0x00, 0x08, 0x14, 0x1c, 0x22, 0x2a, 0x36, 0x3e, 0x41, 0x49, 0x55, 0x5d, 0x63, 0x6b, 0x77, 0x7f,
0x00,
-};
\ No newline at end of file
+};
diff --git a/media/libstagefright/codecs/aacenc/src/aacenc.c b/media/libstagefright/codecs/aacenc/src/aacenc.c
index b5e8a9c..ad2f29a 100644
--- a/media/libstagefright/codecs/aacenc/src/aacenc.c
+++ b/media/libstagefright/codecs/aacenc/src/aacenc.c
@@ -492,4 +492,4 @@
pDecHandle->Uninit = voAACEncUninit;
return VO_ERR_NONE;
-}
\ No newline at end of file
+}
diff --git a/media/libstagefright/codecs/aacenc/src/adj_thr.c b/media/libstagefright/codecs/aacenc/src/adj_thr.c
index c656f65..a8ab809 100644
--- a/media/libstagefright/codecs/aacenc/src/adj_thr.c
+++ b/media/libstagefright/codecs/aacenc/src/adj_thr.c
@@ -1039,7 +1039,7 @@
/* minSnr adaptation */
/* maximum reduction of minSnr goes down to minSnr^maxRed */
- msaParam->maxRed = 0x20000000; /* *0.25f /
+ msaParam->maxRed = 0x20000000; /* *0.25f */
/* start adaptation of minSnr for avgEn/sfbEn > startRatio */
msaParam->startRatio = 0x0ccccccd; /* 10 */
/* maximum minSnr reduction to minSnr^maxRed is reached for
diff --git a/media/libstagefright/codecs/aacenc/src/asm/ARMV5E/PrePostMDCT_v5.s b/media/libstagefright/codecs/aacenc/src/asm/ARMV5E/PrePostMDCT_v5.s
index 103cc91..da21d5f 100644
--- a/media/libstagefright/codecs/aacenc/src/asm/ARMV5E/PrePostMDCT_v5.s
+++ b/media/libstagefright/codecs/aacenc/src/asm/ARMV5E/PrePostMDCT_v5.s
@@ -128,4 +128,4 @@
PostMDCT_END:
ldmia sp!, {r4 - r11, pc}
@ENDP @ |PostMDCT|
- .end
\ No newline at end of file
+ .end
diff --git a/media/libstagefright/codecs/aacenc/src/asm/ARMV5E/R4R8First_v5.s b/media/libstagefright/codecs/aacenc/src/asm/ARMV5E/R4R8First_v5.s
index 72cb9a3..4ca4f31 100644
--- a/media/libstagefright/codecs/aacenc/src/asm/ARMV5E/R4R8First_v5.s
+++ b/media/libstagefright/codecs/aacenc/src/asm/ARMV5E/R4R8First_v5.s
@@ -249,4 +249,4 @@
.word 0x5a82799a
@ENDP @ |Radix8First|
- .end
\ No newline at end of file
+ .end
diff --git a/media/libstagefright/codecs/aacenc/src/asm/ARMV5E/Radix4FFT_v5.s b/media/libstagefright/codecs/aacenc/src/asm/ARMV5E/Radix4FFT_v5.s
index e81c82e..b59b967 100644
--- a/media/libstagefright/codecs/aacenc/src/asm/ARMV5E/Radix4FFT_v5.s
+++ b/media/libstagefright/codecs/aacenc/src/asm/ARMV5E/Radix4FFT_v5.s
@@ -166,4 +166,4 @@
ldmia sp!, {r4 - r11, pc}
@ENDP @ |Radix4FFT|
- .end
\ No newline at end of file
+ .end
diff --git a/media/libstagefright/codecs/aacenc/src/asm/ARMV7/PrePostMDCT_v7.s b/media/libstagefright/codecs/aacenc/src/asm/ARMV7/PrePostMDCT_v7.s
index 64d767a..7f6b881 100644
--- a/media/libstagefright/codecs/aacenc/src/asm/ARMV7/PrePostMDCT_v7.s
+++ b/media/libstagefright/codecs/aacenc/src/asm/ARMV7/PrePostMDCT_v7.s
@@ -23,9 +23,13 @@
.section .text
.global PreMDCT
+ .fnstart
PreMDCT:
stmdb sp!, {r4 - r11, lr}
+ .save {r4 - r11, lr}
+ fstmfdd sp!, {d8 - d15}
+ .vsave {d8 - d15}
add r9, r0, r1, lsl #2
sub r3, r9, #32
@@ -74,14 +78,20 @@
bne PreMDCT_LOOP
PreMDCT_END:
+ fldmfdd sp!, {d8 - d15}
ldmia sp!, {r4 - r11, pc}
@ENDP @ |PreMDCT|
+ .fnend
.section .text
.global PostMDCT
+ .fnstart
PostMDCT:
stmdb sp!, {r4 - r11, lr}
+ .save {r4 - r11, lr}
+ fstmfdd sp!, {d8 - d15}
+ .vsave {d8 - d15}
add r9, r0, r1, lsl #2
sub r3, r9, #32
@@ -129,7 +139,8 @@
bne PostMDCT_LOOP
PostMDCT_END:
+ fldmfdd sp!, {d8 - d15}
ldmia sp!, {r4 - r11, pc}
@ENDP @ |PostMDCT|
- .end
\ No newline at end of file
+ .fnend
diff --git a/media/libstagefright/codecs/aacenc/src/asm/ARMV7/R4R8First_v7.s b/media/libstagefright/codecs/aacenc/src/asm/ARMV7/R4R8First_v7.s
index 7fc5520..03fa6a9 100644
--- a/media/libstagefright/codecs/aacenc/src/asm/ARMV7/R4R8First_v7.s
+++ b/media/libstagefright/codecs/aacenc/src/asm/ARMV7/R4R8First_v7.s
@@ -23,9 +23,13 @@
.section .text
.global Radix8First
+ .fnstart
Radix8First:
stmdb sp!, {r4 - r11, lr}
+ .save {r4 - r11, lr}
+ fstmfdd sp!, {d8 - d15}
+ .vsave {d8 - d15}
ldr r3, SQRT1_2
cmp r1, #0
@@ -103,17 +107,23 @@
bne Radix8First_LOOP
Radix8First_END:
+ fldmfdd sp!, {d8 - d15}
ldmia sp!, {r4 - r11, pc}
SQRT1_2:
.word 0x2d413ccd
@ENDP @ |Radix8First|
+ .fnend
.section .text
.global Radix4First
+ .fnstart
Radix4First:
stmdb sp!, {r4 - r11, lr}
+ .save {r4 - r11, lr}
+ fstmfdd sp!, {d8 - d15}
+ .vsave {d8 - d15}
cmp r1, #0
beq Radix4First_END
@@ -140,7 +150,8 @@
bne Radix4First_LOOP
Radix4First_END:
+ fldmfdd sp!, {d8 - d15}
ldmia sp!, {r4 - r11, pc}
@ENDP @ |Radix4First|
- .end
\ No newline at end of file
+ .fnend
diff --git a/media/libstagefright/codecs/aacenc/src/asm/ARMV7/Radix4FFT_v7.s b/media/libstagefright/codecs/aacenc/src/asm/ARMV7/Radix4FFT_v7.s
index b8655ae..431bc30 100644
--- a/media/libstagefright/codecs/aacenc/src/asm/ARMV7/Radix4FFT_v7.s
+++ b/media/libstagefright/codecs/aacenc/src/asm/ARMV7/Radix4FFT_v7.s
@@ -23,9 +23,13 @@
.section .text
.global Radix4FFT
+ .fnstart
Radix4FFT:
stmdb sp!, {r4 - r11, lr}
+ .save {r4 - r11, lr}
+ fstmfdd sp!, {d8 - d15}
+ .vsave {d8 - d15}
mov r1, r1, asr #2
cmp r1, #0
@@ -137,7 +141,8 @@
bne Radix4FFT_LOOP1
Radix4FFT_END:
+ fldmfdd sp!, {d8 - d15}
ldmia sp!, {r4 - r11, pc}
@ENDP @ |Radix4FFT|
- .end
\ No newline at end of file
+ .fnend
diff --git a/media/libstagefright/codecs/aacenc/src/band_nrg.c b/media/libstagefright/codecs/aacenc/src/band_nrg.c
index 7501af1..e4034b8 100644
--- a/media/libstagefright/codecs/aacenc/src/band_nrg.c
+++ b/media/libstagefright/codecs/aacenc/src/band_nrg.c
@@ -99,4 +99,4 @@
*bandEnergySideSum = accuSideSum;
}
-#endif
\ No newline at end of file
+#endif
diff --git a/media/libstagefright/codecs/amrnb/enc/Android.mk b/media/libstagefright/codecs/amrnb/enc/Android.mk
index b6aed81..94e8726 100644
--- a/media/libstagefright/codecs/amrnb/enc/Android.mk
+++ b/media/libstagefright/codecs/amrnb/enc/Android.mk
@@ -74,3 +74,30 @@
LOCAL_MODULE := libstagefright_amrnbenc
include $(BUILD_STATIC_LIBRARY)
+
+################################################################################
+
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := \
+ SoftAMRNBEncoder.cpp
+
+LOCAL_C_INCLUDES := \
+ frameworks/base/media/libstagefright/include \
+ frameworks/base/include/media/stagefright/openmax \
+ $(LOCAL_PATH)/src \
+ $(LOCAL_PATH)/include \
+ $(LOCAL_PATH)/../common/include \
+ $(LOCAL_PATH)/../common
+
+LOCAL_STATIC_LIBRARIES := \
+ libstagefright_amrnbenc
+
+LOCAL_SHARED_LIBRARIES := \
+ libstagefright_omx libstagefright_foundation libutils \
+ libstagefright_amrnb_common
+
+LOCAL_MODULE := libstagefright_soft_amrnbenc
+LOCAL_MODULE_TAGS := optional
+
+include $(BUILD_SHARED_LIBRARY)
diff --git a/media/libstagefright/codecs/amrnb/enc/SoftAMRNBEncoder.cpp b/media/libstagefright/codecs/amrnb/enc/SoftAMRNBEncoder.cpp
new file mode 100644
index 0000000..07f8b4f
--- /dev/null
+++ b/media/libstagefright/codecs/amrnb/enc/SoftAMRNBEncoder.cpp
@@ -0,0 +1,404 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "SoftAMRNBEncoder"
+#include <utils/Log.h>
+
+#include "SoftAMRNBEncoder.h"
+
+#include "gsmamr_enc.h"
+
+#include <media/stagefright/foundation/ADebug.h>
+#include <media/stagefright/foundation/hexdump.h>
+
+namespace android {
+
+static const int32_t kSampleRate = 8000;
+
+template<class T>
+static void InitOMXParams(T *params) {
+ params->nSize = sizeof(T);
+ params->nVersion.s.nVersionMajor = 1;
+ params->nVersion.s.nVersionMinor = 0;
+ params->nVersion.s.nRevision = 0;
+ params->nVersion.s.nStep = 0;
+}
+
+SoftAMRNBEncoder::SoftAMRNBEncoder(
+ const char *name,
+ const OMX_CALLBACKTYPE *callbacks,
+ OMX_PTR appData,
+ OMX_COMPONENTTYPE **component)
+ : SimpleSoftOMXComponent(name, callbacks, appData, component),
+ mEncState(NULL),
+ mSidState(NULL),
+ mBitRate(0),
+ mMode(MR475),
+ mInputSize(0),
+ mInputTimeUs(-1ll),
+ mSawInputEOS(false),
+ mSignalledError(false) {
+ initPorts();
+ CHECK_EQ(initEncoder(), (status_t)OK);
+}
+
+SoftAMRNBEncoder::~SoftAMRNBEncoder() {
+ if (mEncState != NULL) {
+ AMREncodeExit(&mEncState, &mSidState);
+ mEncState = mSidState = NULL;
+ }
+}
+
+void SoftAMRNBEncoder::initPorts() {
+ OMX_PARAM_PORTDEFINITIONTYPE def;
+ InitOMXParams(&def);
+
+ def.nPortIndex = 0;
+ def.eDir = OMX_DirInput;
+ def.nBufferCountMin = kNumBuffers;
+ def.nBufferCountActual = def.nBufferCountMin;
+ def.nBufferSize = kNumSamplesPerFrame * sizeof(int16_t);
+ def.bEnabled = OMX_TRUE;
+ def.bPopulated = OMX_FALSE;
+ def.eDomain = OMX_PortDomainAudio;
+ def.bBuffersContiguous = OMX_FALSE;
+ def.nBufferAlignment = 1;
+
+ def.format.audio.cMIMEType = const_cast<char *>("audio/raw");
+ def.format.audio.pNativeRender = NULL;
+ def.format.audio.bFlagErrorConcealment = OMX_FALSE;
+ def.format.audio.eEncoding = OMX_AUDIO_CodingPCM;
+
+ addPort(def);
+
+ def.nPortIndex = 1;
+ def.eDir = OMX_DirOutput;
+ def.nBufferCountMin = kNumBuffers;
+ def.nBufferCountActual = def.nBufferCountMin;
+ def.nBufferSize = 8192;
+ def.bEnabled = OMX_TRUE;
+ def.bPopulated = OMX_FALSE;
+ def.eDomain = OMX_PortDomainAudio;
+ def.bBuffersContiguous = OMX_FALSE;
+ def.nBufferAlignment = 2;
+
+ def.format.audio.cMIMEType = const_cast<char *>("audio/3gpp");
+ def.format.audio.pNativeRender = NULL;
+ def.format.audio.bFlagErrorConcealment = OMX_FALSE;
+ def.format.audio.eEncoding = OMX_AUDIO_CodingAMR;
+
+ addPort(def);
+}
+
+status_t SoftAMRNBEncoder::initEncoder() {
+ if (AMREncodeInit(&mEncState, &mSidState, false /* dtx_enable */) != 0) {
+ return UNKNOWN_ERROR;
+ }
+
+ return OK;
+}
+
+OMX_ERRORTYPE SoftAMRNBEncoder::internalGetParameter(
+ OMX_INDEXTYPE index, OMX_PTR params) {
+ switch (index) {
+ case OMX_IndexParamAudioPortFormat:
+ {
+ OMX_AUDIO_PARAM_PORTFORMATTYPE *formatParams =
+ (OMX_AUDIO_PARAM_PORTFORMATTYPE *)params;
+
+ if (formatParams->nPortIndex > 1) {
+ return OMX_ErrorUndefined;
+ }
+
+ if (formatParams->nIndex > 0) {
+ return OMX_ErrorNoMore;
+ }
+
+ formatParams->eEncoding =
+ (formatParams->nPortIndex == 0)
+ ? OMX_AUDIO_CodingPCM : OMX_AUDIO_CodingAMR;
+
+ return OMX_ErrorNone;
+ }
+
+ case OMX_IndexParamAudioAmr:
+ {
+ OMX_AUDIO_PARAM_AMRTYPE *amrParams =
+ (OMX_AUDIO_PARAM_AMRTYPE *)params;
+
+ if (amrParams->nPortIndex != 1) {
+ return OMX_ErrorUndefined;
+ }
+
+ amrParams->nChannels = 1;
+ amrParams->nBitRate = mBitRate;
+ amrParams->eAMRBandMode = (OMX_AUDIO_AMRBANDMODETYPE)(mMode + 1);
+ amrParams->eAMRDTXMode = OMX_AUDIO_AMRDTXModeOff;
+ amrParams->eAMRFrameFormat = OMX_AUDIO_AMRFrameFormatFSF;
+
+ return OMX_ErrorNone;
+ }
+
+ case OMX_IndexParamAudioPcm:
+ {
+ OMX_AUDIO_PARAM_PCMMODETYPE *pcmParams =
+ (OMX_AUDIO_PARAM_PCMMODETYPE *)params;
+
+ if (pcmParams->nPortIndex != 0) {
+ return OMX_ErrorUndefined;
+ }
+
+ pcmParams->eNumData = OMX_NumericalDataSigned;
+ pcmParams->eEndian = OMX_EndianBig;
+ pcmParams->bInterleaved = OMX_TRUE;
+ pcmParams->nBitPerSample = 16;
+ pcmParams->ePCMMode = OMX_AUDIO_PCMModeLinear;
+ pcmParams->eChannelMapping[0] = OMX_AUDIO_ChannelCF;
+
+ pcmParams->nChannels = 1;
+ pcmParams->nSamplingRate = kSampleRate;
+
+ return OMX_ErrorNone;
+ }
+
+ default:
+ return SimpleSoftOMXComponent::internalGetParameter(index, params);
+ }
+}
+
+OMX_ERRORTYPE SoftAMRNBEncoder::internalSetParameter(
+ OMX_INDEXTYPE index, const OMX_PTR params) {
+ switch (index) {
+ case OMX_IndexParamStandardComponentRole:
+ {
+ const OMX_PARAM_COMPONENTROLETYPE *roleParams =
+ (const OMX_PARAM_COMPONENTROLETYPE *)params;
+
+ if (strncmp((const char *)roleParams->cRole,
+ "audio_encoder.amrnb",
+ OMX_MAX_STRINGNAME_SIZE - 1)) {
+ return OMX_ErrorUndefined;
+ }
+
+ return OMX_ErrorNone;
+ }
+
+ case OMX_IndexParamAudioPortFormat:
+ {
+ const OMX_AUDIO_PARAM_PORTFORMATTYPE *formatParams =
+ (const OMX_AUDIO_PARAM_PORTFORMATTYPE *)params;
+
+ if (formatParams->nPortIndex > 1) {
+ return OMX_ErrorUndefined;
+ }
+
+ if (formatParams->nIndex > 0) {
+ return OMX_ErrorNoMore;
+ }
+
+ if ((formatParams->nPortIndex == 0
+ && formatParams->eEncoding != OMX_AUDIO_CodingPCM)
+ || (formatParams->nPortIndex == 1
+ && formatParams->eEncoding != OMX_AUDIO_CodingAMR)) {
+ return OMX_ErrorUndefined;
+ }
+
+ return OMX_ErrorNone;
+ }
+
+ case OMX_IndexParamAudioAmr:
+ {
+ OMX_AUDIO_PARAM_AMRTYPE *amrParams =
+ (OMX_AUDIO_PARAM_AMRTYPE *)params;
+
+ if (amrParams->nPortIndex != 1) {
+ return OMX_ErrorUndefined;
+ }
+
+ if (amrParams->nChannels != 1
+ || amrParams->eAMRDTXMode != OMX_AUDIO_AMRDTXModeOff
+ || amrParams->eAMRFrameFormat
+ != OMX_AUDIO_AMRFrameFormatFSF
+ || amrParams->eAMRBandMode < OMX_AUDIO_AMRBandModeNB0
+ || amrParams->eAMRBandMode > OMX_AUDIO_AMRBandModeNB7) {
+ return OMX_ErrorUndefined;
+ }
+
+ mBitRate = amrParams->nBitRate;
+ mMode = amrParams->eAMRBandMode - 1;
+
+ amrParams->eAMRDTXMode = OMX_AUDIO_AMRDTXModeOff;
+ amrParams->eAMRFrameFormat = OMX_AUDIO_AMRFrameFormatFSF;
+
+ return OMX_ErrorNone;
+ }
+
+ case OMX_IndexParamAudioPcm:
+ {
+ OMX_AUDIO_PARAM_PCMMODETYPE *pcmParams =
+ (OMX_AUDIO_PARAM_PCMMODETYPE *)params;
+
+ if (pcmParams->nPortIndex != 0) {
+ return OMX_ErrorUndefined;
+ }
+
+ if (pcmParams->nChannels != 1
+ || pcmParams->nSamplingRate != kSampleRate) {
+ return OMX_ErrorUndefined;
+ }
+
+ return OMX_ErrorNone;
+ }
+
+
+ default:
+ return SimpleSoftOMXComponent::internalSetParameter(index, params);
+ }
+}
+
+void SoftAMRNBEncoder::onQueueFilled(OMX_U32 portIndex) {
+ if (mSignalledError) {
+ return;
+ }
+
+ List<BufferInfo *> &inQueue = getPortQueue(0);
+ List<BufferInfo *> &outQueue = getPortQueue(1);
+
+ size_t numBytesPerInputFrame = kNumSamplesPerFrame * sizeof(int16_t);
+
+ for (;;) {
+ // We do the following until we run out of buffers.
+
+ while (mInputSize < numBytesPerInputFrame) {
+ // As long as there's still input data to be read we
+ // will drain "kNumSamplesPerFrame" samples
+ // into the "mInputFrame" buffer and then encode those
+ // as a unit into an output buffer.
+
+ if (mSawInputEOS || inQueue.empty()) {
+ return;
+ }
+
+ BufferInfo *inInfo = *inQueue.begin();
+ OMX_BUFFERHEADERTYPE *inHeader = inInfo->mHeader;
+
+ const void *inData = inHeader->pBuffer + inHeader->nOffset;
+
+ size_t copy = numBytesPerInputFrame - mInputSize;
+ if (copy > inHeader->nFilledLen) {
+ copy = inHeader->nFilledLen;
+ }
+
+ if (mInputSize == 0) {
+ mInputTimeUs = inHeader->nTimeStamp;
+ }
+
+ memcpy((uint8_t *)mInputFrame + mInputSize, inData, copy);
+ mInputSize += copy;
+
+ inHeader->nOffset += copy;
+ inHeader->nFilledLen -= copy;
+
+ // "Time" on the input buffer has in effect advanced by the
+ // number of audio frames we just advanced nOffset by.
+ inHeader->nTimeStamp +=
+ (copy * 1000000ll / kSampleRate) / sizeof(int16_t);
+
+ if (inHeader->nFilledLen == 0) {
+ if (inHeader->nFlags & OMX_BUFFERFLAG_EOS) {
+ ALOGV("saw input EOS");
+ mSawInputEOS = true;
+
+ // Pad any remaining data with zeroes.
+ memset((uint8_t *)mInputFrame + mInputSize,
+ 0,
+ numBytesPerInputFrame - mInputSize);
+
+ mInputSize = numBytesPerInputFrame;
+ }
+
+ inQueue.erase(inQueue.begin());
+ inInfo->mOwnedByUs = false;
+ notifyEmptyBufferDone(inHeader);
+
+ inData = NULL;
+ inHeader = NULL;
+ inInfo = NULL;
+ }
+ }
+
+ // At this point we have all the input data necessary to encode
+ // a single frame, all we need is an output buffer to store the result
+ // in.
+
+ if (outQueue.empty()) {
+ return;
+ }
+
+ BufferInfo *outInfo = *outQueue.begin();
+ OMX_BUFFERHEADERTYPE *outHeader = outInfo->mHeader;
+
+ uint8_t *outPtr = outHeader->pBuffer + outHeader->nOffset;
+ size_t outAvailable = outHeader->nAllocLen - outHeader->nOffset;
+
+ Frame_Type_3GPP frameType;
+ int res = AMREncode(
+ mEncState, mSidState, (Mode)mMode,
+ mInputFrame, outPtr, &frameType, AMR_TX_WMF);
+
+ CHECK_GE(res, 0);
+ CHECK_LE((size_t)res, outAvailable);
+
+ // Convert header byte from WMF to IETF format.
+ outPtr[0] = ((outPtr[0] << 3) | 4) & 0x7c;
+
+ outHeader->nFilledLen = res;
+ outHeader->nFlags = OMX_BUFFERFLAG_ENDOFFRAME;
+
+ if (mSawInputEOS) {
+ // We also tag this output buffer with EOS if it corresponds
+ // to the final input buffer.
+ outHeader->nFlags = OMX_BUFFERFLAG_EOS;
+ }
+
+ outHeader->nTimeStamp = mInputTimeUs;
+
+#if 0
+ ALOGI("sending %d bytes of data (time = %lld us, flags = 0x%08lx)",
+ nOutputBytes, mInputTimeUs, outHeader->nFlags);
+
+ hexdump(outHeader->pBuffer + outHeader->nOffset, outHeader->nFilledLen);
+#endif
+
+ outQueue.erase(outQueue.begin());
+ outInfo->mOwnedByUs = false;
+ notifyFillBufferDone(outHeader);
+
+ outHeader = NULL;
+ outInfo = NULL;
+
+ mInputSize = 0;
+ }
+}
+
+} // namespace android
+
+android::SoftOMXComponent *createSoftOMXComponent(
+ const char *name, const OMX_CALLBACKTYPE *callbacks,
+ OMX_PTR appData, OMX_COMPONENTTYPE **component) {
+ return new android::SoftAMRNBEncoder(name, callbacks, appData, component);
+}
diff --git a/media/libstagefright/codecs/amrnb/enc/SoftAMRNBEncoder.h b/media/libstagefright/codecs/amrnb/enc/SoftAMRNBEncoder.h
new file mode 100644
index 0000000..50178c4
--- /dev/null
+++ b/media/libstagefright/codecs/amrnb/enc/SoftAMRNBEncoder.h
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef SOFT_AMRNB_ENCODER_H_
+
+#define SOFT_AMRNB_ENCODER_H_
+
+#include "SimpleSoftOMXComponent.h"
+
+namespace android {
+
+struct SoftAMRNBEncoder : public SimpleSoftOMXComponent {
+ SoftAMRNBEncoder(
+ const char *name,
+ const OMX_CALLBACKTYPE *callbacks,
+ OMX_PTR appData,
+ OMX_COMPONENTTYPE **component);
+
+protected:
+ virtual ~SoftAMRNBEncoder();
+
+ virtual OMX_ERRORTYPE internalGetParameter(
+ OMX_INDEXTYPE index, OMX_PTR params);
+
+ virtual OMX_ERRORTYPE internalSetParameter(
+ OMX_INDEXTYPE index, const OMX_PTR params);
+
+ virtual void onQueueFilled(OMX_U32 portIndex);
+
+private:
+ enum {
+ kNumBuffers = 4,
+ kNumSamplesPerFrame = 160,
+ };
+
+ void *mEncState;
+ void *mSidState;
+
+ OMX_U32 mBitRate;
+ int mMode;
+
+ size_t mInputSize;
+ int16_t mInputFrame[kNumSamplesPerFrame];
+ int64_t mInputTimeUs;
+
+ bool mSawInputEOS;
+ bool mSignalledError;
+
+ void initPorts();
+ status_t initEncoder();
+
+ status_t setAudioParams();
+
+ DISALLOW_EVIL_CONSTRUCTORS(SoftAMRNBEncoder);
+};
+
+} // namespace android
+
+#endif // SOFT_AMRNB_ENCODER_H_
diff --git a/media/libstagefright/codecs/amrwbenc/Android.mk b/media/libstagefright/codecs/amrwbenc/Android.mk
index ae43870..6ce6171 100644
--- a/media/libstagefright/codecs/amrwbenc/Android.mk
+++ b/media/libstagefright/codecs/amrwbenc/Android.mk
@@ -117,4 +117,26 @@
include $(BUILD_STATIC_LIBRARY)
+################################################################################
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := \
+ SoftAMRWBEncoder.cpp
+
+LOCAL_C_INCLUDES := \
+ frameworks/base/media/libstagefright/include \
+ frameworks/base/include/media/stagefright/openmax \
+ frameworks/base/media/libstagefright/codecs/common/include \
+
+LOCAL_STATIC_LIBRARIES := \
+ libstagefright_amrwbenc
+
+LOCAL_SHARED_LIBRARIES := \
+ libstagefright_omx libstagefright_foundation libutils \
+ libstagefright_enc_common
+
+LOCAL_MODULE := libstagefright_soft_amrwbenc
+LOCAL_MODULE_TAGS := optional
+
+include $(BUILD_SHARED_LIBRARY)
diff --git a/media/libstagefright/codecs/amrwbenc/SoftAMRWBEncoder.cpp b/media/libstagefright/codecs/amrwbenc/SoftAMRWBEncoder.cpp
new file mode 100644
index 0000000..9ccb49c
--- /dev/null
+++ b/media/libstagefright/codecs/amrwbenc/SoftAMRWBEncoder.cpp
@@ -0,0 +1,459 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "SoftAMRWBEncoder"
+#include <utils/Log.h>
+
+#include "SoftAMRWBEncoder.h"
+
+#include "cmnMemory.h"
+
+#include <media/stagefright/foundation/ADebug.h>
+#include <media/stagefright/foundation/hexdump.h>
+
+namespace android {
+
+static const int32_t kSampleRate = 16000;
+
+template<class T>
+static void InitOMXParams(T *params) {
+ params->nSize = sizeof(T);
+ params->nVersion.s.nVersionMajor = 1;
+ params->nVersion.s.nVersionMinor = 0;
+ params->nVersion.s.nRevision = 0;
+ params->nVersion.s.nStep = 0;
+}
+
+SoftAMRWBEncoder::SoftAMRWBEncoder(
+ const char *name,
+ const OMX_CALLBACKTYPE *callbacks,
+ OMX_PTR appData,
+ OMX_COMPONENTTYPE **component)
+ : SimpleSoftOMXComponent(name, callbacks, appData, component),
+ mEncoderHandle(NULL),
+ mApiHandle(NULL),
+ mMemOperator(NULL),
+ mBitRate(0),
+ mMode(VOAMRWB_MD66),
+ mInputSize(0),
+ mInputTimeUs(-1ll),
+ mSawInputEOS(false),
+ mSignalledError(false) {
+ initPorts();
+ CHECK_EQ(initEncoder(), (status_t)OK);
+}
+
+SoftAMRWBEncoder::~SoftAMRWBEncoder() {
+ if (mEncoderHandle != NULL) {
+ CHECK_EQ(VO_ERR_NONE, mApiHandle->Uninit(mEncoderHandle));
+ mEncoderHandle = NULL;
+ }
+
+ delete mApiHandle;
+ mApiHandle = NULL;
+
+ delete mMemOperator;
+ mMemOperator = NULL;
+}
+
+void SoftAMRWBEncoder::initPorts() {
+ OMX_PARAM_PORTDEFINITIONTYPE def;
+ InitOMXParams(&def);
+
+ def.nPortIndex = 0;
+ def.eDir = OMX_DirInput;
+ def.nBufferCountMin = kNumBuffers;
+ def.nBufferCountActual = def.nBufferCountMin;
+ def.nBufferSize = kNumSamplesPerFrame * sizeof(int16_t);
+ def.bEnabled = OMX_TRUE;
+ def.bPopulated = OMX_FALSE;
+ def.eDomain = OMX_PortDomainAudio;
+ def.bBuffersContiguous = OMX_FALSE;
+ def.nBufferAlignment = 1;
+
+ def.format.audio.cMIMEType = const_cast<char *>("audio/raw");
+ def.format.audio.pNativeRender = NULL;
+ def.format.audio.bFlagErrorConcealment = OMX_FALSE;
+ def.format.audio.eEncoding = OMX_AUDIO_CodingPCM;
+
+ addPort(def);
+
+ def.nPortIndex = 1;
+ def.eDir = OMX_DirOutput;
+ def.nBufferCountMin = kNumBuffers;
+ def.nBufferCountActual = def.nBufferCountMin;
+ def.nBufferSize = 8192;
+ def.bEnabled = OMX_TRUE;
+ def.bPopulated = OMX_FALSE;
+ def.eDomain = OMX_PortDomainAudio;
+ def.bBuffersContiguous = OMX_FALSE;
+ def.nBufferAlignment = 2;
+
+ def.format.audio.cMIMEType = const_cast<char *>("audio/amr-wb");
+ def.format.audio.pNativeRender = NULL;
+ def.format.audio.bFlagErrorConcealment = OMX_FALSE;
+ def.format.audio.eEncoding = OMX_AUDIO_CodingAMR;
+
+ addPort(def);
+}
+
+status_t SoftAMRWBEncoder::initEncoder() {
+ mApiHandle = new VO_AUDIO_CODECAPI;
+
+ if (VO_ERR_NONE != voGetAMRWBEncAPI(mApiHandle)) {
+ ALOGE("Failed to get api handle");
+ return UNKNOWN_ERROR;
+ }
+
+ mMemOperator = new VO_MEM_OPERATOR;
+ mMemOperator->Alloc = cmnMemAlloc;
+ mMemOperator->Copy = cmnMemCopy;
+ mMemOperator->Free = cmnMemFree;
+ mMemOperator->Set = cmnMemSet;
+ mMemOperator->Check = cmnMemCheck;
+
+ VO_CODEC_INIT_USERDATA userData;
+ memset(&userData, 0, sizeof(userData));
+ userData.memflag = VO_IMF_USERMEMOPERATOR;
+ userData.memData = (VO_PTR) mMemOperator;
+
+ if (VO_ERR_NONE != mApiHandle->Init(
+ &mEncoderHandle, VO_AUDIO_CodingAMRWB, &userData)) {
+ ALOGE("Failed to init AMRWB encoder");
+ return UNKNOWN_ERROR;
+ }
+
+ VOAMRWBFRAMETYPE type = VOAMRWB_RFC3267;
+ if (VO_ERR_NONE != mApiHandle->SetParam(
+ mEncoderHandle, VO_PID_AMRWB_FRAMETYPE, &type)) {
+ ALOGE("Failed to set AMRWB encoder frame type to %d", type);
+ return UNKNOWN_ERROR;
+ }
+
+ return OK;
+}
+
+OMX_ERRORTYPE SoftAMRWBEncoder::internalGetParameter(
+ OMX_INDEXTYPE index, OMX_PTR params) {
+ switch (index) {
+ case OMX_IndexParamAudioPortFormat:
+ {
+ OMX_AUDIO_PARAM_PORTFORMATTYPE *formatParams =
+ (OMX_AUDIO_PARAM_PORTFORMATTYPE *)params;
+
+ if (formatParams->nPortIndex > 1) {
+ return OMX_ErrorUndefined;
+ }
+
+ if (formatParams->nIndex > 0) {
+ return OMX_ErrorNoMore;
+ }
+
+ formatParams->eEncoding =
+ (formatParams->nPortIndex == 0)
+ ? OMX_AUDIO_CodingPCM : OMX_AUDIO_CodingAMR;
+
+ return OMX_ErrorNone;
+ }
+
+ case OMX_IndexParamAudioAmr:
+ {
+ OMX_AUDIO_PARAM_AMRTYPE *amrParams =
+ (OMX_AUDIO_PARAM_AMRTYPE *)params;
+
+ if (amrParams->nPortIndex != 1) {
+ return OMX_ErrorUndefined;
+ }
+
+ amrParams->nChannels = 1;
+ amrParams->nBitRate = mBitRate;
+
+ amrParams->eAMRBandMode =
+ (OMX_AUDIO_AMRBANDMODETYPE)(mMode + OMX_AUDIO_AMRBandModeWB0);
+
+ amrParams->eAMRDTXMode = OMX_AUDIO_AMRDTXModeOff;
+ amrParams->eAMRFrameFormat = OMX_AUDIO_AMRFrameFormatFSF;
+
+ return OMX_ErrorNone;
+ }
+
+ case OMX_IndexParamAudioPcm:
+ {
+ OMX_AUDIO_PARAM_PCMMODETYPE *pcmParams =
+ (OMX_AUDIO_PARAM_PCMMODETYPE *)params;
+
+ if (pcmParams->nPortIndex != 0) {
+ return OMX_ErrorUndefined;
+ }
+
+ pcmParams->eNumData = OMX_NumericalDataSigned;
+ pcmParams->eEndian = OMX_EndianBig;
+ pcmParams->bInterleaved = OMX_TRUE;
+ pcmParams->nBitPerSample = 16;
+ pcmParams->ePCMMode = OMX_AUDIO_PCMModeLinear;
+ pcmParams->eChannelMapping[0] = OMX_AUDIO_ChannelCF;
+
+ pcmParams->nChannels = 1;
+ pcmParams->nSamplingRate = kSampleRate;
+
+ return OMX_ErrorNone;
+ }
+
+ default:
+ return SimpleSoftOMXComponent::internalGetParameter(index, params);
+ }
+}
+
+OMX_ERRORTYPE SoftAMRWBEncoder::internalSetParameter(
+ OMX_INDEXTYPE index, const OMX_PTR params) {
+ switch (index) {
+ case OMX_IndexParamStandardComponentRole:
+ {
+ const OMX_PARAM_COMPONENTROLETYPE *roleParams =
+ (const OMX_PARAM_COMPONENTROLETYPE *)params;
+
+ if (strncmp((const char *)roleParams->cRole,
+ "audio_encoder.amrwb",
+ OMX_MAX_STRINGNAME_SIZE - 1)) {
+ return OMX_ErrorUndefined;
+ }
+
+ return OMX_ErrorNone;
+ }
+
+ case OMX_IndexParamAudioPortFormat:
+ {
+ const OMX_AUDIO_PARAM_PORTFORMATTYPE *formatParams =
+ (const OMX_AUDIO_PARAM_PORTFORMATTYPE *)params;
+
+ if (formatParams->nPortIndex > 1) {
+ return OMX_ErrorUndefined;
+ }
+
+ if (formatParams->nIndex > 0) {
+ return OMX_ErrorNoMore;
+ }
+
+ if ((formatParams->nPortIndex == 0
+ && formatParams->eEncoding != OMX_AUDIO_CodingPCM)
+ || (formatParams->nPortIndex == 1
+ && formatParams->eEncoding != OMX_AUDIO_CodingAMR)) {
+ return OMX_ErrorUndefined;
+ }
+
+ return OMX_ErrorNone;
+ }
+
+ case OMX_IndexParamAudioAmr:
+ {
+ OMX_AUDIO_PARAM_AMRTYPE *amrParams =
+ (OMX_AUDIO_PARAM_AMRTYPE *)params;
+
+ if (amrParams->nPortIndex != 1) {
+ return OMX_ErrorUndefined;
+ }
+
+ if (amrParams->nChannels != 1
+ || amrParams->eAMRDTXMode != OMX_AUDIO_AMRDTXModeOff
+ || amrParams->eAMRFrameFormat
+ != OMX_AUDIO_AMRFrameFormatFSF
+ || amrParams->eAMRBandMode < OMX_AUDIO_AMRBandModeWB0
+ || amrParams->eAMRBandMode > OMX_AUDIO_AMRBandModeWB8) {
+ return OMX_ErrorUndefined;
+ }
+
+ mBitRate = amrParams->nBitRate;
+
+ mMode = (VOAMRWBMODE)(
+ amrParams->eAMRBandMode - OMX_AUDIO_AMRBandModeWB0);
+
+ amrParams->eAMRDTXMode = OMX_AUDIO_AMRDTXModeOff;
+ amrParams->eAMRFrameFormat = OMX_AUDIO_AMRFrameFormatFSF;
+
+ if (VO_ERR_NONE !=
+ mApiHandle->SetParam(
+ mEncoderHandle, VO_PID_AMRWB_MODE, &mMode)) {
+ ALOGE("Failed to set AMRWB encoder mode to %d", mMode);
+ return OMX_ErrorUndefined;
+ }
+
+ return OMX_ErrorNone;
+ }
+
+ case OMX_IndexParamAudioPcm:
+ {
+ OMX_AUDIO_PARAM_PCMMODETYPE *pcmParams =
+ (OMX_AUDIO_PARAM_PCMMODETYPE *)params;
+
+ if (pcmParams->nPortIndex != 0) {
+ return OMX_ErrorUndefined;
+ }
+
+ if (pcmParams->nChannels != 1
+ || pcmParams->nSamplingRate != (OMX_U32)kSampleRate) {
+ return OMX_ErrorUndefined;
+ }
+
+ return OMX_ErrorNone;
+ }
+
+
+ default:
+ return SimpleSoftOMXComponent::internalSetParameter(index, params);
+ }
+}
+
+void SoftAMRWBEncoder::onQueueFilled(OMX_U32 portIndex) {
+ if (mSignalledError) {
+ return;
+ }
+
+ List<BufferInfo *> &inQueue = getPortQueue(0);
+ List<BufferInfo *> &outQueue = getPortQueue(1);
+
+ size_t numBytesPerInputFrame = kNumSamplesPerFrame * sizeof(int16_t);
+
+ for (;;) {
+ // We do the following until we run out of buffers.
+
+ while (mInputSize < numBytesPerInputFrame) {
+ // As long as there's still input data to be read we
+ // will drain "kNumSamplesPerFrame" samples
+ // into the "mInputFrame" buffer and then encode those
+ // as a unit into an output buffer.
+
+ if (mSawInputEOS || inQueue.empty()) {
+ return;
+ }
+
+ BufferInfo *inInfo = *inQueue.begin();
+ OMX_BUFFERHEADERTYPE *inHeader = inInfo->mHeader;
+
+ const void *inData = inHeader->pBuffer + inHeader->nOffset;
+
+ size_t copy = numBytesPerInputFrame - mInputSize;
+ if (copy > inHeader->nFilledLen) {
+ copy = inHeader->nFilledLen;
+ }
+
+ if (mInputSize == 0) {
+ mInputTimeUs = inHeader->nTimeStamp;
+ }
+
+ memcpy((uint8_t *)mInputFrame + mInputSize, inData, copy);
+ mInputSize += copy;
+
+ inHeader->nOffset += copy;
+ inHeader->nFilledLen -= copy;
+
+ // "Time" on the input buffer has in effect advanced by the
+ // number of audio frames we just advanced nOffset by.
+ inHeader->nTimeStamp +=
+ (copy * 1000000ll / kSampleRate) / sizeof(int16_t);
+
+ if (inHeader->nFilledLen == 0) {
+ if (inHeader->nFlags & OMX_BUFFERFLAG_EOS) {
+ ALOGV("saw input EOS");
+ mSawInputEOS = true;
+
+ // Pad any remaining data with zeroes.
+ memset((uint8_t *)mInputFrame + mInputSize,
+ 0,
+ numBytesPerInputFrame - mInputSize);
+
+ mInputSize = numBytesPerInputFrame;
+ }
+
+ inQueue.erase(inQueue.begin());
+ inInfo->mOwnedByUs = false;
+ notifyEmptyBufferDone(inHeader);
+
+ inData = NULL;
+ inHeader = NULL;
+ inInfo = NULL;
+ }
+ }
+
+ // At this point we have all the input data necessary to encode
+ // a single frame, all we need is an output buffer to store the result
+ // in.
+
+ if (outQueue.empty()) {
+ return;
+ }
+
+ BufferInfo *outInfo = *outQueue.begin();
+ OMX_BUFFERHEADERTYPE *outHeader = outInfo->mHeader;
+
+ uint8_t *outPtr = outHeader->pBuffer + outHeader->nOffset;
+ size_t outAvailable = outHeader->nAllocLen - outHeader->nOffset;
+
+ VO_CODECBUFFER inputData;
+ memset(&inputData, 0, sizeof(inputData));
+ inputData.Buffer = (unsigned char *) mInputFrame;
+ inputData.Length = mInputSize;
+
+ CHECK_EQ(VO_ERR_NONE,
+ mApiHandle->SetInputData(mEncoderHandle, &inputData));
+
+ VO_CODECBUFFER outputData;
+ memset(&outputData, 0, sizeof(outputData));
+ VO_AUDIO_OUTPUTINFO outputInfo;
+ memset(&outputInfo, 0, sizeof(outputInfo));
+
+ outputData.Buffer = outPtr;
+ outputData.Length = outAvailable;
+ VO_U32 ret = mApiHandle->GetOutputData(
+ mEncoderHandle, &outputData, &outputInfo);
+ CHECK(ret == VO_ERR_NONE || ret == VO_ERR_INPUT_BUFFER_SMALL);
+
+ outHeader->nFilledLen = outputData.Length;
+ outHeader->nFlags = OMX_BUFFERFLAG_ENDOFFRAME;
+
+ if (mSawInputEOS) {
+ // We also tag this output buffer with EOS if it corresponds
+ // to the final input buffer.
+ outHeader->nFlags = OMX_BUFFERFLAG_EOS;
+ }
+
+ outHeader->nTimeStamp = mInputTimeUs;
+
+#if 0
+ ALOGI("sending %ld bytes of data (time = %lld us, flags = 0x%08lx)",
+ outHeader->nFilledLen, mInputTimeUs, outHeader->nFlags);
+
+ hexdump(outHeader->pBuffer + outHeader->nOffset, outHeader->nFilledLen);
+#endif
+
+ outQueue.erase(outQueue.begin());
+ outInfo->mOwnedByUs = false;
+ notifyFillBufferDone(outHeader);
+
+ outHeader = NULL;
+ outInfo = NULL;
+
+ mInputSize = 0;
+ }
+}
+
+} // namespace android
+
+android::SoftOMXComponent *createSoftOMXComponent(
+ const char *name, const OMX_CALLBACKTYPE *callbacks,
+ OMX_PTR appData, OMX_COMPONENTTYPE **component) {
+ return new android::SoftAMRWBEncoder(name, callbacks, appData, component);
+}
diff --git a/media/libstagefright/codecs/amrwbenc/SoftAMRWBEncoder.h b/media/libstagefright/codecs/amrwbenc/SoftAMRWBEncoder.h
new file mode 100644
index 0000000..d0c1dab
--- /dev/null
+++ b/media/libstagefright/codecs/amrwbenc/SoftAMRWBEncoder.h
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef SOFT_AMRWB_ENCODER_H_
+
+#define SOFT_AMRWB_ENCODER_H_
+
+#include "SimpleSoftOMXComponent.h"
+
+#include "voAMRWB.h"
+
+struct VO_AUDIO_CODECAPI;
+struct VO_MEM_OPERATOR;
+
+namespace android {
+
+struct SoftAMRWBEncoder : public SimpleSoftOMXComponent {
+ SoftAMRWBEncoder(
+ const char *name,
+ const OMX_CALLBACKTYPE *callbacks,
+ OMX_PTR appData,
+ OMX_COMPONENTTYPE **component);
+
+protected:
+ virtual ~SoftAMRWBEncoder();
+
+ virtual OMX_ERRORTYPE internalGetParameter(
+ OMX_INDEXTYPE index, OMX_PTR params);
+
+ virtual OMX_ERRORTYPE internalSetParameter(
+ OMX_INDEXTYPE index, const OMX_PTR params);
+
+ virtual void onQueueFilled(OMX_U32 portIndex);
+
+private:
+ enum {
+ kNumBuffers = 4,
+ kNumSamplesPerFrame = 320,
+ };
+
+ void *mEncoderHandle;
+ VO_AUDIO_CODECAPI *mApiHandle;
+ VO_MEM_OPERATOR *mMemOperator;
+
+ OMX_U32 mBitRate;
+ VOAMRWBMODE mMode;
+
+ size_t mInputSize;
+ int16_t mInputFrame[kNumSamplesPerFrame];
+ int64_t mInputTimeUs;
+
+ bool mSawInputEOS;
+ bool mSignalledError;
+
+ void initPorts();
+ status_t initEncoder();
+
+ DISALLOW_EVIL_CONSTRUCTORS(SoftAMRWBEncoder);
+};
+
+} // namespace android
+
+#endif // SOFT_AMRWB_ENCODER_H_
diff --git a/media/libstagefright/codecs/amrwbenc/src/mem_align.c b/media/libstagefright/codecs/amrwbenc/src/mem_align.c
index a29baf3..3b7853f 100644
--- a/media/libstagefright/codecs/amrwbenc/src/mem_align.c
+++ b/media/libstagefright/codecs/amrwbenc/src/mem_align.c
@@ -23,6 +23,11 @@
#include "mem_align.h"
+#ifdef _MSC_VER
+#include <stddef.h>
+#else
+#include <stdint.h>
+#endif
/*****************************************************************************
*
@@ -66,8 +71,8 @@
pMemop->Set(CodecID, tmp, 0, size + alignment);
mem_ptr =
- (unsigned char *) ((unsigned int) (tmp + alignment - 1) &
- (~((unsigned int) (alignment - 1))));
+ (unsigned char *) ((intptr_t) (tmp + alignment - 1) &
+ (~((intptr_t) (alignment - 1))));
if (mem_ptr == tmp)
mem_ptr += alignment;
diff --git a/media/libstagefright/colorconversion/ColorConverter.cpp b/media/libstagefright/colorconversion/ColorConverter.cpp
index 5cc3f78..f3ef3de 100644
--- a/media/libstagefright/colorconversion/ColorConverter.cpp
+++ b/media/libstagefright/colorconversion/ColorConverter.cpp
@@ -144,8 +144,8 @@
return ERROR_UNSUPPORTED;
}
- uint32_t *dst_ptr = (uint32_t *)dst.mBits
- + (dst.mCropTop * dst.mWidth + dst.mCropLeft) / 2;
+ uint16_t *dst_ptr = (uint16_t *)dst.mBits
+ + dst.mCropTop * dst.mWidth + dst.mCropLeft;
const uint8_t *src_ptr = (const uint8_t *)src.mBits
+ (src.mCropTop * dst.mWidth + src.mCropLeft) * 2;
@@ -182,11 +182,15 @@
| ((kAdjustedClip[g2] >> 2) << 5)
| (kAdjustedClip[b2] >> 3);
- dst_ptr[x / 2] = (rgb2 << 16) | rgb1;
+ if (x + 1 < src.cropWidth()) {
+ *(uint32_t *)(&dst_ptr[x]) = (rgb2 << 16) | rgb1;
+ } else {
+ dst_ptr[x] = rgb1;
+ }
}
src_ptr += src.mWidth * 2;
- dst_ptr += dst.mWidth / 2;
+ dst_ptr += dst.mWidth;
}
return OK;
@@ -290,15 +294,14 @@
const BitmapParams &src, const BitmapParams &dst) {
uint8_t *kAdjustedClip = initClip();
- if (!((dst.mWidth & 3) == 0
- && (src.mCropLeft & 1) == 0
+ if (!((src.mCropLeft & 1) == 0
&& src.cropWidth() == dst.cropWidth()
&& src.cropHeight() == dst.cropHeight())) {
return ERROR_UNSUPPORTED;
}
- uint32_t *dst_ptr = (uint32_t *)dst.mBits
- + (dst.mCropTop * dst.mWidth + dst.mCropLeft) / 2;
+ uint16_t *dst_ptr = (uint16_t *)dst.mBits
+ + dst.mCropTop * dst.mWidth + dst.mCropLeft;
const uint8_t *src_y =
(const uint8_t *)src.mBits + src.mCropTop * src.mWidth + src.mCropLeft;
@@ -340,7 +343,11 @@
| ((kAdjustedClip[g2] >> 2) << 5)
| (kAdjustedClip[r2] >> 3);
- dst_ptr[x / 2] = (rgb2 << 16) | rgb1;
+ if (x + 1 < src.cropWidth()) {
+ *(uint32_t *)(&dst_ptr[x]) = (rgb2 << 16) | rgb1;
+ } else {
+ dst_ptr[x] = rgb1;
+ }
}
src_y += src.mWidth;
@@ -349,7 +356,7 @@
src_u += src.mWidth;
}
- dst_ptr += dst.mWidth / 2;
+ dst_ptr += dst.mWidth;
}
return OK;
@@ -361,15 +368,14 @@
uint8_t *kAdjustedClip = initClip();
- if (!((dst.mWidth & 3) == 0
- && (src.mCropLeft & 1) == 0
+ if (!((src.mCropLeft & 1) == 0
&& src.cropWidth() == dst.cropWidth()
&& src.cropHeight() == dst.cropHeight())) {
return ERROR_UNSUPPORTED;
}
- uint32_t *dst_ptr = (uint32_t *)dst.mBits
- + (dst.mCropTop * dst.mWidth + dst.mCropLeft) / 2;
+ uint16_t *dst_ptr = (uint16_t *)dst.mBits
+ + dst.mCropTop * dst.mWidth + dst.mCropLeft;
const uint8_t *src_y =
(const uint8_t *)src.mBits + src.mCropTop * src.mWidth + src.mCropLeft;
@@ -411,7 +417,11 @@
| ((kAdjustedClip[g2] >> 2) << 5)
| (kAdjustedClip[r2] >> 3);
- dst_ptr[x / 2] = (rgb2 << 16) | rgb1;
+ if (x + 1 < src.cropWidth()) {
+ *(uint32_t *)(&dst_ptr[x]) = (rgb2 << 16) | rgb1;
+ } else {
+ dst_ptr[x] = rgb1;
+ }
}
src_y += src.mWidth;
@@ -420,7 +430,7 @@
src_u += src.mWidth;
}
- dst_ptr += dst.mWidth / 2;
+ dst_ptr += dst.mWidth;
}
return OK;
@@ -430,15 +440,14 @@
const BitmapParams &src, const BitmapParams &dst) {
uint8_t *kAdjustedClip = initClip();
- if (!((dst.mWidth & 3) == 0
- && (src.mCropLeft & 1) == 0
+ if (!((src.mCropLeft & 1) == 0
&& src.cropWidth() == dst.cropWidth()
&& src.cropHeight() == dst.cropHeight())) {
return ERROR_UNSUPPORTED;
}
- uint32_t *dst_ptr = (uint32_t *)dst.mBits
- + (dst.mCropTop * dst.mWidth + dst.mCropLeft) / 2;
+ uint16_t *dst_ptr = (uint16_t *)dst.mBits
+ + dst.mCropTop * dst.mWidth + dst.mCropLeft;
const uint8_t *src_y = (const uint8_t *)src.mBits;
@@ -478,7 +487,11 @@
| ((kAdjustedClip[g2] >> 2) << 5)
| (kAdjustedClip[b2] >> 3);
- dst_ptr[x / 2] = (rgb2 << 16) | rgb1;
+ if (x + 1 < src.cropWidth()) {
+ *(uint32_t *)(&dst_ptr[x]) = (rgb2 << 16) | rgb1;
+ } else {
+ dst_ptr[x] = rgb1;
+ }
}
src_y += src.mWidth;
@@ -487,7 +500,7 @@
src_u += src.mWidth;
}
- dst_ptr += dst.mWidth / 2;
+ dst_ptr += dst.mWidth;
}
return OK;
diff --git a/media/libstagefright/include/AwesomePlayer.h b/media/libstagefright/include/AwesomePlayer.h
index 82c6476..a7a3d47 100644
--- a/media/libstagefright/include/AwesomePlayer.h
+++ b/media/libstagefright/include/AwesomePlayer.h
@@ -41,7 +41,7 @@
class DrmManagerClinet;
class DecryptHandle;
-class TimedTextPlayer;
+class TimedTextDriver;
struct WVMExtractor;
struct AwesomeRenderer : public RefBase {
@@ -232,7 +232,7 @@
sp<DecryptHandle> mDecryptHandle;
int64_t mLastVideoTimeUs;
- TimedTextPlayer *mTextPlayer;
+ TimedTextDriver *mTextDriver;
mutable Mutex mTimedTextLock;
sp<WVMExtractor> mWVMExtractor;
@@ -326,4 +326,3 @@
} // namespace android
#endif // AWESOME_PLAYER_H_
-
diff --git a/media/libstagefright/include/OMX.h b/media/libstagefright/include/OMX.h
index 53e764f..2c87b34 100644
--- a/media/libstagefright/include/OMX.h
+++ b/media/libstagefright/include/OMX.h
@@ -31,7 +31,7 @@
public:
OMX();
- virtual bool livesLocally(pid_t pid);
+ virtual bool livesLocally(node_id node, pid_t pid);
virtual status_t listNodes(List<ComponentInfo> *list);
diff --git a/media/libstagefright/omx/OMX.cpp b/media/libstagefright/omx/OMX.cpp
index 694b12d8..ace883c 100644
--- a/media/libstagefright/omx/OMX.cpp
+++ b/media/libstagefright/omx/OMX.cpp
@@ -185,7 +185,7 @@
instance->onObserverDied(mMaster);
}
-bool OMX::livesLocally(pid_t pid) {
+bool OMX::livesLocally(node_id node, pid_t pid) {
return pid == getpid();
}
diff --git a/media/libstagefright/omx/SimpleSoftOMXComponent.cpp b/media/libstagefright/omx/SimpleSoftOMXComponent.cpp
index 0914f32..c79e01f 100644
--- a/media/libstagefright/omx/SimpleSoftOMXComponent.cpp
+++ b/media/libstagefright/omx/SimpleSoftOMXComponent.cpp
@@ -333,8 +333,9 @@
void SimpleSoftOMXComponent::onMessageReceived(const sp<AMessage> &msg) {
Mutex::Autolock autoLock(mLock);
-
- switch (msg->what()) {
+ uint32_t msgType = msg->what();
+ ALOGV("msgType = %d", msgType);
+ switch (msgType) {
case kWhatSendCommand:
{
int32_t cmd, param;
@@ -354,27 +355,27 @@
CHECK(mState == OMX_StateExecuting && mTargetState == mState);
bool found = false;
- for (size_t i = 0; i < mPorts.size(); ++i) {
- PortInfo *port = &mPorts.editItemAt(i);
+ size_t portIndex = (kWhatEmptyThisBuffer == msgType)?
+ header->nInputPortIndex: header->nOutputPortIndex;
+ PortInfo *port = &mPorts.editItemAt(portIndex);
- for (size_t j = 0; j < port->mBuffers.size(); ++j) {
- BufferInfo *buffer = &port->mBuffers.editItemAt(j);
+ for (size_t j = 0; j < port->mBuffers.size(); ++j) {
+ BufferInfo *buffer = &port->mBuffers.editItemAt(j);
- if (buffer->mHeader == header) {
- CHECK(!buffer->mOwnedByUs);
+ if (buffer->mHeader == header) {
+ CHECK(!buffer->mOwnedByUs);
- buffer->mOwnedByUs = true;
+ buffer->mOwnedByUs = true;
- CHECK((msg->what() == kWhatEmptyThisBuffer
- && port->mDef.eDir == OMX_DirInput)
- || (port->mDef.eDir == OMX_DirOutput));
+ CHECK((msgType == kWhatEmptyThisBuffer
+ && port->mDef.eDir == OMX_DirInput)
+ || (port->mDef.eDir == OMX_DirOutput));
- port->mQueue.push_back(buffer);
- onQueueFilled(i);
+ port->mQueue.push_back(buffer);
+ onQueueFilled(portIndex);
- found = true;
- break;
- }
+ found = true;
+ break;
}
}
diff --git a/media/libstagefright/omx/SoftOMXPlugin.cpp b/media/libstagefright/omx/SoftOMXPlugin.cpp
index da3ae42..99ffe7d 100644
--- a/media/libstagefright/omx/SoftOMXPlugin.cpp
+++ b/media/libstagefright/omx/SoftOMXPlugin.cpp
@@ -35,8 +35,11 @@
} kComponents[] = {
{ "OMX.google.aac.decoder", "aacdec", "audio_decoder.aac" },
+ { "OMX.google.aac.encoder", "aacenc", "audio_encoder.aac" },
{ "OMX.google.amrnb.decoder", "amrdec", "audio_decoder.amrnb" },
+ { "OMX.google.amrnb.encoder", "amrnbenc", "audio_encoder.amrnb" },
{ "OMX.google.amrwb.decoder", "amrdec", "audio_decoder.amrwb" },
+ { "OMX.google.amrwb.encoder", "amrwbenc", "audio_encoder.amrwb" },
{ "OMX.google.h264.decoder", "h264dec", "video_decoder.avc" },
{ "OMX.google.g711.alaw.decoder", "g711dec", "audio_decoder.g711alaw" },
{ "OMX.google.g711.mlaw.decoder", "g711dec", "audio_decoder.g711mlaw" },
diff --git a/media/libstagefright/omx/tests/Android.mk b/media/libstagefright/omx/tests/Android.mk
index bf69428..41c08be 100644
--- a/media/libstagefright/omx/tests/Android.mk
+++ b/media/libstagefright/omx/tests/Android.mk
@@ -7,11 +7,13 @@
LOCAL_SHARED_LIBRARIES := \
libstagefright libbinder libmedia libutils
-LOCAL_C_INCLUDES:= \
+LOCAL_C_INCLUDES := \
$(JNI_H_INCLUDE) \
frameworks/base/media/libstagefright \
$(TOP)/frameworks/base/include/media/stagefright/openmax
-LOCAL_MODULE:= omx_tests
+LOCAL_MODULE := omx_tests
+
+LOCAL_MODULE_TAGS := tests
include $(BUILD_EXECUTABLE)
diff --git a/media/libstagefright/timedtext/Android.mk b/media/libstagefright/timedtext/Android.mk
index 59d0e15..8b23dee 100644
--- a/media/libstagefright/timedtext/Android.mk
+++ b/media/libstagefright/timedtext/Android.mk
@@ -3,7 +3,10 @@
LOCAL_SRC_FILES:= \
TextDescriptions.cpp \
- TimedTextParser.cpp \
+ TimedTextDriver.cpp \
+ TimedTextInBandSource.cpp \
+ TimedTextSource.cpp \
+ TimedTextSRTSource.cpp \
TimedTextPlayer.cpp
LOCAL_CFLAGS += -Wno-multichar
diff --git a/media/libstagefright/timedtext/TimedTextDriver.cpp b/media/libstagefright/timedtext/TimedTextDriver.cpp
new file mode 100644
index 0000000..9ec9415
--- /dev/null
+++ b/media/libstagefright/timedtext/TimedTextDriver.cpp
@@ -0,0 +1,223 @@
+ /*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "TimedTextDriver"
+#include <utils/Log.h>
+
+#include <binder/IPCThreadState.h>
+
+#include <media/MediaPlayerInterface.h>
+#include <media/stagefright/MediaErrors.h>
+#include <media/stagefright/MediaSource.h>
+#include <media/stagefright/DataSource.h>
+#include <media/stagefright/Utils.h>
+#include <media/stagefright/foundation/ADebug.h>
+#include <media/stagefright/foundation/ALooper.h>
+
+#include "TimedTextDriver.h"
+
+#include "TextDescriptions.h"
+#include "TimedTextPlayer.h"
+#include "TimedTextSource.h"
+
+namespace android {
+
+TimedTextDriver::TimedTextDriver(
+ const wp<MediaPlayerBase> &listener)
+ : mLooper(new ALooper),
+ mListener(listener),
+ mState(UNINITIALIZED) {
+ mLooper->setName("TimedTextDriver");
+ mLooper->start();
+ mPlayer = new TimedTextPlayer(listener);
+ mLooper->registerHandler(mPlayer);
+}
+
+TimedTextDriver::~TimedTextDriver() {
+ mTextInBandVector.clear();
+ mTextOutOfBandVector.clear();
+ mLooper->stop();
+}
+
+status_t TimedTextDriver::setTimedTextTrackIndex_l(int32_t index) {
+ if (index >=
+ (int)(mTextInBandVector.size() + mTextOutOfBandVector.size())) {
+ return BAD_VALUE;
+ }
+
+ sp<TimedTextSource> source;
+ if (index < mTextInBandVector.size()) {
+ source = mTextInBandVector.itemAt(index);
+ } else {
+ source = mTextOutOfBandVector.itemAt(index - mTextInBandVector.size());
+ }
+ mPlayer->setDataSource(source);
+ return OK;
+}
+
+status_t TimedTextDriver::start() {
+ Mutex::Autolock autoLock(mLock);
+ switch (mState) {
+ case UNINITIALIZED:
+ return INVALID_OPERATION;
+ case STOPPED:
+ mPlayer->start();
+ break;
+ case PLAYING:
+ return OK;
+ case PAUSED:
+ mPlayer->resume();
+ break;
+ default:
+ TRESPASS();
+ }
+ mState = PLAYING;
+ return OK;
+}
+
+status_t TimedTextDriver::stop() {
+ return pause();
+}
+
+// TODO: Test if pause() works properly.
+// Scenario 1: start - pause - resume
+// Scenario 2: start - seek
+// Scenario 3: start - pause - seek - resume
+status_t TimedTextDriver::pause() {
+ Mutex::Autolock autoLock(mLock);
+ switch (mState) {
+ case UNINITIALIZED:
+ return INVALID_OPERATION;
+ case STOPPED:
+ return OK;
+ case PLAYING:
+ mPlayer->pause();
+ break;
+ case PAUSED:
+ return OK;
+ default:
+ TRESPASS();
+ }
+ mState = PAUSED;
+ return OK;
+}
+
+status_t TimedTextDriver::resume() {
+ return start();
+}
+
+status_t TimedTextDriver::seekToAsync(int64_t timeUs) {
+ mPlayer->seekToAsync(timeUs);
+ return OK;
+}
+
+status_t TimedTextDriver::setTimedTextTrackIndex(int32_t index) {
+ // TODO: This is current implementation for MediaPlayer::disableTimedText().
+ // Find better way for readability.
+ if (index < 0) {
+ mPlayer->pause();
+ return OK;
+ }
+
+ status_t ret = OK;
+ Mutex::Autolock autoLock(mLock);
+ switch (mState) {
+ case UNINITIALIZED:
+ ret = INVALID_OPERATION;
+ break;
+ case PAUSED:
+ ret = setTimedTextTrackIndex_l(index);
+ break;
+ case PLAYING:
+ mPlayer->pause();
+ ret = setTimedTextTrackIndex_l(index);
+ if (ret != OK) {
+ break;
+ }
+ mPlayer->start();
+ break;
+ case STOPPED:
+ // TODO: The only difference between STOPPED and PAUSED is this
+ // part. Revise the flow from "MediaPlayer::enableTimedText()" and
+ // remove one of the status, PAUSED and STOPPED, if possible.
+ ret = setTimedTextTrackIndex_l(index);
+ if (ret != OK) {
+ break;
+ }
+ mPlayer->start();
+ break;
+ defaut:
+ TRESPASS();
+ }
+ return ret;
+}
+
+status_t TimedTextDriver::addInBandTextSource(
+ const sp<MediaSource>& mediaSource) {
+ sp<TimedTextSource> source =
+ TimedTextSource::CreateTimedTextSource(mediaSource);
+ if (source == NULL) {
+ return ERROR_UNSUPPORTED;
+ }
+ Mutex::Autolock autoLock(mLock);
+ mTextInBandVector.add(source);
+ if (mState == UNINITIALIZED) {
+ mState = STOPPED;
+ }
+ return OK;
+}
+
+status_t TimedTextDriver::addOutOfBandTextSource(
+ const Parcel &request) {
+ // TODO: Define "TimedTextSource::CreateFromURI(uri)"
+ // and move below lines there..?
+
+ // String values written in Parcel are UTF-16 values.
+ const String16 uri16 = request.readString16();
+ String8 uri = String8(request.readString16());
+
+ uri.toLower();
+ // To support local subtitle file only for now
+ if (strncasecmp("file://", uri.string(), 7)) {
+ return ERROR_UNSUPPORTED;
+ }
+ sp<DataSource> dataSource =
+ DataSource::CreateFromURI(uri);
+ if (dataSource == NULL) {
+ return ERROR_UNSUPPORTED;
+ }
+
+ sp<TimedTextSource> source;
+ if (uri.getPathExtension() == String8(".srt")) {
+ source = TimedTextSource::CreateTimedTextSource(
+ dataSource, TimedTextSource::OUT_OF_BAND_FILE_SRT);
+ }
+
+ if (source == NULL) {
+ return ERROR_UNSUPPORTED;
+ }
+
+ Mutex::Autolock autoLock(mLock);
+
+ mTextOutOfBandVector.add(source);
+ if (mState == UNINITIALIZED) {
+ mState = STOPPED;
+ }
+ return OK;
+}
+
+} // namespace android
diff --git a/media/libstagefright/timedtext/TimedTextDriver.h b/media/libstagefright/timedtext/TimedTextDriver.h
new file mode 100644
index 0000000..efedb6e
--- /dev/null
+++ b/media/libstagefright/timedtext/TimedTextDriver.h
@@ -0,0 +1,81 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef TIMED_TEXT_DRIVER_H_
+#define TIMED_TEXT_DRIVER_H_
+
+#include <media/stagefright/foundation/ABase.h> // for DISALLOW_* macro
+#include <utils/Errors.h> // for status_t
+#include <utils/RefBase.h>
+#include <utils/threads.h>
+
+namespace android {
+
+class ALooper;
+class MediaPlayerBase;
+class MediaSource;
+class Parcel;
+class TimedTextPlayer;
+class TimedTextSource;
+
+class TimedTextDriver {
+public:
+ TimedTextDriver(const wp<MediaPlayerBase> &listener);
+
+ ~TimedTextDriver();
+
+ // TODO: pause-resume pair seems equivalent to stop-start pair.
+ // Check if it is replaceable with stop-start.
+ status_t start();
+ status_t stop();
+ status_t pause();
+ status_t resume();
+
+ status_t seekToAsync(int64_t timeUs);
+
+ status_t addInBandTextSource(const sp<MediaSource>& source);
+ status_t addOutOfBandTextSource(const Parcel &request);
+
+ status_t setTimedTextTrackIndex(int32_t index);
+
+private:
+ Mutex mLock;
+
+ enum State {
+ UNINITIALIZED,
+ STOPPED,
+ PLAYING,
+ PAUSED,
+ };
+
+ sp<ALooper> mLooper;
+ sp<TimedTextPlayer> mPlayer;
+ wp<MediaPlayerBase> mListener;
+
+ // Variables to be guarded by mLock.
+ State mState;
+ Vector<sp<TimedTextSource> > mTextInBandVector;
+ Vector<sp<TimedTextSource> > mTextOutOfBandVector;
+ // -- End of variables to be guarded by mLock
+
+ status_t setTimedTextTrackIndex_l(int32_t index);
+
+ DISALLOW_EVIL_CONSTRUCTORS(TimedTextDriver);
+};
+
+} // namespace android
+
+#endif // TIMED_TEXT_DRIVER_H_
diff --git a/media/libstagefright/timedtext/TimedTextInBandSource.cpp b/media/libstagefright/timedtext/TimedTextInBandSource.cpp
new file mode 100644
index 0000000..f2c4d54
--- /dev/null
+++ b/media/libstagefright/timedtext/TimedTextInBandSource.cpp
@@ -0,0 +1,118 @@
+ /*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "TimedTextInBandSource"
+#include <utils/Log.h>
+
+#include <binder/Parcel.h>
+#include <media/stagefright/MediaBuffer.h>
+#include <media/stagefright/MediaDebug.h> // CHECK_XX macro
+#include <media/stagefright/MediaDefs.h> // for MEDIA_MIMETYPE_xxx
+#include <media/stagefright/MediaErrors.h>
+#include <media/stagefright/MediaSource.h>
+#include <media/stagefright/MetaData.h>
+
+#include "TimedTextInBandSource.h"
+#include "TextDescriptions.h"
+
+namespace android {
+
+TimedTextInBandSource::TimedTextInBandSource(const sp<MediaSource>& mediaSource)
+ : mSource(mediaSource) {
+}
+
+TimedTextInBandSource::~TimedTextInBandSource() {
+}
+
+status_t TimedTextInBandSource::read(
+ int64_t *timeUs, Parcel *parcel, const MediaSource::ReadOptions *options) {
+ MediaBuffer *textBuffer = NULL;
+ status_t err = mSource->read(&textBuffer, options);
+ if (err != OK) {
+ return err;
+ }
+ CHECK(textBuffer != NULL);
+ textBuffer->meta_data()->findInt64(kKeyTime, timeUs);
+ // TODO: this is legacy code. when 'timeUs' can be <= 0?
+ if (*timeUs > 0) {
+ extractAndAppendLocalDescriptions(*timeUs, textBuffer, parcel);
+ }
+ textBuffer->release();
+ return OK;
+}
+
+// Each text sample consists of a string of text, optionally with sample
+// modifier description. The modifier description could specify a new
+// text style for the string of text. These descriptions are present only
+// if they are needed. This method is used to extract the modifier
+// description and append it at the end of the text.
+status_t TimedTextInBandSource::extractAndAppendLocalDescriptions(
+ int64_t timeUs, const MediaBuffer *textBuffer, Parcel *parcel) {
+ const void *data;
+ size_t size = 0;
+ int32_t flag = TextDescriptions::LOCAL_DESCRIPTIONS;
+
+ const char *mime;
+ CHECK(mSource->getFormat()->findCString(kKeyMIMEType, &mime));
+
+ if (strcasecmp(mime, MEDIA_MIMETYPE_TEXT_3GPP) == 0) {
+ data = textBuffer->data();
+ size = textBuffer->size();
+
+ if (size > 0) {
+ parcel->freeData();
+ flag |= TextDescriptions::IN_BAND_TEXT_3GPP;
+ return TextDescriptions::getParcelOfDescriptions(
+ (const uint8_t *)data, size, flag, timeUs / 1000, parcel);
+ }
+ return OK;
+ }
+ return ERROR_UNSUPPORTED;
+}
+
+// To extract and send the global text descriptions for all the text samples
+// in the text track or text file.
+// TODO: send error message to application via notifyListener()...?
+status_t TimedTextInBandSource::extractGlobalDescriptions(Parcel *parcel) {
+ const void *data;
+ size_t size = 0;
+ int32_t flag = TextDescriptions::GLOBAL_DESCRIPTIONS;
+
+ const char *mime;
+ CHECK(mSource->getFormat()->findCString(kKeyMIMEType, &mime));
+
+ // support 3GPP only for now
+ if (strcasecmp(mime, MEDIA_MIMETYPE_TEXT_3GPP) == 0) {
+ uint32_t type;
+ // get the 'tx3g' box content. This box contains the text descriptions
+ // used to render the text track
+ if (!mSource->getFormat()->findData(
+ kKeyTextFormatData, &type, &data, &size)) {
+ return ERROR_MALFORMED;
+ }
+
+ if (size > 0) {
+ flag |= TextDescriptions::IN_BAND_TEXT_3GPP;
+ return TextDescriptions::getParcelOfDescriptions(
+ (const uint8_t *)data, size, flag, 0, parcel);
+ }
+ return OK;
+ }
+ return ERROR_UNSUPPORTED;
+}
+
+} // namespace android
diff --git a/media/libstagefright/timedtext/TimedTextInBandSource.h b/media/libstagefright/timedtext/TimedTextInBandSource.h
new file mode 100644
index 0000000..26e5737
--- /dev/null
+++ b/media/libstagefright/timedtext/TimedTextInBandSource.h
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef TIMED_TEXT_IN_BAND_SOURCE_H_
+#define TIMED_TEXT_IN_BAND_SOURCE_H_
+
+#include <media/stagefright/MediaErrors.h>
+#include <media/stagefright/MediaSource.h>
+
+#include "TimedTextSource.h"
+
+namespace android {
+
+class MediaBuffer;
+class Parcel;
+
+class TimedTextInBandSource : public TimedTextSource {
+ public:
+ TimedTextInBandSource(const sp<MediaSource>& mediaSource);
+ virtual status_t start() { return mSource->start(); }
+ virtual status_t stop() { return mSource->stop(); }
+ virtual status_t read(
+ int64_t *timeUs,
+ Parcel *parcel,
+ const MediaSource::ReadOptions *options = NULL);
+ virtual status_t extractGlobalDescriptions(Parcel *parcel);
+
+ protected:
+ virtual ~TimedTextInBandSource();
+
+ private:
+ sp<MediaSource> mSource;
+
+ status_t extractAndAppendLocalDescriptions(
+ int64_t timeUs, const MediaBuffer *textBuffer, Parcel *parcel);
+
+ DISALLOW_EVIL_CONSTRUCTORS(TimedTextInBandSource);
+};
+
+} // namespace android
+
+#endif // TIMED_TEXT_IN_BAND_SOURCE_H_
diff --git a/media/libstagefright/timedtext/TimedTextParser.cpp b/media/libstagefright/timedtext/TimedTextParser.cpp
deleted file mode 100644
index caea0a4..0000000
--- a/media/libstagefright/timedtext/TimedTextParser.cpp
+++ /dev/null
@@ -1,262 +0,0 @@
-/*
- * 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.
- * 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.
- */
-
-#include "TimedTextParser.h"
-#include <media/stagefright/DataSource.h>
-
-namespace android {
-
-TimedTextParser::TimedTextParser()
- : mDataSource(NULL),
- mOffset(0),
- mIndex(0) {
-}
-
-TimedTextParser::~TimedTextParser() {
- reset();
-}
-
-status_t TimedTextParser::init(
- const sp<DataSource> &dataSource, FileType fileType) {
- mDataSource = dataSource;
- mFileType = fileType;
-
- status_t err;
- if ((err = scanFile()) != OK) {
- reset();
- return err;
- }
-
- return OK;
-}
-
-void TimedTextParser::reset() {
- mDataSource.clear();
- mTextVector.clear();
- mOffset = 0;
- mIndex = 0;
-}
-
-// scan the text file to get start/stop time and the
-// offset of each piece of text content
-status_t TimedTextParser::scanFile() {
- if (mFileType != OUT_OF_BAND_FILE_SRT) {
- return ERROR_UNSUPPORTED;
- }
-
- off64_t offset = 0;
- int64_t startTimeUs;
- bool endOfFile = false;
-
- while (!endOfFile) {
- TextInfo info;
- status_t err = getNextInSrtFileFormat(&offset, &startTimeUs, &info);
-
- if (err != OK) {
- if (err == ERROR_END_OF_STREAM) {
- endOfFile = true;
- } else {
- return err;
- }
- } else {
- mTextVector.add(startTimeUs, info);
- }
- }
-
- if (mTextVector.isEmpty()) {
- return ERROR_MALFORMED;
- }
- return OK;
-}
-
-// read one line started from *offset and store it into data.
-status_t TimedTextParser::readNextLine(off64_t *offset, AString *data) {
- char character;
-
- data->clear();
-
- while (true) {
- ssize_t err;
- if ((err = mDataSource->readAt(*offset, &character, 1)) < 1) {
- if (err == 0) {
- return ERROR_END_OF_STREAM;
- }
- return ERROR_IO;
- }
-
- (*offset) ++;
-
- // a line could end with CR, LF or CR + LF
- if (character == 10) {
- break;
- } else if (character == 13) {
- if ((err = mDataSource->readAt(*offset, &character, 1)) < 1) {
- if (err == 0) { // end of the stream
- return OK;
- }
- return ERROR_IO;
- }
-
- (*offset) ++;
-
- if (character != 10) {
- (*offset) --;
- }
- break;
- }
-
- data->append(character);
- }
-
- return OK;
-}
-
-/* SRT format:
- * Subtitle number
- * Start time --> End time
- * Text of subtitle (one or more lines)
- * Blank lines
- *
- * .srt file example:
- * 1
- * 00:00:20,000 --> 00:00:24,400
- * Altocumulus clouds occur between six thousand
- *
- * 2
- * 00:00:24,600 --> 00:00:27,800
- * and twenty thousand feet above ground level.
- */
-status_t TimedTextParser::getNextInSrtFileFormat(
- off64_t *offset, int64_t *startTimeUs, TextInfo *info) {
- AString data;
- status_t err;
-
- // To skip blank lines.
- do {
- if ((err = readNextLine(offset, &data)) != OK) {
- return err;
- }
- data.trim();
- } while(data.empty());
-
- // Just ignore the first non-blank line which is subtitle sequence number.
-
- if ((err = readNextLine(offset, &data)) != OK) {
- return err;
- }
- int hour1, hour2, min1, min2, sec1, sec2, msec1, msec2;
- // the start time format is: hours:minutes:seconds,milliseconds
- // 00:00:24,600 --> 00:00:27,800
- if (sscanf(data.c_str(), "%02d:%02d:%02d,%03d --> %02d:%02d:%02d,%03d",
- &hour1, &min1, &sec1, &msec1, &hour2, &min2, &sec2, &msec2) != 8) {
- return ERROR_MALFORMED;
- }
-
- *startTimeUs = ((hour1 * 3600 + min1 * 60 + sec1) * 1000 + msec1) * 1000ll;
- info->endTimeUs = ((hour2 * 3600 + min2 * 60 + sec2) * 1000 + msec2) * 1000ll;
- if (info->endTimeUs <= *startTimeUs) {
- return ERROR_MALFORMED;
- }
-
- info->offset = *offset;
-
- bool needMoreData = true;
- while (needMoreData) {
- if ((err = readNextLine(offset, &data)) != OK) {
- if (err == ERROR_END_OF_STREAM) {
- needMoreData = false;
- } else {
- return err;
- }
- }
-
- if (needMoreData) {
- data.trim();
- if (data.empty()) {
- // it's an empty line used to separate two subtitles
- needMoreData = false;
- }
- }
- }
-
- info->textLen = *offset - info->offset;
-
- return OK;
-}
-
-status_t TimedTextParser::getText(
- AString *text, int64_t *startTimeUs, int64_t *endTimeUs,
- const MediaSource::ReadOptions *options) {
- Mutex::Autolock autoLock(mLock);
-
- text->clear();
-
- int64_t seekTimeUs;
- MediaSource::ReadOptions::SeekMode mode;
- if (options && options->getSeekTo(&seekTimeUs, &mode)) {
- int64_t lastEndTimeUs = mTextVector.valueAt(mTextVector.size() - 1).endTimeUs;
- int64_t firstStartTimeUs = mTextVector.keyAt(0);
-
- if (seekTimeUs < 0 || seekTimeUs > lastEndTimeUs) {
- return ERROR_OUT_OF_RANGE;
- } else if (seekTimeUs < firstStartTimeUs) {
- mIndex = 0;
- } else {
- // binary search
- ssize_t low = 0;
- ssize_t high = mTextVector.size() - 1;
- ssize_t mid = 0;
- int64_t currTimeUs;
-
- while (low <= high) {
- mid = low + (high - low)/2;
- currTimeUs = mTextVector.keyAt(mid);
- const int diff = currTimeUs - seekTimeUs;
-
- if (diff == 0) {
- break;
- } else if (diff < 0) {
- low = mid + 1;
- } else {
- if ((high == mid + 1)
- && (seekTimeUs < mTextVector.keyAt(high))) {
- break;
- }
- high = mid - 1;
- }
- }
-
- mIndex = mid;
- }
- }
-
- TextInfo info = mTextVector.valueAt(mIndex);
- *startTimeUs = mTextVector.keyAt(mIndex);
- *endTimeUs = info.endTimeUs;
- mIndex ++;
-
- char *str = new char[info.textLen];
- if (mDataSource->readAt(info.offset, str, info.textLen) < info.textLen) {
- delete[] str;
- return ERROR_IO;
- }
-
- text->append(str, info.textLen);
- delete[] str;
- return OK;
-}
-
-} // namespace android
diff --git a/media/libstagefright/timedtext/TimedTextParser.h b/media/libstagefright/timedtext/TimedTextParser.h
deleted file mode 100644
index 44774c2..0000000
--- a/media/libstagefright/timedtext/TimedTextParser.h
+++ /dev/null
@@ -1,75 +0,0 @@
-/*
- * 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.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef TIMED_TEXT_PARSER_H_
-
-#define TIMED_TEXT_PARSER_H_
-
-#include <media/MediaPlayerInterface.h>
-#include <media/stagefright/foundation/ABase.h>
-#include <media/stagefright/foundation/AString.h>
-#include <media/stagefright/MediaSource.h>
-
-namespace android {
-
-class DataSource;
-
-class TimedTextParser : public RefBase {
-public:
- TimedTextParser();
- virtual ~TimedTextParser();
-
- enum FileType {
- OUT_OF_BAND_FILE_SRT = 1,
- };
-
- status_t getText(AString *text, int64_t *startTimeUs, int64_t *endTimeUs,
- const MediaSource::ReadOptions *options = NULL);
- status_t init(const sp<DataSource> &dataSource, FileType fileType);
- void reset();
-
-private:
- Mutex mLock;
-
- sp<DataSource> mDataSource;
- off64_t mOffset;
-
- struct TextInfo {
- int64_t endTimeUs;
- // the offset of the text in the original file
- off64_t offset;
- int textLen;
- };
-
- int mIndex;
- FileType mFileType;
-
- // the key indicated the start time of the text
- KeyedVector<int64_t, TextInfo> mTextVector;
-
- status_t getNextInSrtFileFormat(
- off64_t *offset, int64_t *startTimeUs, TextInfo *info);
- status_t readNextLine(off64_t *offset, AString *data);
-
- status_t scanFile();
-
- DISALLOW_EVIL_CONSTRUCTORS(TimedTextParser);
-};
-
-} // namespace android
-
-#endif // TIMED_TEXT_PARSER_H_
-
diff --git a/media/libstagefright/timedtext/TimedTextPlayer.cpp b/media/libstagefright/timedtext/TimedTextPlayer.cpp
index 3014b0b..8c2df88 100644
--- a/media/libstagefright/timedtext/TimedTextPlayer.cpp
+++ b/media/libstagefright/timedtext/TimedTextPlayer.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2011 The Android Open Source Project
+ * Copyright (C) 2012 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -18,399 +18,164 @@
#define LOG_TAG "TimedTextPlayer"
#include <utils/Log.h>
-#include <binder/IPCThreadState.h>
-
+#include <media/stagefright/foundation/AMessage.h>
#include <media/stagefright/MediaDebug.h>
-#include <media/stagefright/MediaDefs.h>
#include <media/stagefright/MediaErrors.h>
-#include <media/stagefright/MediaSource.h>
-#include <media/stagefright/MetaData.h>
-#include <media/stagefright/MediaBuffer.h>
-#include <media/stagefright/FileSource.h>
-#include <media/stagefright/Utils.h>
+#include <media/MediaPlayerInterface.h>
-#include "include/AwesomePlayer.h"
#include "TimedTextPlayer.h"
-#include "TimedTextParser.h"
-#include "TextDescriptions.h"
+
+#include "TimedTextDriver.h"
+#include "TimedTextSource.h"
namespace android {
-struct TimedTextEvent : public TimedEventQueue::Event {
- TimedTextEvent(
- TimedTextPlayer *player,
- void (TimedTextPlayer::*method)())
- : mPlayer(player),
- mMethod(method) {
- }
+static const int64_t kAdjustmentProcessingTimeUs = 100000ll;
-protected:
- virtual ~TimedTextEvent() {}
-
- virtual void fire(TimedEventQueue *queue, int64_t /* now_us */) {
- (mPlayer->*mMethod)();
- }
-
-private:
- TimedTextPlayer *mPlayer;
- void (TimedTextPlayer::*mMethod)();
-
- TimedTextEvent(const TimedTextEvent &);
- TimedTextEvent &operator=(const TimedTextEvent &);
-};
-
-TimedTextPlayer::TimedTextPlayer(
- AwesomePlayer *observer,
- const wp<MediaPlayerBase> &listener,
- TimedEventQueue *queue)
- : mSource(NULL),
- mOutOfBandSource(NULL),
- mSeekTimeUs(0),
- mStarted(false),
- mTextEventPending(false),
- mQueue(queue),
- mListener(listener),
- mObserver(observer),
- mTextBuffer(NULL),
- mTextParser(NULL),
- mTextType(kNoText) {
- mTextEvent = new TimedTextEvent(this, &TimedTextPlayer::onTextEvent);
+TimedTextPlayer::TimedTextPlayer(const wp<MediaPlayerBase> &listener)
+ : mListener(listener),
+ mSource(NULL),
+ mSendSubtitleGeneration(0) {
}
TimedTextPlayer::~TimedTextPlayer() {
- if (mStarted) {
- reset();
+ if (mSource != NULL) {
+ mSource->stop();
+ mSource.clear();
+ mSource = NULL;
}
-
- mTextTrackVector.clear();
- mTextOutOfBandVector.clear();
}
-status_t TimedTextPlayer::start(uint8_t index) {
- CHECK(!mStarted);
-
- if (index >=
- mTextTrackVector.size() + mTextOutOfBandVector.size()) {
- ALOGE("Incorrect text track index: %d", index);
- return BAD_VALUE;
- }
-
- status_t err;
- if (index < mTextTrackVector.size()) { // start an in-band text
- mSource = mTextTrackVector.itemAt(index);
-
- err = mSource->start();
-
- if (err != OK) {
- return err;
- }
- mTextType = kInBandText;
- } else { // start an out-of-band text
- OutOfBandText text =
- mTextOutOfBandVector.itemAt(index - mTextTrackVector.size());
-
- mOutOfBandSource = text.source;
- TimedTextParser::FileType fileType = text.type;
-
- if (mTextParser == NULL) {
- mTextParser = new TimedTextParser();
- }
-
- if ((err = mTextParser->init(mOutOfBandSource, fileType)) != OK) {
- return err;
- }
- mTextType = kOutOfBandText;
- }
-
- // send sample description format
- if ((err = extractAndSendGlobalDescriptions()) != OK) {
- return err;
- }
-
- int64_t positionUs;
- mObserver->getPosition(&positionUs);
- seekTo(positionUs);
-
- postTextEvent();
-
- mStarted = true;
-
- return OK;
+void TimedTextPlayer::start() {
+ sp<AMessage> msg = new AMessage(kWhatSeek, id());
+ msg->setInt64("seekTimeUs", -1);
+ msg->post();
}
void TimedTextPlayer::pause() {
- CHECK(mStarted);
-
- cancelTextEvent();
+ (new AMessage(kWhatPause, id()))->post();
}
void TimedTextPlayer::resume() {
- CHECK(mStarted);
-
- postTextEvent();
+ start();
}
-void TimedTextPlayer::reset() {
- CHECK(mStarted);
+void TimedTextPlayer::seekToAsync(int64_t timeUs) {
+ sp<AMessage> msg = new AMessage(kWhatSeek, id());
+ msg->setInt64("seekTimeUs", timeUs);
+ msg->post();
+}
- // send an empty text to clear the screen
- notifyListener(MEDIA_TIMED_TEXT);
+void TimedTextPlayer::setDataSource(sp<TimedTextSource> source) {
+ sp<AMessage> msg = new AMessage(kWhatSetSource, id());
+ msg->setObject("source", source);
+ msg->post();
+}
- cancelTextEvent();
-
- mSeeking = false;
- mStarted = false;
-
- if (mTextType == kInBandText) {
- if (mTextBuffer != NULL) {
- mTextBuffer->release();
- mTextBuffer = NULL;
+void TimedTextPlayer::onMessageReceived(const sp<AMessage> &msg) {
+ switch (msg->what()) {
+ case kWhatPause: {
+ mSendSubtitleGeneration++;
+ break;
}
-
- if (mSource != NULL) {
- mSource->stop();
- mSource.clear();
- mSource = NULL;
+ case kWhatSeek: {
+ int64_t seekTimeUs = 0;
+ msg->findInt64("seekTimeUs", &seekTimeUs);
+ if (seekTimeUs < 0) {
+ sp<MediaPlayerBase> listener = mListener.promote();
+ if (listener != NULL) {
+ int32_t positionMs = 0;
+ listener->getCurrentPosition(&positionMs);
+ seekTimeUs = positionMs * 1000ll;
+ }
+ }
+ doSeekAndRead(seekTimeUs);
+ break;
}
- } else {
- if (mTextParser != NULL) {
- mTextParser.clear();
- mTextParser = NULL;
+ case kWhatSendSubtitle: {
+ int32_t generation;
+ CHECK(msg->findInt32("generation", &generation));
+ if (generation != mSendSubtitleGeneration) {
+ // Drop obsolete msg.
+ break;
+ }
+ sp<RefBase> obj;
+ msg->findObject("subtitle", &obj);
+ if (obj != NULL) {
+ sp<ParcelEvent> parcelEvent;
+ parcelEvent = static_cast<ParcelEvent*>(obj.get());
+ notifyListener(MEDIA_TIMED_TEXT, &(parcelEvent->parcel));
+ } else {
+ notifyListener(MEDIA_TIMED_TEXT);
+ }
+ doRead();
+ break;
}
- if (mOutOfBandSource != NULL) {
- mOutOfBandSource.clear();
- mOutOfBandSource = NULL;
+ case kWhatSetSource: {
+ sp<RefBase> obj;
+ msg->findObject("source", &obj);
+ if (obj == NULL) break;
+ if (mSource != NULL) {
+ mSource->stop();
+ }
+ mSource = static_cast<TimedTextSource*>(obj.get());
+ mSource->start();
+ Parcel parcel;
+ if (mSource->extractGlobalDescriptions(&parcel) == OK &&
+ parcel.dataSize() > 0) {
+ notifyListener(MEDIA_TIMED_TEXT, &parcel);
+ } else {
+ notifyListener(MEDIA_TIMED_TEXT);
+ }
+ break;
}
}
}
-status_t TimedTextPlayer::seekTo(int64_t time_us) {
- Mutex::Autolock autoLock(mLock);
-
- mSeeking = true;
- mSeekTimeUs = time_us;
-
- postTextEvent();
-
- return OK;
-}
-
-status_t TimedTextPlayer::setTimedTextTrackIndex(int32_t index) {
- if (index >=
- (int)(mTextTrackVector.size() + mTextOutOfBandVector.size())) {
- return BAD_VALUE;
- }
-
- if (mStarted) {
- reset();
- }
-
- if (index >= 0) {
- return start(index);
- }
- return OK;
-}
-
-void TimedTextPlayer::onTextEvent() {
- Mutex::Autolock autoLock(mLock);
-
- if (!mTextEventPending) {
- return;
- }
- mTextEventPending = false;
-
- if (mData.dataSize() > 0) {
- notifyListener(MEDIA_TIMED_TEXT, &mData);
- mData.freeData();
- }
-
+void TimedTextPlayer::doSeekAndRead(int64_t seekTimeUs) {
MediaSource::ReadOptions options;
- if (mSeeking) {
- options.setSeekTo(mSeekTimeUs,
- MediaSource::ReadOptions::SEEK_PREVIOUS_SYNC);
- mSeeking = false;
-
- notifyListener(MEDIA_TIMED_TEXT); //empty text to clear the screen
- }
-
- int64_t positionUs, timeUs;
- mObserver->getPosition(&positionUs);
-
- if (mTextType == kInBandText) {
- if (mSource->read(&mTextBuffer, &options) != OK) {
- return;
- }
-
- mTextBuffer->meta_data()->findInt64(kKeyTime, &timeUs);
- } else {
- int64_t endTimeUs;
- if (mTextParser->getText(
- &mText, &timeUs, &endTimeUs, &options) != OK) {
- return;
- }
- }
-
- if (timeUs > 0) {
- extractAndAppendLocalDescriptions(timeUs);
- }
-
- if (mTextType == kInBandText) {
- if (mTextBuffer != NULL) {
- mTextBuffer->release();
- mTextBuffer = NULL;
- }
- } else {
- mText.clear();
- }
-
- //send the text now
- if (timeUs <= positionUs + 100000ll) {
- postTextEvent();
- } else {
- postTextEvent(timeUs - positionUs - 100000ll);
- }
+ options.setSeekTo(seekTimeUs, MediaSource::ReadOptions::SEEK_PREVIOUS_SYNC);
+ doRead(&options);
}
-void TimedTextPlayer::postTextEvent(int64_t delayUs) {
- if (mTextEventPending) {
- return;
- }
-
- mTextEventPending = true;
- mQueue->postEventWithDelay(mTextEvent, delayUs < 0 ? 10000 : delayUs);
+void TimedTextPlayer::doRead(MediaSource::ReadOptions* options) {
+ int64_t timeUs = 0;
+ sp<ParcelEvent> parcelEvent = new ParcelEvent();
+ mSource->read(&timeUs, &(parcelEvent->parcel), options);
+ postTextEvent(parcelEvent, timeUs);
}
-void TimedTextPlayer::cancelTextEvent() {
- mQueue->cancelEvent(mTextEvent->eventID());
- mTextEventPending = false;
-}
+void TimedTextPlayer::postTextEvent(const sp<ParcelEvent>& parcel, int64_t timeUs) {
+ sp<MediaPlayerBase> listener = mListener.promote();
+ if (listener != NULL) {
+ int64_t positionUs, delayUs;
+ int32_t positionMs = 0;
+ listener->getCurrentPosition(&positionMs);
+ positionUs = positionMs * 1000;
-void TimedTextPlayer::addTextSource(sp<MediaSource> source) {
- Mutex::Autolock autoLock(mLock);
- mTextTrackVector.add(source);
-}
-
-status_t TimedTextPlayer::setParameter(int key, const Parcel &request) {
- Mutex::Autolock autoLock(mLock);
-
- if (key == KEY_PARAMETER_TIMED_TEXT_ADD_OUT_OF_BAND_SOURCE) {
- const String16 uri16 = request.readString16();
- String8 uri = String8(uri16);
- KeyedVector<String8, String8> headers;
-
- // To support local subtitle file only for now
- if (strncasecmp("file://", uri.string(), 7)) {
- return INVALID_OPERATION;
- }
- sp<DataSource> dataSource =
- DataSource::CreateFromURI(uri, &headers);
- status_t err = dataSource->initCheck();
-
- if (err != OK) {
- return err;
- }
-
- OutOfBandText text;
- text.source = dataSource;
- if (uri.getPathExtension() == String8(".srt")) {
- text.type = TimedTextParser::OUT_OF_BAND_FILE_SRT;
+ if (timeUs <= positionUs + kAdjustmentProcessingTimeUs) {
+ delayUs = 0;
} else {
- return ERROR_UNSUPPORTED;
+ delayUs = timeUs - positionUs - kAdjustmentProcessingTimeUs;
}
-
- mTextOutOfBandVector.add(text);
-
- return OK;
+ sp<AMessage> msg = new AMessage(kWhatSendSubtitle, id());
+ msg->setInt32("generation", mSendSubtitleGeneration);
+ if (parcel != NULL) {
+ msg->setObject("subtitle", parcel);
+ }
+ msg->post(delayUs);
}
- return INVALID_OPERATION;
}
void TimedTextPlayer::notifyListener(int msg, const Parcel *parcel) {
- if (mListener != NULL) {
- sp<MediaPlayerBase> listener = mListener.promote();
-
- if (listener != NULL) {
- if (parcel && (parcel->dataSize() > 0)) {
- listener->sendEvent(msg, 0, 0, parcel);
- } else { // send an empty timed text to clear the screen
- listener->sendEvent(msg);
- }
+ sp<MediaPlayerBase> listener = mListener.promote();
+ if (listener != NULL) {
+ if (parcel != NULL && (parcel->dataSize() > 0)) {
+ listener->sendEvent(msg, 0, 0, parcel);
+ } else { // send an empty timed text to clear the screen
+ listener->sendEvent(msg);
}
}
}
-// Each text sample consists of a string of text, optionally with sample
-// modifier description. The modifier description could specify a new
-// text style for the string of text. These descriptions are present only
-// if they are needed. This method is used to extract the modifier
-// description and append it at the end of the text.
-status_t TimedTextPlayer::extractAndAppendLocalDescriptions(int64_t timeUs) {
- const void *data;
- size_t size = 0;
- int32_t flag = TextDescriptions::LOCAL_DESCRIPTIONS;
-
- if (mTextType == kInBandText) {
- const char *mime;
- CHECK(mSource->getFormat()->findCString(kKeyMIMEType, &mime));
-
- if (!strcasecmp(mime, MEDIA_MIMETYPE_TEXT_3GPP)) {
- flag |= TextDescriptions::IN_BAND_TEXT_3GPP;
- data = mTextBuffer->data();
- size = mTextBuffer->size();
- } else {
- // support 3GPP only for now
- return ERROR_UNSUPPORTED;
- }
- } else {
- data = mText.c_str();
- size = mText.size();
- flag |= TextDescriptions::OUT_OF_BAND_TEXT_SRT;
- }
-
- if ((size > 0) && (flag != TextDescriptions::LOCAL_DESCRIPTIONS)) {
- mData.freeData();
- return TextDescriptions::getParcelOfDescriptions(
- (const uint8_t *)data, size, flag, timeUs / 1000, &mData);
- }
-
- return OK;
-}
-
-// To extract and send the global text descriptions for all the text samples
-// in the text track or text file.
-status_t TimedTextPlayer::extractAndSendGlobalDescriptions() {
- const void *data;
- size_t size = 0;
- int32_t flag = TextDescriptions::GLOBAL_DESCRIPTIONS;
-
- if (mTextType == kInBandText) {
- const char *mime;
- CHECK(mSource->getFormat()->findCString(kKeyMIMEType, &mime));
-
- // support 3GPP only for now
- if (!strcasecmp(mime, MEDIA_MIMETYPE_TEXT_3GPP)) {
- uint32_t type;
- // get the 'tx3g' box content. This box contains the text descriptions
- // used to render the text track
- if (!mSource->getFormat()->findData(
- kKeyTextFormatData, &type, &data, &size)) {
- return ERROR_MALFORMED;
- }
-
- flag |= TextDescriptions::IN_BAND_TEXT_3GPP;
- }
- }
-
- if ((size > 0) && (flag != TextDescriptions::GLOBAL_DESCRIPTIONS)) {
- Parcel parcel;
- if (TextDescriptions::getParcelOfDescriptions(
- (const uint8_t *)data, size, flag, 0, &parcel) == OK) {
- if (parcel.dataSize() > 0) {
- notifyListener(MEDIA_TIMED_TEXT, &parcel);
- }
- }
- }
-
- return OK;
-}
-}
+} // namespace android
diff --git a/media/libstagefright/timedtext/TimedTextPlayer.h b/media/libstagefright/timedtext/TimedTextPlayer.h
index a744db5..837beeb 100644
--- a/media/libstagefright/timedtext/TimedTextPlayer.h
+++ b/media/libstagefright/timedtext/TimedTextPlayer.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2011 The Android Open Source Project
+ * Copyright (C) 2012 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -15,99 +15,61 @@
*/
#ifndef TIMEDTEXT_PLAYER_H_
-
#define TIMEDTEXT_PLAYER_H_
-#include <media/MediaPlayerInterface.h>
+#include <binder/Parcel.h>
#include <media/stagefright/foundation/ABase.h>
-#include <media/stagefright/foundation/AString.h>
+#include <media/stagefright/foundation/AHandler.h>
+#include <media/stagefright/MediaSource.h>
+#include <utils/RefBase.h>
-#include "include/TimedEventQueue.h"
-#include "TimedTextParser.h"
+#include "TimedTextSource.h"
namespace android {
-class MediaSource;
-class AwesomePlayer;
-class MediaBuffer;
+class AMessage;
+class MediaPlayerBase;
+class TimedTextDriver;
+class TimedTextSource;
-class TimedTextPlayer {
+class TimedTextPlayer : public AHandler {
public:
- TimedTextPlayer(AwesomePlayer *observer,
- const wp<MediaPlayerBase> &listener,
- TimedEventQueue *queue);
+ TimedTextPlayer(const wp<MediaPlayerBase> &listener);
virtual ~TimedTextPlayer();
- // index: the index of the text track which will
- // be turned on
- status_t start(uint8_t index);
-
+ void start();
void pause();
-
void resume();
+ void seekToAsync(int64_t timeUs);
+ void setDataSource(sp<TimedTextSource> source);
- status_t seekTo(int64_t time_us);
-
- void addTextSource(sp<MediaSource> source);
-
- status_t setTimedTextTrackIndex(int32_t index);
- status_t setParameter(int key, const Parcel &request);
+protected:
+ virtual void onMessageReceived(const sp<AMessage> &msg);
private:
- enum TextType {
- kNoText = 0,
- kInBandText = 1,
- kOutOfBandText = 2,
+ enum {
+ kWhatPause = 'paus',
+ kWhatSeek = 'seek',
+ kWhatSendSubtitle = 'send',
+ kWhatSetSource = 'ssrc',
};
- Mutex mLock;
-
- sp<MediaSource> mSource;
- sp<DataSource> mOutOfBandSource;
-
- bool mSeeking;
- int64_t mSeekTimeUs;
-
- bool mStarted;
-
- sp<TimedEventQueue::Event> mTextEvent;
- bool mTextEventPending;
-
- TimedEventQueue *mQueue;
+ // To add Parcel into an AMessage as an object, it should be 'RefBase'.
+ struct ParcelEvent : public RefBase {
+ Parcel parcel;
+ };
wp<MediaPlayerBase> mListener;
- AwesomePlayer *mObserver;
+ sp<TimedTextSource> mSource;
+ int32_t mSendSubtitleGeneration;
- MediaBuffer *mTextBuffer;
- Parcel mData;
-
- // for in-band timed text
- Vector<sp<MediaSource> > mTextTrackVector;
-
- // for out-of-band timed text
- struct OutOfBandText {
- TimedTextParser::FileType type;
- sp<DataSource> source;
- };
- Vector<OutOfBandText > mTextOutOfBandVector;
-
- sp<TimedTextParser> mTextParser;
- AString mText;
-
- TextType mTextType;
-
- void reset();
-
+ void doSeekAndRead(int64_t seekTimeUs);
+ void doRead(MediaSource::ReadOptions* options = NULL);
void onTextEvent();
- void postTextEvent(int64_t delayUs = -1);
- void cancelTextEvent();
-
+ void postTextEvent(const sp<ParcelEvent>& parcel = NULL, int64_t timeUs = -1);
void notifyListener(int msg, const Parcel *parcel = NULL);
- status_t extractAndAppendLocalDescriptions(int64_t timeUs);
- status_t extractAndSendGlobalDescriptions();
-
DISALLOW_EVIL_CONSTRUCTORS(TimedTextPlayer);
};
diff --git a/media/libstagefright/timedtext/TimedTextSRTSource.cpp b/media/libstagefright/timedtext/TimedTextSRTSource.cpp
new file mode 100644
index 0000000..3752d34
--- /dev/null
+++ b/media/libstagefright/timedtext/TimedTextSRTSource.cpp
@@ -0,0 +1,275 @@
+ /*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "TimedTextSRTSource"
+#include <utils/Log.h>
+
+#include <binder/Parcel.h>
+#include <media/stagefright/foundation/AString.h>
+#include <media/stagefright/DataSource.h>
+#include <media/stagefright/MediaErrors.h>
+#include <media/stagefright/MediaSource.h>
+
+#include "TimedTextSRTSource.h"
+#include "TextDescriptions.h"
+
+namespace android {
+
+TimedTextSRTSource::TimedTextSRTSource(const sp<DataSource>& dataSource)
+ : mSource(dataSource),
+ mIndex(0) {
+}
+
+TimedTextSRTSource::~TimedTextSRTSource() {
+}
+
+status_t TimedTextSRTSource::start() {
+ status_t err = scanFile();
+ if (err != OK) {
+ reset();
+ }
+ return err;
+}
+
+void TimedTextSRTSource::reset() {
+ mTextVector.clear();
+ mIndex = 0;
+}
+
+status_t TimedTextSRTSource::stop() {
+ reset();
+ return OK;
+}
+
+status_t TimedTextSRTSource::read(
+ int64_t *timeUs,
+ Parcel *parcel,
+ const MediaSource::ReadOptions *options) {
+ int64_t endTimeUs;
+ AString text;
+ status_t err = getText(options, &text, timeUs, &endTimeUs);
+ if (err != OK) {
+ return err;
+ }
+
+ if (*timeUs > 0) {
+ extractAndAppendLocalDescriptions(*timeUs, text, parcel);
+ }
+ return OK;
+}
+
+status_t TimedTextSRTSource::scanFile() {
+ off64_t offset = 0;
+ int64_t startTimeUs;
+ bool endOfFile = false;
+
+ while (!endOfFile) {
+ TextInfo info;
+ status_t err = getNextSubtitleInfo(&offset, &startTimeUs, &info);
+ switch (err) {
+ case OK:
+ mTextVector.add(startTimeUs, info);
+ break;
+ case ERROR_END_OF_STREAM:
+ endOfFile = true;
+ break;
+ default:
+ return err;
+ }
+ }
+ if (mTextVector.isEmpty()) {
+ return ERROR_MALFORMED;
+ }
+ return OK;
+}
+
+/* SRT format:
+ * Subtitle number
+ * Start time --> End time
+ * Text of subtitle (one or more lines)
+ * Blank lines
+ *
+ * .srt file example:
+ * 1
+ * 00:00:20,000 --> 00:00:24,400
+ * Altocumulus clouds occr between six thousand
+ *
+ * 2
+ * 00:00:24,600 --> 00:00:27,800
+ * and twenty thousand feet above ground level.
+ */
+status_t TimedTextSRTSource::getNextSubtitleInfo(
+ off64_t *offset, int64_t *startTimeUs, TextInfo *info) {
+ AString data;
+ status_t err;
+
+ // To skip blank lines.
+ do {
+ if ((err = readNextLine(offset, &data)) != OK) {
+ return err;
+ }
+ data.trim();
+ } while (data.empty());
+
+ // Just ignore the first non-blank line which is subtitle sequence number.
+ if ((err = readNextLine(offset, &data)) != OK) {
+ return err;
+ }
+ int hour1, hour2, min1, min2, sec1, sec2, msec1, msec2;
+ // the start time format is: hours:minutes:seconds,milliseconds
+ // 00:00:24,600 --> 00:00:27,800
+ if (sscanf(data.c_str(), "%02d:%02d:%02d,%03d --> %02d:%02d:%02d,%03d",
+ &hour1, &min1, &sec1, &msec1, &hour2, &min2, &sec2, &msec2) != 8) {
+ return ERROR_MALFORMED;
+ }
+
+ *startTimeUs = ((hour1 * 3600 + min1 * 60 + sec1) * 1000 + msec1) * 1000ll;
+ info->endTimeUs = ((hour2 * 3600 + min2 * 60 + sec2) * 1000 + msec2) * 1000ll;
+ if (info->endTimeUs <= *startTimeUs) {
+ return ERROR_MALFORMED;
+ }
+
+ info->offset = *offset;
+ bool needMoreData = true;
+ while (needMoreData) {
+ if ((err = readNextLine(offset, &data)) != OK) {
+ if (err == ERROR_END_OF_STREAM) {
+ needMoreData = false;
+ } else {
+ return err;
+ }
+ }
+
+ if (needMoreData) {
+ data.trim();
+ if (data.empty()) {
+ // it's an empty line used to separate two subtitles
+ needMoreData = false;
+ }
+ }
+ }
+ info->textLen = *offset - info->offset;
+ return OK;
+}
+
+status_t TimedTextSRTSource::readNextLine(off64_t *offset, AString *data) {
+ data->clear();
+ while (true) {
+ ssize_t readSize;
+ char character;
+ if ((readSize = mSource->readAt(*offset, &character, 1)) < 1) {
+ if (readSize == 0) {
+ return ERROR_END_OF_STREAM;
+ }
+ return ERROR_IO;
+ }
+
+ (*offset)++;
+
+ // a line could end with CR, LF or CR + LF
+ if (character == 10) {
+ break;
+ } else if (character == 13) {
+ if ((readSize = mSource->readAt(*offset, &character, 1)) < 1) {
+ if (readSize == 0) { // end of the stream
+ return OK;
+ }
+ return ERROR_IO;
+ }
+
+ (*offset)++;
+ if (character != 10) {
+ (*offset)--;
+ }
+ break;
+ }
+ data->append(character);
+ }
+ return OK;
+}
+
+status_t TimedTextSRTSource::getText(
+ const MediaSource::ReadOptions *options,
+ AString *text, int64_t *startTimeUs, int64_t *endTimeUs) {
+ text->clear();
+ int64_t seekTimeUs;
+ MediaSource::ReadOptions::SeekMode mode;
+ if (options != NULL && options->getSeekTo(&seekTimeUs, &mode)) {
+ int64_t lastEndTimeUs =
+ mTextVector.valueAt(mTextVector.size() - 1).endTimeUs;
+ int64_t firstStartTimeUs = mTextVector.keyAt(0);
+ if (seekTimeUs < 0 || seekTimeUs > lastEndTimeUs) {
+ return ERROR_OUT_OF_RANGE;
+ } else if (seekTimeUs < firstStartTimeUs) {
+ mIndex = 0;
+ } else {
+ // binary search
+ ssize_t low = 0;
+ ssize_t high = mTextVector.size() - 1;
+ ssize_t mid = 0;
+ int64_t currTimeUs;
+
+ while (low <= high) {
+ mid = low + (high - low)/2;
+ currTimeUs = mTextVector.keyAt(mid);
+ const int diff = currTimeUs - seekTimeUs;
+
+ if (diff == 0) {
+ break;
+ } else if (diff < 0) {
+ low = mid + 1;
+ } else {
+ if ((high == mid + 1)
+ && (seekTimeUs < mTextVector.keyAt(high))) {
+ break;
+ }
+ high = mid - 1;
+ }
+ }
+ mIndex = mid;
+ }
+ }
+ const TextInfo &info = mTextVector.valueAt(mIndex);
+ *startTimeUs = mTextVector.keyAt(mIndex);
+ *endTimeUs = info.endTimeUs;
+ mIndex++;
+
+ char *str = new char[info.textLen];
+ if (mSource->readAt(info.offset, str, info.textLen) < info.textLen) {
+ delete[] str;
+ return ERROR_IO;
+ }
+ text->append(str, info.textLen);
+ delete[] str;
+ return OK;
+}
+
+status_t TimedTextSRTSource::extractAndAppendLocalDescriptions(
+ int64_t timeUs, const AString &text, Parcel *parcel) {
+ const void *data = text.c_str();
+ size_t size = text.size();
+ int32_t flag = TextDescriptions::LOCAL_DESCRIPTIONS |
+ TextDescriptions::OUT_OF_BAND_TEXT_SRT;
+
+ if (size > 0) {
+ return TextDescriptions::getParcelOfDescriptions(
+ (const uint8_t *)data, size, flag, timeUs / 1000, parcel);
+ }
+ return OK;
+}
+
+} // namespace android
diff --git a/media/libstagefright/timedtext/TimedTextSRTSource.h b/media/libstagefright/timedtext/TimedTextSRTSource.h
new file mode 100644
index 0000000..a0734d9
--- /dev/null
+++ b/media/libstagefright/timedtext/TimedTextSRTSource.h
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef TIMED_TEXT_SRT_SOURCE_H_
+#define TIMED_TEXT_SRT_SOURCE_H_
+
+#include <media/stagefright/MediaErrors.h>
+#include <media/stagefright/MediaSource.h>
+#include <utils/Compat.h> // off64_t
+
+#include "TimedTextSource.h"
+
+namespace android {
+
+class AString;
+class DataSource;
+class MediaBuffer;
+class Parcel;
+
+class TimedTextSRTSource : public TimedTextSource {
+ public:
+ TimedTextSRTSource(const sp<DataSource>& dataSource);
+ virtual status_t start();
+ virtual status_t stop();
+ virtual status_t read(
+ int64_t *timeUs,
+ Parcel *parcel,
+ const MediaSource::ReadOptions *options = NULL);
+
+ protected:
+ virtual ~TimedTextSRTSource();
+
+ private:
+ sp<DataSource> mSource;
+
+ struct TextInfo {
+ int64_t endTimeUs;
+ // The offset of the text in the original file.
+ off64_t offset;
+ int textLen;
+ };
+
+ int mIndex;
+ KeyedVector<int64_t, TextInfo> mTextVector;
+
+ void reset();
+ status_t scanFile();
+ status_t getNextSubtitleInfo(
+ off64_t *offset, int64_t *startTimeUs, TextInfo *info);
+ status_t readNextLine(off64_t *offset, AString *data);
+ status_t getText(
+ const MediaSource::ReadOptions *options,
+ AString *text, int64_t *startTimeUs, int64_t *endTimeUs);
+ status_t extractAndAppendLocalDescriptions(
+ int64_t timeUs, const AString &text, Parcel *parcel);
+
+ DISALLOW_EVIL_CONSTRUCTORS(TimedTextSRTSource);
+};
+
+} // namespace android
+
+#endif // TIMED_TEXT_SRT_SOURCE_H_
diff --git a/media/libstagefright/timedtext/TimedTextSource.cpp b/media/libstagefright/timedtext/TimedTextSource.cpp
new file mode 100644
index 0000000..9efe67c
--- /dev/null
+++ b/media/libstagefright/timedtext/TimedTextSource.cpp
@@ -0,0 +1,53 @@
+ /*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "TimedTextSource"
+#include <utils/Log.h>
+
+#include <media/stagefright/DataSource.h>
+#include <media/stagefright/MediaSource.h>
+
+#include "TimedTextSource.h"
+
+#include "TimedTextInBandSource.h"
+#include "TimedTextSRTSource.h"
+
+namespace android {
+
+// static
+sp<TimedTextSource> TimedTextSource::CreateTimedTextSource(
+ const sp<MediaSource>& mediaSource) {
+ return new TimedTextInBandSource(mediaSource);
+}
+
+// static
+sp<TimedTextSource> TimedTextSource::CreateTimedTextSource(
+ const sp<DataSource>& dataSource, FileType filetype) {
+ switch(filetype) {
+ case OUT_OF_BAND_FILE_SRT:
+ return new TimedTextSRTSource(dataSource);
+ case OUT_OF_BAND_FILE_SMI:
+ // TODO: Implement for SMI.
+ ALOGE("Supporting SMI is not implemented yet");
+ break;
+ default:
+ ALOGE("Undefined subtitle format. : %d", filetype);
+ }
+ return NULL;
+}
+
+} // namespace android
diff --git a/media/libstagefright/timedtext/TimedTextSource.h b/media/libstagefright/timedtext/TimedTextSource.h
new file mode 100644
index 0000000..06bae71
--- /dev/null
+++ b/media/libstagefright/timedtext/TimedTextSource.h
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef TIMED_TEXT_SOURCE_H_
+#define TIMED_TEXT_SOURCE_H_
+
+#include <media/stagefright/foundation/ABase.h> // for DISALLOW_XXX macro.
+#include <media/stagefright/MediaErrors.h>
+#include <media/stagefright/MediaSource.h> // for MediaSource::ReadOptions
+#include <utils/RefBase.h>
+
+namespace android {
+
+class DataSource;
+class Parcel;
+
+class TimedTextSource : public RefBase {
+ public:
+ enum FileType {
+ OUT_OF_BAND_FILE_SRT = 1,
+ OUT_OF_BAND_FILE_SMI = 2,
+ };
+ static sp<TimedTextSource> CreateTimedTextSource(
+ const sp<MediaSource>& source);
+ static sp<TimedTextSource> CreateTimedTextSource(
+ const sp<DataSource>& source, FileType filetype);
+ TimedTextSource() {}
+ virtual status_t start() = 0;
+ virtual status_t stop() = 0;
+ // Returns subtitle parcel and its start time.
+ virtual status_t read(
+ int64_t *timeUs,
+ Parcel *parcel,
+ const MediaSource::ReadOptions *options = NULL) = 0;
+ virtual status_t extractGlobalDescriptions(Parcel *parcel) {
+ return INVALID_OPERATION;
+ }
+
+ protected:
+ virtual ~TimedTextSource() { }
+
+ private:
+ DISALLOW_EVIL_CONSTRUCTORS(TimedTextSource);
+};
+
+} // namespace android
+
+#endif // TIMED_TEXT_SOURCE_H_
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/audio/MediaAudioManagerTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/audio/MediaAudioManagerTest.java
index c9087d1..7967ce7 100644
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/audio/MediaAudioManagerTest.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/audio/MediaAudioManagerTest.java
@@ -19,8 +19,13 @@
import com.android.mediaframeworktest.MediaFrameworkTest;
import android.content.Context;
import android.media.AudioManager;
+import android.media.MediaPlayer;
+import android.media.AudioManager.OnAudioFocusChangeListener;
+import android.os.Looper;
import android.test.ActivityInstrumentationTestCase2;
import android.test.suitebuilder.annotation.MediumTest;
+import android.test.suitebuilder.annotation.LargeTest;
+import android.util.Log;
/**
* Junit / Instrumentation test case for the media AudioManager api
@@ -28,8 +33,13 @@
public class MediaAudioManagerTest extends ActivityInstrumentationTestCase2<MediaFrameworkTest> {
- private String TAG = "MediaAudioManagerTest";
+ private final static String TAG = "MediaAudioManagerTest";
+ // the AudioManager used throughout the test
private AudioManager mAudioManager;
+ // keep track of looper for AudioManager so we can terminate it
+ private Looper mAudioManagerLooper;
+ private final Object mLooperLock = new Object();
+ private final static int WAIT_FOR_LOOPER_TO_INITIALIZE_MS = 60000; // 60s
private int[] ringtoneMode = {AudioManager.RINGER_MODE_NORMAL,
AudioManager.RINGER_MODE_SILENT, AudioManager.RINGER_MODE_VIBRATE};
@@ -37,17 +47,48 @@
super("com.android.mediaframeworktest", MediaFrameworkTest.class);
}
+ private void initializeAudioManagerWithLooper() {
+ new Thread() {
+ @Override
+ public void run() {
+ Looper.prepare();
+ mAudioManagerLooper = Looper.myLooper();
+ mAudioManager = (AudioManager)getActivity().getSystemService(Context.AUDIO_SERVICE);
+ synchronized (mLooperLock) {
+ mLooperLock.notify();
+ }
+ Looper.loop();
+ }
+ }.start();
+ }
+
@Override
protected void setUp() throws Exception {
super.setUp();
- mAudioManager = (AudioManager) getActivity().getSystemService(Context.AUDIO_SERVICE);
+ synchronized(mLooperLock) {
+ initializeAudioManagerWithLooper();
+ try {
+ mLooperLock.wait(WAIT_FOR_LOOPER_TO_INITIALIZE_MS);
+ } catch (Exception e) {
+ assertTrue("initializeAudioManagerWithLooper() failed to complete in time", false);
+ }
+ }
}
@Override
protected void tearDown() throws Exception {
super.tearDown();
+ synchronized(mLooperLock) {
+ if (mAudioManagerLooper != null) {
+ mAudioManagerLooper.quit();
+ }
+ }
}
+ //-----------------------------------------------------------------
+ // Ringer Mode
+ //----------------------------------
+
public boolean validateSetRingTone(int i) {
int getRingtone = mAudioManager.getRingerMode();
if (i != getRingtone)
@@ -67,4 +108,136 @@
assertTrue("SetRingtoneMode : " + ringtoneMode[i], result);
}
}
+
+ //-----------------------------------------------------------------
+ // AudioFocus
+ //----------------------------------
+
+ private static AudioFocusListener mAudioFocusListener;
+ private final static int INVALID_FOCUS = -80; // initialized to magic invalid focus change type
+ private final static int WAIT_FOR_AUDIOFOCUS_LOSS_MS = 10;
+
+ private static class AudioFocusListener implements OnAudioFocusChangeListener {
+ public int mLastFocusChange = INVALID_FOCUS;
+ public int mFocusChangeCounter = 0;
+ public AudioFocusListener() {
+ }
+ public void onAudioFocusChange(int focusChange) {
+ mLastFocusChange = focusChange;
+ mFocusChangeCounter++;
+ }
+ }
+
+ /**
+ * Fails the test if expectedFocusLossMode != mAudioFocusListener.mLastFocusChange
+ */
+ private void verifyAudioFocusLoss(int focusGainMode, int expectedFocusLossMode)
+ throws Exception {
+ // request AudioFocus so we can test that mAudioFocusListener loses it when another
+ // request comes in
+ int result = mAudioManager.requestAudioFocus(mAudioFocusListener,
+ AudioManager.STREAM_MUSIC,
+ AudioManager.AUDIOFOCUS_GAIN);
+ assertTrue("requestAudioFocus returned " + result,
+ result == AudioManager.AUDIOFOCUS_REQUEST_GRANTED);
+ // cause mAudioFocusListener to lose AudioFocus
+ result = mAudioManager.requestAudioFocus(null, AudioManager.STREAM_MUSIC,
+ focusGainMode);
+ assertTrue("requestAudioFocus returned " + result,
+ result == AudioManager.AUDIOFOCUS_REQUEST_GRANTED);
+ // the audio focus request is async, so wait a bit to verify it had the expected effect
+ java.lang.Thread.sleep(WAIT_FOR_AUDIOFOCUS_LOSS_MS);
+ // test successful if the expected focus loss was recorded
+ assertEquals("listener lost focus",
+ mAudioFocusListener.mLastFocusChange, expectedFocusLossMode);
+ }
+
+ private void setupAudioFocusListener() {
+ mAudioFocusListener = new AudioFocusListener();
+ mAudioManager.registerAudioFocusListener(mAudioFocusListener);
+ }
+
+ private void cleanupAudioFocusListener() {
+ // clean up
+ mAudioManager.abandonAudioFocus(mAudioFocusListener);
+ mAudioManager.unregisterAudioFocusListener(mAudioFocusListener);
+ }
+
+ //----------------------------------
+
+ //Test case 1: test audio focus listener loses audio focus:
+ // AUDIOFOCUS_GAIN causes AUDIOFOCUS_LOSS
+ @MediumTest
+ public void testAudioFocusLoss() throws Exception {
+ setupAudioFocusListener();
+
+ verifyAudioFocusLoss(AudioManager.AUDIOFOCUS_GAIN, AudioManager.AUDIOFOCUS_LOSS);
+
+ cleanupAudioFocusListener();
+ }
+
+ //Test case 2: test audio focus listener loses audio focus:
+ // AUDIOFOCUS_GAIN_TRANSIENT causes AUDIOFOCUS_LOSS_TRANSIENT
+ @MediumTest
+ public void testAudioFocusLossTransient() throws Exception {
+ setupAudioFocusListener();
+
+ verifyAudioFocusLoss(AudioManager.AUDIOFOCUS_GAIN_TRANSIENT,
+ AudioManager.AUDIOFOCUS_LOSS_TRANSIENT);
+
+ cleanupAudioFocusListener();
+ }
+
+ //Test case 3: test audio focus listener loses audio focus:
+ // AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK causes AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK
+ @MediumTest
+ public void testAudioFocusLossTransientDuck() throws Exception {
+ setupAudioFocusListener();
+
+ verifyAudioFocusLoss(AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK,
+ AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK);
+
+ cleanupAudioFocusListener();
+ }
+
+ //Test case 4: test audio focus registering and use over 3000 iterations
+ @LargeTest
+ public void testAudioFocusStressListenerRequestAbandon() throws Exception {
+ final int ITERATIONS = 3000;
+ // here we only test the life cycle of a focus listener, and make sure we don't crash
+ // when doing it many times without waiting
+ for (int i = 0 ; i < ITERATIONS ; i++) {
+ setupAudioFocusListener();
+ int result = mAudioManager.requestAudioFocus(mAudioFocusListener,
+ AudioManager.STREAM_MUSIC, AudioManager.AUDIOFOCUS_GAIN);
+ assertTrue("audio focus request was not granted",
+ result == AudioManager.AUDIOFOCUS_REQUEST_GRANTED);
+ cleanupAudioFocusListener();
+ }
+ assertTrue("testAudioFocusListenerLifeCycle : tested" + ITERATIONS +" iterations", true);
+ }
+
+ //Test case 5: test audio focus use without listener
+ @LargeTest
+ public void testAudioFocusStressNoListenerRequestAbandon() throws Exception {
+ final int ITERATIONS = 1000;
+ // make sure we have a listener in the stack
+ setupAudioFocusListener();
+ mAudioManager.requestAudioFocus(mAudioFocusListener, AudioManager.STREAM_MUSIC,
+ AudioManager.AUDIOFOCUS_GAIN);
+ // keep making the current owner lose and gain audio focus repeatedly
+ for (int i = 0 ; i < ITERATIONS ; i++) {
+ mAudioManager.requestAudioFocus(null, AudioManager.STREAM_MUSIC,
+ AudioManager.AUDIOFOCUS_GAIN_TRANSIENT);
+ mAudioManager.abandonAudioFocus(null);
+ // the audio focus request is async, so wait a bit to verify it had the expected effect
+ java.lang.Thread.sleep(WAIT_FOR_AUDIOFOCUS_LOSS_MS);
+ }
+ // verify there were 2 audio focus changes per iteration (one loss + one gain)
+ assertTrue("testAudioFocusListenerLifeCycle : observed " +
+ mAudioFocusListener.mFocusChangeCounter + " AudioFocus changes",
+ mAudioFocusListener.mFocusChangeCounter == ITERATIONS * 2);
+ mAudioManager.abandonAudioFocus(mAudioFocusListener);
+ mAudioManager.unregisterAudioFocusListener(mAudioFocusListener);
+ }
}
diff --git a/native/include/android/configuration.h b/native/include/android/configuration.h
index 4d683fb..06cd3da 100644
--- a/native/include/android/configuration.h
+++ b/native/include/android/configuration.h
@@ -42,6 +42,8 @@
ACONFIGURATION_DENSITY_MEDIUM = 160,
ACONFIGURATION_DENSITY_TV = 213,
ACONFIGURATION_DENSITY_HIGH = 240,
+ ACONFIGURATION_DENSITY_XHIGH = 320,
+ ACONFIGURATION_DENSITY_XXHIGH = 480,
ACONFIGURATION_DENSITY_NONE = 0xffff,
ACONFIGURATION_KEYBOARD_ANY = 0x0000,
diff --git a/opengl/include/GLES/glext.h b/opengl/include/GLES/glext.h
index 65ab5e4..54afaab 100644
--- a/opengl/include/GLES/glext.h
+++ b/opengl/include/GLES/glext.h
@@ -1,7 +1,7 @@
#ifndef __glext_h_
#define __glext_h_
-/* $Revision: 10965 $ on $Date:: 2010-04-09 02:11:29 -0700 #$ */
+/* $Revision: 16481 $ on $Date:: 2012-01-04 10:43:56 -0800 #$ */
#ifdef __cplusplus
extern "C" {
@@ -68,6 +68,14 @@
typedef void* GLeglImageOES;
#endif
+/* GL_OES_EGL_image_external */
+#ifndef GL_OES_EGL_image_external
+/* GLeglImageOES defined in GL_OES_EGL_image already. */
+#define GL_TEXTURE_EXTERNAL_OES 0x8D65
+#define GL_TEXTURE_BINDING_EXTERNAL_OES 0x8D67
+#define GL_REQUIRED_TEXTURE_IMAGE_UNITS_OES 0x8D68
+#endif
+
/* GL_OES_element_index_uint */
#ifndef GL_OES_element_index_uint
#define GL_UNSIGNED_INT 0x1405
@@ -211,14 +219,6 @@
#define GL_VERTEX_ARRAY_BINDING_OES 0x85B5
#endif
-/* GL_OES_EGL_image_external */
-#ifndef GL_OES_EGL_image_external
-#define GL_TEXTURE_EXTERNAL_OES 0x8D65
-#define GL_SAMPLER_EXTERNAL_OES 0x8D66
-#define GL_TEXTURE_BINDING_EXTERNAL_OES 0x8D67
-#define GL_REQUIRED_TEXTURE_IMAGE_UNITS_OES 0x8D68
-#endif
-
/*------------------------------------------------------------------------*
* AMD extension tokens
*------------------------------------------------------------------------*/
@@ -243,6 +243,34 @@
/* GL_APPLE_texture_2D_limited_npot */
/* No new tokens introduced by this extension. */
+/* GL_APPLE_framebuffer_multisample */
+#ifndef GL_APPLE_framebuffer_multisample
+#define GL_RENDERBUFFER_SAMPLES_APPLE 0x8CAB
+#define GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_APPLE 0x8D56
+#define GL_MAX_SAMPLES_APPLE 0x8D57
+#define GL_READ_FRAMEBUFFER_APPLE 0x8CA8
+#define GL_DRAW_FRAMEBUFFER_APPLE 0x8CA9
+#define GL_DRAW_FRAMEBUFFER_BINDING_APPLE 0x8CA6
+#define GL_READ_FRAMEBUFFER_BINDING_APPLE 0x8CAA
+#endif
+
+/* GL_APPLE_texture_format_BGRA8888 */
+#ifndef GL_APPLE_texture_format_BGRA8888
+#define GL_BGRA_EXT 0x80E1
+#endif
+
+/* GL_APPLE_texture_max_level */
+#ifndef GL_APPLE_texture_max_level
+#define GL_TEXTURE_MAX_LEVEL_APPLE 0x813D
+#endif
+
+/*------------------------------------------------------------------------*
+ * ARM extension tokens
+ *------------------------------------------------------------------------*/
+
+/* GL_ARM_rgba8 */
+/* No new tokens introduced by this extension. */
+
/*------------------------------------------------------------------------*
* EXT extension tokens
*------------------------------------------------------------------------*/
@@ -260,6 +288,14 @@
#define GL_STENCIL_EXT 0x1802
#endif
+/* GL_EXT_multisampled_render_to_texture */
+#ifndef GL_EXT_multisampled_render_to_texture
+#define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_SAMPLES_EXT 0x8D6C
+#define GL_RENDERBUFFER_SAMPLES_EXT 0x9133
+#define GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_EXT 0x9134
+#define GL_MAX_SAMPLES_EXT 0x9135
+#endif
+
/* GL_EXT_multi_draw_arrays */
/* No new tokens introduced by this extension. */
@@ -270,6 +306,32 @@
#define GL_UNSIGNED_SHORT_1_5_5_5_REV_EXT 0x8366
#endif
+/* GL_EXT_robustness */
+#ifndef GL_EXT_robustness
+/* reuse GL_NO_ERROR */
+#define GL_GUILTY_CONTEXT_RESET_EXT 0x8253
+#define GL_INNOCENT_CONTEXT_RESET_EXT 0x8254
+#define GL_UNKNOWN_CONTEXT_RESET_EXT 0x8255
+#define GL_CONTEXT_ROBUST_ACCESS_EXT 0x90F3
+#define GL_RESET_NOTIFICATION_STRATEGY_EXT 0x8256
+#define GL_LOSE_CONTEXT_ON_RESET_EXT 0x8252
+#define GL_NO_RESET_NOTIFICATION_EXT 0x8261
+#endif
+
+/* GL_EXT_sRGB */
+#ifndef GL_EXT_sRGB
+#define GL_SRGB_EXT 0x8C40
+#define GL_SRGB_ALPHA_EXT 0x8C42
+#define GL_SRGB8_ALPHA8_EXT 0x8C43
+#define GL_FRAMEBUFFER_ATTACHMENT_COLOR_ENCODING_EXT 0x8210
+#endif
+
+/* GL_EXT_texture_compression_dxt1 */
+#ifndef GL_EXT_texture_compression_dxt1
+#define GL_COMPRESSED_RGB_S3TC_DXT1_EXT 0x83F0
+#define GL_COMPRESSED_RGBA_S3TC_DXT1_EXT 0x83F1
+#endif
+
/* GL_EXT_texture_filter_anisotropic */
#ifndef GL_EXT_texture_filter_anisotropic
#define GL_TEXTURE_MAX_ANISOTROPY_EXT 0x84FE
@@ -288,6 +350,27 @@
#define GL_TEXTURE_LOD_BIAS_EXT 0x8501
#endif
+/* GL_EXT_texture_storage */
+#ifndef GL_EXT_texture_storage
+#define GL_TEXTURE_IMMUTABLE_FORMAT_EXT 0x912F
+#define GL_ALPHA8_EXT 0x803C
+#define GL_LUMINANCE8_EXT 0x8040
+#define GL_LUMINANCE8_ALPHA8_EXT 0x8045
+#define GL_RGBA32F_EXT 0x8814
+#define GL_RGB32F_EXT 0x8815
+#define GL_ALPHA32F_EXT 0x8816
+#define GL_LUMINANCE32F_EXT 0x8818
+#define GL_LUMINANCE_ALPHA32F_EXT 0x8819
+/* reuse GL_RGBA16F_EXT */
+#define GL_RGB16F_EXT 0x881B
+#define GL_ALPHA16F_EXT 0x881C
+#define GL_LUMINANCE16F_EXT 0x881E
+#define GL_LUMINANCE_ALPHA16F_EXT 0x881F
+#define GL_RGB10_A2_EXT 0x8059
+#define GL_RGB10_EXT 0x8052
+#define GL_BGRA8_EXT 0x93A1
+#endif
+
/*------------------------------------------------------------------------*
* IMG extension tokens
*------------------------------------------------------------------------*/
@@ -507,6 +590,12 @@
typedef void (GL_APIENTRYP PFNGLEGLIMAGETARGETRENDERBUFFERSTORAGEOESPROC) (GLenum target, GLeglImageOES image);
#endif
+/* GL_OES_EGL_image_external */
+#ifndef GL_OES_EGL_image_external
+#define GL_OES_EGL_image_external 1
+/* glEGLImageTargetTexture2DOES defined in GL_OES_EGL_image already. */
+#endif
+
/* GL_OES_element_index_uint */
#ifndef GL_OES_element_index_uint
#define GL_OES_element_index_uint 1
@@ -785,11 +874,6 @@
typedef GLboolean (GL_APIENTRYP PFNGLISVERTEXARRAYOESPROC) (GLuint array);
#endif
-/* GL_OES_EGL_image_external */
-#ifndef GL_OES_EGL_image_external
-#define GL_OES_EGL_image_external 1
-#endif
-
/*------------------------------------------------------------------------*
* AMD extension functions
*------------------------------------------------------------------------*/
@@ -813,6 +897,36 @@
#define GL_APPLE_texture_2D_limited_npot 1
#endif
+/* GL_APPLE_framebuffer_multisample */
+#ifndef GL_APPLE_framebuffer_multisample
+#define GL_APPLE_framebuffer_multisample 1
+#ifdef GL_GLEXT_PROTOTYPES
+GL_API void GL_APIENTRY glRenderbufferStorageMultisampleAPPLE (GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height);
+GL_API void GL_APIENTRY glResolveMultisampleFramebufferAPPLE (void);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (GL_APIENTRYP PFNGLRENDERBUFFERSTORAGEMULTISAMPLEAPPLEPROC) (GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height);
+typedef void (GL_APIENTRYP PFNGLRESOLVEMULTISAMPLEFRAMEBUFFERAPPLEPROC) (void);
+#endif
+
+/* GL_APPLE_texture_format_BGRA8888 */
+#ifndef GL_APPLE_texture_format_BGRA8888
+#define GL_APPLE_texture_format_BGRA8888 1
+#endif
+
+/* GL_APPLE_texture_max_level */
+#ifndef GL_APPLE_texture_max_level
+#define GL_APPLE_texture_max_level 1
+#endif
+
+/*------------------------------------------------------------------------*
+ * ARM extension functions
+ *------------------------------------------------------------------------*/
+
+/* GL_ARM_rgba8 */
+#ifndef GL_ARM_rgba8
+#define GL_ARM_rgba8 1
+#endif
+
/*------------------------------------------------------------------------*
* EXT extension functions
*------------------------------------------------------------------------*/
@@ -831,6 +945,17 @@
typedef void (GL_APIENTRYP PFNGLDISCARDFRAMEBUFFEREXTPROC) (GLenum target, GLsizei numAttachments, const GLenum *attachments);
#endif
+/* GL_EXT_multisampled_render_to_texture */
+#ifndef GL_EXT_multisampled_render_to_texture
+#define GL_EXT_multisampled_render_to_texture 1
+#ifdef GL_GLEXT_PROTOTYPES
+GL_API void GL_APIENTRY glRenderbufferStorageMultisampleEXT (GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height);
+GL_API void GL_APIENTRY glFramebufferTexture2DMultisampleEXT (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level, GLsizei samples);
+#endif
+typedef void (GL_APIENTRYP PFNGLRENDERBUFFERSTORAGEMULTISAMPLEEXTPROC) (GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height);
+typedef void (GL_APIENTRYP PFNGLFRAMEBUFFERTEXTURE2DMULTISAMPLEEXTPROC) (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level, GLsizei samples);
+#endif
+
/* GL_EXT_multi_draw_arrays */
#ifndef GL_EXT_multi_draw_arrays
#define GL_EXT_multi_draw_arrays 1
@@ -847,6 +972,31 @@
#define GL_EXT_read_format_bgra 1
#endif
+/* GL_EXT_robustness */
+#ifndef GL_EXT_robustness
+#define GL_EXT_robustness 1
+#ifdef GL_GLEXT_PROTOTYPES
+GL_API GLenum GL_APIENTRY glGetGraphicsResetStatusEXT (void);
+GL_API void GL_APIENTRY glReadnPixelsEXT (GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLsizei bufSize, void *data);
+GL_API void GL_APIENTRY glGetnUniformfvEXT (GLuint program, GLint location, GLsizei bufSize, float *params);
+GL_API void GL_APIENTRY glGetnUniformivEXT (GLuint program, GLint location, GLsizei bufSize, GLint *params);
+#endif
+typedef GLenum (GL_APIENTRYP PFNGLGETGRAPHICSRESETSTATUSEXTPROC) (void);
+typedef void (GL_APIENTRYP PFNGLREADNPIXELSEXTPROC) (GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLsizei bufSize, void *data);
+typedef void (GL_APIENTRYP PFNGLGETNUNIFORMFVEXTPROC) (GLuint program, GLint location, GLsizei bufSize, float *params);
+typedef void (GL_APIENTRYP PFNGLGETNUNIFORMIVEXTPROC) (GLuint program, GLint location, GLsizei bufSize, GLint *params);
+#endif
+
+/* GL_EXT_sRGB */
+#ifndef GL_EXT_sRGB
+#define GL_EXT_sRGB 1
+#endif
+
+/* GL_EXT_texture_compression_dxt1 */
+#ifndef GL_EXT_texture_compression_dxt1
+#define GL_EXT_texture_compression_dxt1 1
+#endif
+
/* GL_EXT_texture_filter_anisotropic */
#ifndef GL_EXT_texture_filter_anisotropic
#define GL_EXT_texture_filter_anisotropic 1
@@ -862,6 +1012,25 @@
#define GL_EXT_texture_lod_bias 1
#endif
+/* GL_EXT_texture_storage */
+#ifndef GL_EXT_texture_storage
+#define GL_EXT_texture_storage 1
+#ifdef GL_GLEXT_PROTOTYPES
+GL_API void GL_APIENTRY glTexStorage1DEXT (GLenum target, GLsizei levels, GLenum internalformat, GLsizei width);
+GL_API void GL_APIENTRY glTexStorage2DEXT (GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height);
+GL_API void GL_APIENTRY glTexStorage3DEXT (GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth);
+GL_API void GL_APIENTRY glTextureStorage1DEXT (GLuint texture, GLenum target, GLsizei levels, GLenum internalformat, GLsizei width);
+GL_API void GL_APIENTRY glTextureStorage2DEXT (GLuint texture, GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height);
+GL_API void GL_APIENTRY glTextureStorage3DEXT (GLuint texture, GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth);
+#endif
+typedef void (GL_APIENTRYP PFNGLTEXSTORAGE1DEXTPROC) (GLenum target, GLsizei levels, GLenum internalformat, GLsizei width);
+typedef void (GL_APIENTRYP PFNGLTEXSTORAGE2DEXTPROC) (GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height);
+typedef void (GL_APIENTRYP PFNGLTEXSTORAGE3DEXTPROC) (GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth);
+typedef void (GL_APIENTRYP PFNGLTEXTURESTORAGE1DEXTPROC) (GLuint texture, GLenum target, GLsizei levels, GLenum internalformat, GLsizei width);
+typedef void (GL_APIENTRYP PFNGLTEXTURESTORAGE2DEXTPROC) (GLuint texture, GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height);
+typedef void (GL_APIENTRYP PFNGLTEXTURESTORAGE3DEXTPROC) (GLuint texture, GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth);
+#endif
+
/*------------------------------------------------------------------------*
* IMG extension functions
*------------------------------------------------------------------------*/
diff --git a/opengl/include/GLES2/gl2ext.h b/opengl/include/GLES2/gl2ext.h
index 9db4e252c..8f8d80a1 100644
--- a/opengl/include/GLES2/gl2ext.h
+++ b/opengl/include/GLES2/gl2ext.h
@@ -1,7 +1,7 @@
#ifndef __gl2ext_h_
#define __gl2ext_h_
-/* $Revision: 10969 $ on $Date:: 2010-04-09 02:27:15 -0700 #$ */
+/* $Revision: 16619 $ on $Date:: 2012-01-18 10:00:14 -0800 #$ */
#ifdef __cplusplus
extern "C" {
@@ -57,6 +57,15 @@
typedef void* GLeglImageOES;
#endif
+/* GL_OES_EGL_image_external */
+#ifndef GL_OES_EGL_image_external
+/* GLeglImageOES defined in GL_OES_EGL_image already. */
+#define GL_TEXTURE_EXTERNAL_OES 0x8D65
+#define GL_SAMPLER_EXTERNAL_OES 0x8D66
+#define GL_TEXTURE_BINDING_EXTERNAL_OES 0x8D67
+#define GL_REQUIRED_TEXTURE_IMAGE_UNITS_OES 0x8D68
+#endif
+
/* GL_OES_element_index_uint */
#ifndef GL_OES_element_index_uint
#define GL_UNSIGNED_INT 0x1405
@@ -146,14 +155,6 @@
#define GL_INT_10_10_10_2_OES 0x8DF7
#endif
-/* GL_OES_EGL_image_external */
-#ifndef GL_OES_EGL_image_external
-#define GL_TEXTURE_EXTERNAL_OES 0x8D65
-#define GL_SAMPLER_EXTERNAL_OES 0x8D66
-#define GL_TEXTURE_BINDING_EXTERNAL_OES 0x8D67
-#define GL_REQUIRED_TEXTURE_IMAGE_UNITS_OES 0x8D68
-#endif
-
/*------------------------------------------------------------------------*
* AMD extension tokens
*------------------------------------------------------------------------*/
@@ -188,6 +189,69 @@
#endif
/*------------------------------------------------------------------------*
+ * ANGLE extension tokens
+ *------------------------------------------------------------------------*/
+
+/* GL_ANGLE_framebuffer_blit */
+#ifndef GL_ANGLE_framebuffer_blit
+#define GL_READ_FRAMEBUFFER_ANGLE 0x8CA8
+#define GL_DRAW_FRAMEBUFFER_ANGLE 0x8CA9
+#define GL_DRAW_FRAMEBUFFER_BINDING_ANGLE 0x8CA6
+#define GL_READ_FRAMEBUFFER_BINDING_ANGLE 0x8CAA
+#endif
+
+/* GL_ANGLE_framebuffer_multisample */
+#ifndef GL_ANGLE_framebuffer_multisample
+#define GL_RENDERBUFFER_SAMPLES_ANGLE 0x8CAB
+#define GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_ANGLE 0x8D56
+#define GL_MAX_SAMPLES_ANGLE 0x8D57
+#endif
+
+/*------------------------------------------------------------------------*
+ * APPLE extension tokens
+ *------------------------------------------------------------------------*/
+
+/* GL_APPLE_rgb_422 */
+#ifndef GL_APPLE_rgb_422
+#define GL_RGB_422_APPLE 0x8A1F
+#define GL_UNSIGNED_SHORT_8_8_APPLE 0x85BA
+#define GL_UNSIGNED_SHORT_8_8_REV_APPLE 0x85BB
+#endif
+
+/* GL_APPLE_framebuffer_multisample */
+#ifndef GL_APPLE_framebuffer_multisample
+#define GL_RENDERBUFFER_SAMPLES_APPLE 0x8CAB
+#define GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_APPLE 0x8D56
+#define GL_MAX_SAMPLES_APPLE 0x8D57
+#define GL_READ_FRAMEBUFFER_APPLE 0x8CA8
+#define GL_DRAW_FRAMEBUFFER_APPLE 0x8CA9
+#define GL_DRAW_FRAMEBUFFER_BINDING_APPLE 0x8CA6
+#define GL_READ_FRAMEBUFFER_BINDING_APPLE 0x8CAA
+#endif
+
+/* GL_APPLE_texture_format_BGRA8888 */
+#ifndef GL_APPLE_texture_format_BGRA8888
+#define GL_BGRA_EXT 0x80E1
+#endif
+
+/* GL_APPLE_texture_max_level */
+#ifndef GL_APPLE_texture_max_level
+#define GL_TEXTURE_MAX_LEVEL_APPLE 0x813D
+#endif
+
+/*------------------------------------------------------------------------*
+ * ARM extension tokens
+ *------------------------------------------------------------------------*/
+
+/* GL_ARM_mali_shader_binary */
+#ifndef GL_ARM_mali_shader_binary
+#define GL_MALI_SHADER_BINARY_ARM 0x8F60
+#endif
+
+/* GL_ARM_rgba8 */
+/* No new tokens introduced by this extension. */
+
+/*------------------------------------------------------------------------*
* EXT extension tokens
*------------------------------------------------------------------------*/
@@ -197,6 +261,29 @@
#define GL_MAX_EXT 0x8008
#endif
+/* GL_EXT_color_buffer_half_float */
+#ifndef GL_EXT_color_buffer_half_float
+#define GL_RGBA16F_EXT 0x881A
+#define GL_RGB16F_EXT 0x881B
+#define GL_RG16F_EXT 0x822F
+#define GL_R16F_EXT 0x822D
+#define GL_FRAMEBUFFER_ATTACHMENT_COMPONENT_TYPE_EXT 0x8211
+#define GL_UNSIGNED_NORMALIZED_EXT 0x8C17
+#endif
+
+/* GL_EXT_debug_label */
+#ifndef GL_EXT_debug_label
+#define GL_PROGRAM_PIPELINE_OBJECT_EXT 0x8A4F
+#define GL_PROGRAM_OBJECT_EXT 0x8B40
+#define GL_SHADER_OBJECT_EXT 0x8B48
+#define GL_BUFFER_OBJECT_EXT 0x9151
+#define GL_QUERY_OBJECT_EXT 0x9153
+#define GL_VERTEX_ARRAY_OBJECT_EXT 0x9154
+#endif
+
+/* GL_EXT_debug_marker */
+/* No new tokens introduced by this extension. */
+
/* GL_EXT_discard_framebuffer */
#ifndef GL_EXT_discard_framebuffer
#define GL_COLOR_EXT 0x1800
@@ -204,9 +291,26 @@
#define GL_STENCIL_EXT 0x1802
#endif
+/* GL_EXT_multisampled_render_to_texture */
+#ifndef GL_EXT_multisampled_render_to_texture
+#define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_SAMPLES_EXT 0x8D6C
+#define GL_RENDERBUFFER_SAMPLES_EXT 0x9133
+#define GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_EXT 0x9134
+#define GL_MAX_SAMPLES_EXT 0x9135
+#endif
+
/* GL_EXT_multi_draw_arrays */
/* No new tokens introduced by this extension. */
+/* GL_EXT_occlusion_query_boolean */
+#ifndef GL_EXT_occlusion_query_boolean
+#define GL_ANY_SAMPLES_PASSED_EXT 0x8C2F
+#define GL_ANY_SAMPLES_PASSED_CONSERVATIVE_EXT 0x8D6A
+#define GL_CURRENT_QUERY_EXT 0x8865
+#define GL_QUERY_RESULT_EXT 0x8866
+#define GL_QUERY_RESULT_AVAILABLE_EXT 0x8867
+#endif
+
/* GL_EXT_read_format_bgra */
#ifndef GL_EXT_read_format_bgra
#define GL_BGRA_EXT 0x80E1
@@ -214,6 +318,53 @@
#define GL_UNSIGNED_SHORT_1_5_5_5_REV_EXT 0x8366
#endif
+/* GL_EXT_robustness */
+#ifndef GL_EXT_robustness
+/* reuse GL_NO_ERROR */
+#define GL_GUILTY_CONTEXT_RESET_EXT 0x8253
+#define GL_INNOCENT_CONTEXT_RESET_EXT 0x8254
+#define GL_UNKNOWN_CONTEXT_RESET_EXT 0x8255
+#define GL_CONTEXT_ROBUST_ACCESS_EXT 0x90F3
+#define GL_RESET_NOTIFICATION_STRATEGY_EXT 0x8256
+#define GL_LOSE_CONTEXT_ON_RESET_EXT 0x8252
+#define GL_NO_RESET_NOTIFICATION_EXT 0x8261
+#endif
+
+/* GL_EXT_separate_shader_objects */
+#ifndef GL_EXT_separate_shader_objects
+#define GL_VERTEX_SHADER_BIT_EXT 0x00000001
+#define GL_FRAGMENT_SHADER_BIT_EXT 0x00000002
+#define GL_ALL_SHADER_BITS_EXT 0xFFFFFFFF
+#define GL_PROGRAM_SEPARABLE_EXT 0x8258
+#define GL_ACTIVE_PROGRAM_EXT 0x8259
+#define GL_PROGRAM_PIPELINE_BINDING_EXT 0x825A
+#endif
+
+/* GL_EXT_shader_texture_lod */
+/* No new tokens introduced by this extension. */
+
+/* GL_EXT_shadow_samplers */
+#ifndef GL_EXT_shadow_samplers
+#define GL_TEXTURE_COMPARE_MODE_EXT 0x884C
+#define GL_TEXTURE_COMPARE_FUNC_EXT 0x884D
+#define GL_COMPARE_REF_TO_TEXTURE_EXT 0x884E
+#define GL_SAMPLER_2D_SHADOW_EXT 0x8B62
+#endif
+
+/* GL_EXT_sRGB */
+#ifndef GL_EXT_sRGB
+#define GL_SRGB_EXT 0x8C40
+#define GL_SRGB_ALPHA_EXT 0x8C42
+#define GL_SRGB8_ALPHA8_EXT 0x8C43
+#define GL_FRAMEBUFFER_ATTACHMENT_COLOR_ENCODING_EXT 0x8210
+#endif
+
+/* GL_EXT_texture_compression_dxt1 */
+#ifndef GL_EXT_texture_compression_dxt1
+#define GL_COMPRESSED_RGB_S3TC_DXT1_EXT 0x83F0
+#define GL_COMPRESSED_RGBA_S3TC_DXT1_EXT 0x83F1
+#endif
+
/* GL_EXT_texture_filter_anisotropic */
#ifndef GL_EXT_texture_filter_anisotropic
#define GL_TEXTURE_MAX_ANISOTROPY_EXT 0x84FE
@@ -225,15 +376,54 @@
#define GL_BGRA_EXT 0x80E1
#endif
+/* GL_EXT_texture_rg */
+#ifndef GL_EXT_texture_rg
+#define GL_RED_EXT 0x1903
+#define GL_RG_EXT 0x8227
+#define GL_R8_EXT 0x8229
+#define GL_RG8_EXT 0x822B
+#endif
+
+/* GL_EXT_texture_storage */
+#ifndef GL_EXT_texture_storage
+#define GL_TEXTURE_IMMUTABLE_FORMAT_EXT 0x912F
+#define GL_ALPHA8_EXT 0x803C
+#define GL_LUMINANCE8_EXT 0x8040
+#define GL_LUMINANCE8_ALPHA8_EXT 0x8045
+#define GL_RGBA32F_EXT 0x8814
+#define GL_RGB32F_EXT 0x8815
+#define GL_ALPHA32F_EXT 0x8816
+#define GL_LUMINANCE32F_EXT 0x8818
+#define GL_LUMINANCE_ALPHA32F_EXT 0x8819
+/* reuse GL_RGBA16F_EXT */
+#define GL_RGB16F_EXT 0x881B
+#define GL_ALPHA16F_EXT 0x881C
+#define GL_LUMINANCE16F_EXT 0x881E
+#define GL_LUMINANCE_ALPHA16F_EXT 0x881F
+#define GL_RGB10_A2_EXT 0x8059
+#define GL_RGB10_EXT 0x8052
+#define GL_BGRA8_EXT 0x93A1
+#endif
+
/* GL_EXT_texture_type_2_10_10_10_REV */
#ifndef GL_EXT_texture_type_2_10_10_10_REV
#define GL_UNSIGNED_INT_2_10_10_10_REV_EXT 0x8368
#endif
-/* GL_EXT_texture_compression_dxt1 */
-#ifndef GL_EXT_texture_compression_dxt1
-#define GL_COMPRESSED_RGB_S3TC_DXT1_EXT 0x83F0
-#define GL_COMPRESSED_RGBA_S3TC_DXT1_EXT 0x83F1
+/* GL_EXT_unpack_subimage */
+#ifndef GL_EXT_unpack_subimage
+#define GL_UNPACK_ROW_LENGTH 0x0CF2
+#define GL_UNPACK_SKIP_ROWS 0x0CF3
+#define GL_UNPACK_SKIP_PIXELS 0x0CF4
+#endif
+
+/*------------------------------------------------------------------------*
+ * DMP extension tokens
+ *------------------------------------------------------------------------*/
+
+/* GL_DMP_shader_binary */
+#ifndef GL_DMP_shader_binary
+#define GL_SHADER_BINARY_DMP 0x9250
#endif
/*------------------------------------------------------------------------*
@@ -276,13 +466,6 @@
* NV extension tokens
*------------------------------------------------------------------------*/
-/* GL_NV_fence */
-#ifndef GL_NV_fence
-#define GL_ALL_COMPLETED_NV 0x84F2
-#define GL_FENCE_STATUS_NV 0x84F3
-#define GL_FENCE_CONDITION_NV 0x84F4
-#endif
-
/* GL_NV_coverage_sample */
#ifndef GL_NV_coverage_sample
#define GL_COVERAGE_COMPONENT_NV 0x8ED0
@@ -301,10 +484,90 @@
#define GL_DEPTH_COMPONENT16_NONLINEAR_NV 0x8E2C
#endif
+/* GL_NV_draw_buffers */
+#ifndef GL_NV_draw_buffers
+#define GL_MAX_DRAW_BUFFERS_NV 0x8824
+#define GL_DRAW_BUFFER0_NV 0x8825
+#define GL_DRAW_BUFFER1_NV 0x8826
+#define GL_DRAW_BUFFER2_NV 0x8827
+#define GL_DRAW_BUFFER3_NV 0x8828
+#define GL_DRAW_BUFFER4_NV 0x8829
+#define GL_DRAW_BUFFER5_NV 0x882A
+#define GL_DRAW_BUFFER6_NV 0x882B
+#define GL_DRAW_BUFFER7_NV 0x882C
+#define GL_DRAW_BUFFER8_NV 0x882D
+#define GL_DRAW_BUFFER9_NV 0x882E
+#define GL_DRAW_BUFFER10_NV 0x882F
+#define GL_DRAW_BUFFER11_NV 0x8830
+#define GL_DRAW_BUFFER12_NV 0x8831
+#define GL_DRAW_BUFFER13_NV 0x8832
+#define GL_DRAW_BUFFER14_NV 0x8833
+#define GL_DRAW_BUFFER15_NV 0x8834
+#define GL_COLOR_ATTACHMENT0_NV 0x8CE0
+#define GL_COLOR_ATTACHMENT1_NV 0x8CE1
+#define GL_COLOR_ATTACHMENT2_NV 0x8CE2
+#define GL_COLOR_ATTACHMENT3_NV 0x8CE3
+#define GL_COLOR_ATTACHMENT4_NV 0x8CE4
+#define GL_COLOR_ATTACHMENT5_NV 0x8CE5
+#define GL_COLOR_ATTACHMENT6_NV 0x8CE6
+#define GL_COLOR_ATTACHMENT7_NV 0x8CE7
+#define GL_COLOR_ATTACHMENT8_NV 0x8CE8
+#define GL_COLOR_ATTACHMENT9_NV 0x8CE9
+#define GL_COLOR_ATTACHMENT10_NV 0x8CEA
+#define GL_COLOR_ATTACHMENT11_NV 0x8CEB
+#define GL_COLOR_ATTACHMENT12_NV 0x8CEC
+#define GL_COLOR_ATTACHMENT13_NV 0x8CED
+#define GL_COLOR_ATTACHMENT14_NV 0x8CEE
+#define GL_COLOR_ATTACHMENT15_NV 0x8CEF
+#endif
+
+/* GL_NV_fbo_color_attachments */
+#ifndef GL_NV_fbo_color_attachments
+#define GL_MAX_COLOR_ATTACHMENTS_NV 0x8CDF
+/* GL_COLOR_ATTACHMENT{0-15}_NV defined in GL_NV_draw_buffers already. */
+#endif
+
+/* GL_NV_fence */
+#ifndef GL_NV_fence
+#define GL_ALL_COMPLETED_NV 0x84F2
+#define GL_FENCE_STATUS_NV 0x84F3
+#define GL_FENCE_CONDITION_NV 0x84F4
+#endif
+
+/* GL_NV_read_buffer */
+#ifndef GL_NV_read_buffer
+#define GL_READ_BUFFER_NV 0x0C02
+#endif
+
+/* GL_NV_read_buffer_front */
+/* No new tokens introduced by this extension. */
+
+/* GL_NV_read_depth */
+/* No new tokens introduced by this extension. */
+
+/* GL_NV_read_depth_stencil */
+/* No new tokens introduced by this extension. */
+
+/* GL_NV_read_stencil */
+/* No new tokens introduced by this extension. */
+
+/* GL_NV_texture_compression_s3tc_update */
+/* No new tokens introduced by this extension. */
+
+/* GL_NV_texture_npot_2D_mipmap */
+/* No new tokens introduced by this extension. */
+
/*------------------------------------------------------------------------*
* QCOM extension tokens
*------------------------------------------------------------------------*/
+/* GL_QCOM_alpha_test */
+#ifndef GL_QCOM_alpha_test
+#define GL_ALPHA_TEST_QCOM 0x0BC0
+#define GL_ALPHA_TEST_FUNC_QCOM 0x0BC1
+#define GL_ALPHA_TEST_REF_QCOM 0x0BC2
+#endif
+
/* GL_QCOM_driver_control */
/* No new tokens introduced by this extension. */
@@ -373,6 +636,15 @@
#endif
/*------------------------------------------------------------------------*
+ * VIV extension tokens
+ *------------------------------------------------------------------------*/
+
+/* GL_VIV_shader_binary */
+#ifndef GL_VIV_shader_binary
+#define GL_SHADER_BINARY_VIV 0x8FC4
+#endif
+
+/*------------------------------------------------------------------------*
* End of extension tokens, start of corresponding extension functions
*------------------------------------------------------------------------*/
@@ -416,6 +688,12 @@
typedef void (GL_APIENTRYP PFNGLEGLIMAGETARGETRENDERBUFFERSTORAGEOESPROC) (GLenum target, GLeglImageOES image);
#endif
+/* GL_OES_EGL_image_external */
+#ifndef GL_OES_EGL_image_external
+#define GL_OES_EGL_image_external 1
+/* glEGLImageTargetTexture2DOES defined in GL_OES_EGL_image already. */
+#endif
+
/* GL_OES_element_index_uint */
#ifndef GL_OES_element_index_uint
#define GL_OES_element_index_uint 1
@@ -549,11 +827,6 @@
#define GL_OES_vertex_type_10_10_10_2 1
#endif
-/* GL_OES_EGL_image_external */
-#ifndef GL_OES_EGL_image_external
-#define GL_OES_EGL_image_external 1
-#endif
-
/*------------------------------------------------------------------------*
* AMD extension functions
*------------------------------------------------------------------------*/
@@ -603,6 +876,72 @@
#endif
/*------------------------------------------------------------------------*
+ * ANGLE extension functions
+ *------------------------------------------------------------------------*/
+
+/* GL_ANGLE_framebuffer_blit */
+#ifndef GL_ANGLE_framebuffer_blit
+#define GL_ANGLE_framebuffer_blit 1
+#ifdef GL_GLEXT_PROTOTYPES
+GL_APICALL void GL_APIENTRY glBlitFramebufferANGLE (GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter);
+#endif
+typedef void (GL_APIENTRYP PFNGLBLITFRAMEBUFFERANGLEPROC) (GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter);
+#endif
+
+/* GL_ANGLE_framebuffer_multisample */
+#ifndef GL_ANGLE_framebuffer_multisample
+#define GL_ANGLE_framebuffer_multisample 1
+#ifdef GL_GLEXT_PROTOTYPES
+GL_APICALL void GL_APIENTRY glRenderbufferStorageMultisampleANGLE (GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height);
+#endif
+typedef void (GL_APIENTRYP PFNGLRENDERBUFFERSTORAGEMULTISAMPLEANGLEPROC) (GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height);
+#endif
+
+/*------------------------------------------------------------------------*
+ * APPLE extension functions
+ *------------------------------------------------------------------------*/
+
+/* GL_APPLE_rgb_422 */
+#ifndef GL_APPLE_rgb_422
+#define GL_APPLE_rgb_422 1
+#endif
+
+/* GL_APPLE_framebuffer_multisample */
+#ifndef GL_APPLE_framebuffer_multisample
+#define GL_APPLE_framebuffer_multisample 1
+#ifdef GL_GLEXT_PROTOTYPES
+GL_APICALL void GL_APIENTRY glRenderbufferStorageMultisampleAPPLE (GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height);
+GL_APICALL void GL_APIENTRY glResolveMultisampleFramebufferAPPLE (void);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (GL_APIENTRYP PFNGLRENDERBUFFERSTORAGEMULTISAMPLEAPPLEPROC) (GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height);
+typedef void (GL_APIENTRYP PFNGLRESOLVEMULTISAMPLEFRAMEBUFFERAPPLEPROC) (void);
+#endif
+
+/* GL_APPLE_texture_format_BGRA8888 */
+#ifndef GL_APPLE_texture_format_BGRA8888
+#define GL_APPLE_texture_format_BGRA8888 1
+#endif
+
+/* GL_APPLE_texture_max_level */
+#ifndef GL_APPLE_texture_max_level
+#define GL_APPLE_texture_max_level 1
+#endif
+
+/*------------------------------------------------------------------------*
+ * ARM extension functions
+ *------------------------------------------------------------------------*/
+
+/* GL_ARM_mali_shader_binary */
+#ifndef GL_ARM_mali_shader_binary
+#define GL_ARM_mali_shader_binary 1
+#endif
+
+/* GL_ARM_rgba8 */
+#ifndef GL_ARM_rgba8
+#define GL_ARM_rgba8 1
+#endif
+
+/*------------------------------------------------------------------------*
* EXT extension functions
*------------------------------------------------------------------------*/
@@ -611,6 +950,35 @@
#define GL_EXT_blend_minmax 1
#endif
+/* GL_EXT_color_buffer_half_float */
+#ifndef GL_EXT_color_buffer_half_float
+#define GL_EXT_color_buffer_half_float 1
+#endif
+
+/* GL_EXT_debug_label */
+#ifndef GL_EXT_debug_label
+#define GL_EXT_debug_label 1
+#ifdef GL_GLEXT_PROTOTYPES
+GL_APICALL void GL_APIENTRY glLabelObjectEXT (GLenum type, GLuint object, GLsizei length, const GLchar *label);
+GL_APICALL void GL_APIENTRY glGetObjectLabelEXT (GLenum type, GLuint object, GLsizei bufSize, GLsizei *length, GLchar *label);
+#endif
+typedef void (GL_APIENTRYP PFNGLLABELOBJECTEXTPROC) (GLenum type, GLuint object, GLsizei length, const GLchar *label);
+typedef void (GL_APIENTRYP PFNGLGETOBJECTLABELEXTPROC) (GLenum type, GLuint object, GLsizei bufSize, GLsizei *length, GLchar *label);
+#endif
+
+/* GL_EXT_debug_marker */
+#ifndef GL_EXT_debug_marker
+#define GL_EXT_debug_marker 1
+#ifdef GL_GLEXT_PROTOTYPES
+GL_APICALL void GL_APIENTRY glInsertEventMarkerEXT (GLsizei length, const GLchar *marker);
+GL_APICALL void GL_APIENTRY glPushGroupMarkerEXT (GLsizei length, const GLchar *marker);
+GL_APICALL void GL_APIENTRY glPopGroupMarkerEXT (void);
+#endif
+typedef void (GL_APIENTRYP PFNGLINSERTEVENTMARKEREXTPROC) (GLsizei length, const GLchar *marker);
+typedef void (GL_APIENTRYP PFNGLPUSHGROUPMARKEREXTPROC) (GLsizei length, const GLchar *marker);
+typedef void (GL_APIENTRYP PFNGLPOPGROUPMARKEREXTPROC) (void);
+#endif
+
/* GL_EXT_discard_framebuffer */
#ifndef GL_EXT_discard_framebuffer
#define GL_EXT_discard_framebuffer 1
@@ -620,6 +988,17 @@
typedef void (GL_APIENTRYP PFNGLDISCARDFRAMEBUFFEREXTPROC) (GLenum target, GLsizei numAttachments, const GLenum *attachments);
#endif
+/* GL_EXT_multisampled_render_to_texture */
+#ifndef GL_EXT_multisampled_render_to_texture
+#define GL_EXT_multisampled_render_to_texture 1
+#ifdef GL_GLEXT_PROTOTYPES
+GL_APICALL void GL_APIENTRY glRenderbufferStorageMultisampleEXT (GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height);
+GL_APICALL void GL_APIENTRY glFramebufferTexture2DMultisampleEXT (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level, GLsizei samples);
+#endif
+typedef void (GL_APIENTRYP PFNGLRENDERBUFFERSTORAGEMULTISAMPLEEXTPROC) (GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height);
+typedef void (GL_APIENTRYP PFNGLFRAMEBUFFERTEXTURE2DMULTISAMPLEEXTPROC) (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level, GLsizei samples);
+#endif
+
#ifndef GL_EXT_multi_draw_arrays
#define GL_EXT_multi_draw_arrays 1
#ifdef GL_GLEXT_PROTOTYPES
@@ -630,11 +1009,134 @@
typedef void (GL_APIENTRYP PFNGLMULTIDRAWELEMENTSEXTPROC) (GLenum mode, const GLsizei *count, GLenum type, const GLvoid* *indices, GLsizei primcount);
#endif
+/* GL_EXT_occlusion_query_boolean */
+#ifndef GL_EXT_occlusion_query_boolean
+#define GL_EXT_occlusion_query_boolean 1
+#ifdef GL_GLEXT_PROTOTYPES
+GL_APICALL void GL_APIENTRY glGenQueriesEXT (GLsizei n, GLuint *ids);
+GL_APICALL void GL_APIENTRY glDeleteQueriesEXT (GLsizei n, const GLuint *ids);
+GL_APICALL GLboolean GL_APIENTRY glIsQueryEXT (GLuint id);
+GL_APICALL void GL_APIENTRY glBeginQueryEXT (GLenum target, GLuint id);
+GL_APICALL void GL_APIENTRY glEndQueryEXT (GLenum target);
+GL_APICALL void GL_APIENTRY glGetQueryivEXT (GLenum target, GLenum pname, GLint *params);
+GL_APICALL void GL_APIENTRY glGetQueryObjectuivEXT (GLuint id, GLenum pname, GLuint *params);
+#endif
+typedef void (GL_APIENTRYP PFNGLGENQUERIESEXTPROC) (GLsizei n, GLuint *ids);
+typedef void (GL_APIENTRYP PFNGLDELETEQUERIESEXTPROC) (GLsizei n, const GLuint *ids);
+typedef GLboolean (GL_APIENTRYP PFNGLISQUERYEXTPROC) (GLuint id);
+typedef void (GL_APIENTRYP PFNGLBEGINQUERYEXTPROC) (GLenum target, GLuint id);
+typedef void (GL_APIENTRYP PFNGLENDQUERYEXTPROC) (GLenum target);
+typedef void (GL_APIENTRYP PFNGLGETQUERYIVEXTPROC) (GLenum target, GLenum pname, GLint *params);
+typedef void (GL_APIENTRYP PFNGLGETQUERYOBJECTUIVEXTPROC) (GLuint id, GLenum pname, GLuint *params);
+#endif
+
/* GL_EXT_read_format_bgra */
#ifndef GL_EXT_read_format_bgra
#define GL_EXT_read_format_bgra 1
#endif
+/* GL_EXT_robustness */
+#ifndef GL_EXT_robustness
+#define GL_EXT_robustness 1
+#ifdef GL_GLEXT_PROTOTYPES
+GL_APICALL GLenum GL_APIENTRY glGetGraphicsResetStatusEXT (void);
+GL_APICALL void GL_APIENTRY glReadnPixelsEXT (GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLsizei bufSize, void *data);
+GL_APICALL void GL_APIENTRY glGetnUniformfvEXT (GLuint program, GLint location, GLsizei bufSize, float *params);
+GL_APICALL void GL_APIENTRY glGetnUniformivEXT (GLuint program, GLint location, GLsizei bufSize, GLint *params);
+#endif
+typedef GLenum (GL_APIENTRYP PFNGLGETGRAPHICSRESETSTATUSEXTPROC) (void);
+typedef void (GL_APIENTRYP PFNGLREADNPIXELSEXTPROC) (GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLsizei bufSize, void *data);
+typedef void (GL_APIENTRYP PFNGLGETNUNIFORMFVEXTPROC) (GLuint program, GLint location, GLsizei bufSize, float *params);
+typedef void (GL_APIENTRYP PFNGLGETNUNIFORMIVEXTPROC) (GLuint program, GLint location, GLsizei bufSize, GLint *params);
+#endif
+
+/* GL_EXT_separate_shader_objects */
+#ifndef GL_EXT_separate_shader_objects
+#define GL_EXT_separate_shader_objects 1
+#ifdef GL_GLEXT_PROTOTYPES
+GL_APICALL void GL_APIENTRY glUseProgramStagesEXT (GLuint pipeline, GLbitfield stages, GLuint program);
+GL_APICALL void GL_APIENTRY glActiveShaderProgramEXT (GLuint pipeline, GLuint program);
+GL_APICALL GLuint GL_APIENTRY glCreateShaderProgramvEXT (GLenum type, GLsizei count, const GLchar **strings);
+GL_APICALL void GL_APIENTRY glBindProgramPipelineEXT (GLuint pipeline);
+GL_APICALL void GL_APIENTRY glDeleteProgramPipelinesEXT (GLsizei n, const GLuint *pipelines);
+GL_APICALL void GL_APIENTRY glGenProgramPipelinesEXT (GLsizei n, GLuint *pipelines);
+GL_APICALL GLboolean GL_APIENTRY glIsProgramPipelineEXT (GLuint pipeline);
+GL_APICALL void GL_APIENTRY glProgramParameteriEXT (GLuint program, GLenum pname, GLint value);
+GL_APICALL void GL_APIENTRY glGetProgramPipelineivEXT (GLuint pipeline, GLenum pname, GLint *params);
+GL_APICALL void GL_APIENTRY glProgramUniform1iEXT (GLuint program, GLint location, GLint x);
+GL_APICALL void GL_APIENTRY glProgramUniform2iEXT (GLuint program, GLint location, GLint x, GLint y);
+GL_APICALL void GL_APIENTRY glProgramUniform3iEXT (GLuint program, GLint location, GLint x, GLint y, GLint z);
+GL_APICALL void GL_APIENTRY glProgramUniform4iEXT (GLuint program, GLint location, GLint x, GLint y, GLint z, GLint w);
+GL_APICALL void GL_APIENTRY glProgramUniform1fEXT (GLuint program, GLint location, GLfloat x);
+GL_APICALL void GL_APIENTRY glProgramUniform2fEXT (GLuint program, GLint location, GLfloat x, GLfloat y);
+GL_APICALL void GL_APIENTRY glProgramUniform3fEXT (GLuint program, GLint location, GLfloat x, GLfloat y, GLfloat z);
+GL_APICALL void GL_APIENTRY glProgramUniform4fEXT (GLuint program, GLint location, GLfloat x, GLfloat y, GLfloat z, GLfloat w);
+GL_APICALL void GL_APIENTRY glProgramUniform1ivEXT (GLuint program, GLint location, GLsizei count, const GLint *value);
+GL_APICALL void GL_APIENTRY glProgramUniform2ivEXT (GLuint program, GLint location, GLsizei count, const GLint *value);
+GL_APICALL void GL_APIENTRY glProgramUniform3ivEXT (GLuint program, GLint location, GLsizei count, const GLint *value);
+GL_APICALL void GL_APIENTRY glProgramUniform4ivEXT (GLuint program, GLint location, GLsizei count, const GLint *value);
+GL_APICALL void GL_APIENTRY glProgramUniform1fvEXT (GLuint program, GLint location, GLsizei count, const GLfloat *value);
+GL_APICALL void GL_APIENTRY glProgramUniform2fvEXT (GLuint program, GLint location, GLsizei count, const GLfloat *value);
+GL_APICALL void GL_APIENTRY glProgramUniform3fvEXT (GLuint program, GLint location, GLsizei count, const GLfloat *value);
+GL_APICALL void GL_APIENTRY glProgramUniform4fvEXT (GLuint program, GLint location, GLsizei count, const GLfloat *value);
+GL_APICALL void GL_APIENTRY glProgramUniformMatrix2fvEXT (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
+GL_APICALL void GL_APIENTRY glProgramUniformMatrix3fvEXT (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
+GL_APICALL void GL_APIENTRY glProgramUniformMatrix4fvEXT (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
+GL_APICALL void GL_APIENTRY glValidateProgramPipelineEXT (GLuint pipeline);
+GL_APICALL void GL_APIENTRY glGetProgramPipelineInfoLogEXT (GLuint pipeline, GLsizei bufSize, GLsizei *length, GLchar *infoLog);
+#endif
+typedef void (GL_APIENTRYP PFNGLUSEPROGRAMSTAGESEXTPROC) (GLuint pipeline, GLbitfield stages, GLuint program);
+typedef void (GL_APIENTRYP PFNGLACTIVESHADERPROGRAMEXTPROC) (GLuint pipeline, GLuint program);
+typedef GLuint (GL_APIENTRYP PFNGLCREATESHADERPROGRAMVEXTPROC) (GLenum type, GLsizei count, const GLchar **strings);
+typedef void (GL_APIENTRYP PFNGLBINDPROGRAMPIPELINEEXTPROC) (GLuint pipeline);
+typedef void (GL_APIENTRYP PFNGLDELETEPROGRAMPIPELINESEXTPROC) (GLsizei n, const GLuint *pipelines);
+typedef void (GL_APIENTRYP PFNGLGENPROGRAMPIPELINESEXTPROC) (GLsizei n, GLuint *pipelines);
+typedef GLboolean (GL_APIENTRYP PFNGLISPROGRAMPIPELINEEXTPROC) (GLuint pipeline);
+typedef void (GL_APIENTRYP PFNGLPROGRAMPARAMETERIEXTPROC) (GLuint program, GLenum pname, GLint value);
+typedef void (GL_APIENTRYP PFNGLGETPROGRAMPIPELINEIVEXTPROC) (GLuint pipeline, GLenum pname, GLint *params);
+typedef void (GL_APIENTRYP PFNGLPROGRAMUNIFORM1IEXTPROC) (GLuint program, GLint location, GLint x);
+typedef void (GL_APIENTRYP PFNGLPROGRAMUNIFORM2IEXTPROC) (GLuint program, GLint location, GLint x, GLint y);
+typedef void (GL_APIENTRYP PFNGLPROGRAMUNIFORM3IEXTPROC) (GLuint program, GLint location, GLint x, GLint y, GLint z);
+typedef void (GL_APIENTRYP PFNGLPROGRAMUNIFORM4IEXTPROC) (GLuint program, GLint location, GLint x, GLint y, GLint z, GLint w);
+typedef void (GL_APIENTRYP PFNGLPROGRAMUNIFORM1FEXTPROC) (GLuint program, GLint location, GLfloat x);
+typedef void (GL_APIENTRYP PFNGLPROGRAMUNIFORM2FEXTPROC) (GLuint program, GLint location, GLfloat x, GLfloat y);
+typedef void (GL_APIENTRYP PFNGLPROGRAMUNIFORM3FEXTPROC) (GLuint program, GLint location, GLfloat x, GLfloat y, GLfloat z);
+typedef void (GL_APIENTRYP PFNGLPROGRAMUNIFORM4FEXTPROC) (GLuint program, GLint location, GLfloat x, GLfloat y, GLfloat z, GLfloat w);
+typedef void (GL_APIENTRYP PFNGLPROGRAMUNIFORM1IVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLint *value);
+typedef void (GL_APIENTRYP PFNGLPROGRAMUNIFORM2IVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLint *value);
+typedef void (GL_APIENTRYP PFNGLPROGRAMUNIFORM3IVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLint *value);
+typedef void (GL_APIENTRYP PFNGLPROGRAMUNIFORM4IVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLint *value);
+typedef void (GL_APIENTRYP PFNGLPROGRAMUNIFORM1FVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLfloat *value);
+typedef void (GL_APIENTRYP PFNGLPROGRAMUNIFORM2FVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLfloat *value);
+typedef void (GL_APIENTRYP PFNGLPROGRAMUNIFORM3FVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLfloat *value);
+typedef void (GL_APIENTRYP PFNGLPROGRAMUNIFORM4FVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLfloat *value);
+typedef void (GL_APIENTRYP PFNGLPROGRAMUNIFORMMATRIX2FVEXTPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
+typedef void (GL_APIENTRYP PFNGLPROGRAMUNIFORMMATRIX3FVEXTPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
+typedef void (GL_APIENTRYP PFNGLPROGRAMUNIFORMMATRIX4FVEXTPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
+typedef void (GL_APIENTRYP PFNGLVALIDATEPROGRAMPIPELINEEXTPROC) (GLuint pipeline);
+typedef void (GL_APIENTRYP PFNGLGETPROGRAMPIPELINEINFOLOGEXTPROC) (GLuint pipeline, GLsizei bufSize, GLsizei *length, GLchar *infoLog);
+#endif
+
+/* GL_EXT_shader_texture_lod */
+#ifndef GL_EXT_shader_texture_lod
+#define GL_EXT_shader_texture_lod 1
+#endif
+
+/* GL_EXT_shadow_samplers */
+#ifndef GL_EXT_shadow_samplers
+#define GL_EXT_shadow_samplers 1
+#endif
+
+/* GL_EXT_sRGB */
+#ifndef GL_EXT_sRGB
+#define GL_EXT_sRGB 1
+#endif
+
+/* GL_EXT_texture_compression_dxt1 */
+#ifndef GL_EXT_texture_compression_dxt1
+#define GL_EXT_texture_compression_dxt1 1
+#endif
+
/* GL_EXT_texture_filter_anisotropic */
#ifndef GL_EXT_texture_filter_anisotropic
#define GL_EXT_texture_filter_anisotropic 1
@@ -645,14 +1147,47 @@
#define GL_EXT_texture_format_BGRA8888 1
#endif
+/* GL_EXT_texture_rg */
+#ifndef GL_EXT_texture_rg
+#define GL_EXT_texture_rg 1
+#endif
+
+/* GL_EXT_texture_storage */
+#ifndef GL_EXT_texture_storage
+#define GL_EXT_texture_storage 1
+#ifdef GL_GLEXT_PROTOTYPES
+GL_APICALL void GL_APIENTRY glTexStorage1DEXT (GLenum target, GLsizei levels, GLenum internalformat, GLsizei width);
+GL_APICALL void GL_APIENTRY glTexStorage2DEXT (GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height);
+GL_APICALL void GL_APIENTRY glTexStorage3DEXT (GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth);
+GL_APICALL void GL_APIENTRY glTextureStorage1DEXT (GLuint texture, GLenum target, GLsizei levels, GLenum internalformat, GLsizei width);
+GL_APICALL void GL_APIENTRY glTextureStorage2DEXT (GLuint texture, GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height);
+GL_APICALL void GL_APIENTRY glTextureStorage3DEXT (GLuint texture, GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth);
+#endif
+typedef void (GL_APIENTRYP PFNGLTEXSTORAGE1DEXTPROC) (GLenum target, GLsizei levels, GLenum internalformat, GLsizei width);
+typedef void (GL_APIENTRYP PFNGLTEXSTORAGE2DEXTPROC) (GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height);
+typedef void (GL_APIENTRYP PFNGLTEXSTORAGE3DEXTPROC) (GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth);
+typedef void (GL_APIENTRYP PFNGLTEXTURESTORAGE1DEXTPROC) (GLuint texture, GLenum target, GLsizei levels, GLenum internalformat, GLsizei width);
+typedef void (GL_APIENTRYP PFNGLTEXTURESTORAGE2DEXTPROC) (GLuint texture, GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height);
+typedef void (GL_APIENTRYP PFNGLTEXTURESTORAGE3DEXTPROC) (GLuint texture, GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth);
+#endif
+
/* GL_EXT_texture_type_2_10_10_10_REV */
#ifndef GL_EXT_texture_type_2_10_10_10_REV
#define GL_EXT_texture_type_2_10_10_10_REV 1
#endif
-/* GL_EXT_texture_compression_dxt1 */
-#ifndef GL_EXT_texture_compression_dxt1
-#define GL_EXT_texture_compression_dxt1 1
+/* GL_EXT_unpack_subimage */
+#ifndef GL_EXT_unpack_subimage
+#define GL_EXT_unpack_subimage 1
+#endif
+
+/*------------------------------------------------------------------------*
+ * DMP extension functions
+ *------------------------------------------------------------------------*/
+
+/* GL_DMP_shader_binary */
+#ifndef GL_DMP_shader_binary
+#define GL_DMP_shader_binary 1
#endif
/*------------------------------------------------------------------------*
@@ -694,6 +1229,36 @@
* NV extension functions
*------------------------------------------------------------------------*/
+/* GL_NV_coverage_sample */
+#ifndef GL_NV_coverage_sample
+#define GL_NV_coverage_sample 1
+#ifdef GL_GLEXT_PROTOTYPES
+GL_APICALL void GL_APIENTRY glCoverageMaskNV (GLboolean mask);
+GL_APICALL void GL_APIENTRY glCoverageOperationNV (GLenum operation);
+#endif
+typedef void (GL_APIENTRYP PFNGLCOVERAGEMASKNVPROC) (GLboolean mask);
+typedef void (GL_APIENTRYP PFNGLCOVERAGEOPERATIONNVPROC) (GLenum operation);
+#endif
+
+/* GL_NV_depth_nonlinear */
+#ifndef GL_NV_depth_nonlinear
+#define GL_NV_depth_nonlinear 1
+#endif
+
+/* GL_NV_draw_buffers */
+#ifndef GL_NV_draw_buffers
+#define GL_NV_draw_buffers 1
+#ifdef GL_GLEXT_PROTOTYPES
+GL_APICALL void GL_APIENTRY glDrawBuffersNV (GLsizei n, const GLenum *bufs);
+#endif
+typedef void (GL_APIENTRYP PFNGLDRAWBUFFERSNVPROC) (GLsizei n, const GLenum *bufs);
+#endif
+
+/* GL_NV_fbo_color_attachments */
+#ifndef GL_NV_fbo_color_attachments
+#define GL_NV_fbo_color_attachments 1
+#endif
+
/* GL_NV_fence */
#ifndef GL_NV_fence
#define GL_NV_fence 1
@@ -715,26 +1280,58 @@
typedef void (GL_APIENTRYP PFNGLSETFENCENVPROC) (GLuint fence, GLenum condition);
#endif
-/* GL_NV_coverage_sample */
-#ifndef GL_NV_coverage_sample
-#define GL_NV_coverage_sample 1
+/* GL_NV_read_buffer */
+#ifndef GL_NV_read_buffer
+#define GL_NV_read_buffer 1
#ifdef GL_GLEXT_PROTOTYPES
-GL_APICALL void GL_APIENTRY glCoverageMaskNV (GLboolean mask);
-GL_APICALL void GL_APIENTRY glCoverageOperationNV (GLenum operation);
+GL_APICALL void GL_APIENTRY glReadBufferNV (GLenum mode);
#endif
-typedef void (GL_APIENTRYP PFNGLCOVERAGEMASKNVPROC) (GLboolean mask);
-typedef void (GL_APIENTRYP PFNGLCOVERAGEOPERATIONNVPROC) (GLenum operation);
+typedef void (GL_APIENTRYP PFNGLREADBUFFERNVPROC) (GLenum mode);
#endif
-/* GL_NV_depth_nonlinear */
-#ifndef GL_NV_depth_nonlinear
-#define GL_NV_depth_nonlinear 1
+/* GL_NV_read_buffer_front */
+#ifndef GL_NV_read_buffer_front
+#define GL_NV_read_buffer_front 1
+#endif
+
+/* GL_NV_read_depth */
+#ifndef GL_NV_read_depth
+#define GL_NV_read_depth 1
+#endif
+
+/* GL_NV_read_depth_stencil */
+#ifndef GL_NV_read_depth_stencil
+#define GL_NV_read_depth_stencil 1
+#endif
+
+/* GL_NV_read_stencil */
+#ifndef GL_NV_read_stencil
+#define GL_NV_read_stencil 1
+#endif
+
+/* GL_NV_texture_compression_s3tc_update */
+#ifndef GL_NV_texture_compression_s3tc_update
+#define GL_NV_texture_compression_s3tc_update 1
+#endif
+
+/* GL_NV_texture_npot_2D_mipmap */
+#ifndef GL_NV_texture_npot_2D_mipmap
+#define GL_NV_texture_npot_2D_mipmap 1
#endif
/*------------------------------------------------------------------------*
* QCOM extension functions
*------------------------------------------------------------------------*/
+/* GL_QCOM_alpha_test */
+#ifndef GL_QCOM_alpha_test
+#define GL_QCOM_alpha_test 1
+#ifdef GL_GLEXT_PROTOTYPES
+GL_APICALL void GL_APIENTRY glAlphaFuncQCOM (GLenum func, GLclampf ref);
+#endif
+typedef void (GL_APIENTRYP PFNGLALPHAFUNCQCOMPROC) (GLenum func, GLclampf ref);
+#endif
+
/* GL_QCOM_driver_control */
#ifndef GL_QCOM_driver_control
#define GL_QCOM_driver_control 1
@@ -809,6 +1406,15 @@
typedef void (GL_APIENTRYP PFNGLENDTILINGQCOMPROC) (GLbitfield preserveMask);
#endif
+/*------------------------------------------------------------------------*
+ * VIV extension tokens
+ *------------------------------------------------------------------------*/
+
+/* GL_VIV_shader_binary */
+#ifndef GL_VIV_shader_binary
+#define GL_VIV_shader_binary 1
+#endif
+
#ifdef __cplusplus
}
#endif
diff --git a/opengl/libs/EGL/Loader.cpp b/opengl/libs/EGL/Loader.cpp
index 2fc6125..06be2ef 100644
--- a/opengl/libs/EGL/Loader.cpp
+++ b/opengl/libs/EGL/Loader.cpp
@@ -253,6 +253,19 @@
if (f == NULL) {
//ALOGD("%s", name);
f = (__eglMustCastToProperFunctionPointerType)gl_unimplemented;
+
+ /*
+ * GL_EXT_debug_label is special, we always report it as
+ * supported, it's handled by GLES_trace. If GLES_trace is not
+ * enabled, then these are no-ops.
+ */
+ if (!strcmp(name, "glInsertEventMarkerEXT")) {
+ f = (__eglMustCastToProperFunctionPointerType)gl_noop;
+ } else if (!strcmp(name, "glPushGroupMarkerEXT")) {
+ f = (__eglMustCastToProperFunctionPointerType)gl_noop;
+ } else if (!strcmp(name, "glPopGroupMarkerEXT")) {
+ f = (__eglMustCastToProperFunctionPointerType)gl_noop;
+ }
}
*curr++ = f;
api++;
diff --git a/opengl/libs/EGL/egl.cpp b/opengl/libs/EGL/egl.cpp
index e053589..83933e5 100644
--- a/opengl/libs/EGL/egl.cpp
+++ b/opengl/libs/EGL/egl.cpp
@@ -233,6 +233,26 @@
// ----------------------------------------------------------------------------
+const GLubyte * egl_get_string_for_current_context(GLenum name) {
+ // NOTE: returning NULL here will fall-back to the default
+ // implementation.
+
+ EGLContext context = egl_tls_t::getContext();
+ if (context == EGL_NO_CONTEXT)
+ return NULL;
+
+ egl_context_t const * const c = get_context(context);
+ if (c == NULL) // this should never happen, by construction
+ return NULL;
+
+ if (name != GL_EXTENSIONS)
+ return NULL;
+
+ return (const GLubyte *)c->gl_extensions.string();
+}
+
+// ----------------------------------------------------------------------------
+
// this mutex protects:
// d->disp[]
// egl_init_drivers_locked()
@@ -290,6 +310,9 @@
ALOGE("called unimplemented OpenGL ES API");
}
+void gl_noop() {
+}
+
// ----------------------------------------------------------------------------
#if USE_FAST_TLS_KEY
diff --git a/opengl/libs/EGL/eglApi.cpp b/opengl/libs/EGL/eglApi.cpp
index 664f258..73aab26 100644
--- a/opengl/libs/EGL/eglApi.cpp
+++ b/opengl/libs/EGL/eglApi.cpp
@@ -477,6 +477,26 @@
return result;
}
+void EGLAPI eglBeginFrame(EGLDisplay dpy, EGLSurface surface) {
+ clearError();
+
+ egl_display_t const * const dp = validate_display(dpy);
+ if (!dp) {
+ return;
+ }
+
+ SurfaceRef _s(dp, surface);
+ if (!_s.get()) {
+ setError(EGL_BAD_SURFACE, EGL_FALSE);
+ return;
+ }
+
+ int64_t timestamp = systemTime(SYSTEM_TIME_MONOTONIC);
+
+ egl_surface_t const * const s = get_surface(surface);
+ native_window_set_buffers_timestamp(s->win.get(), timestamp);
+}
+
// ----------------------------------------------------------------------------
// Contexts
// ----------------------------------------------------------------------------
@@ -546,27 +566,6 @@
return result;
}
-static void loseCurrent(egl_context_t * cur_c)
-{
- if (cur_c) {
- egl_surface_t * cur_r = get_surface(cur_c->read);
- egl_surface_t * cur_d = get_surface(cur_c->draw);
-
- // by construction, these are either 0 or valid (possibly terminated)
- // it should be impossible for these to be invalid
- ContextRef _cur_c(cur_c);
- SurfaceRef _cur_r(cur_r);
- SurfaceRef _cur_d(cur_d);
-
- cur_c->read = NULL;
- cur_c->draw = NULL;
-
- _cur_c.release();
- _cur_r.release();
- _cur_d.release();
- }
-}
-
EGLBoolean eglMakeCurrent( EGLDisplay dpy, EGLSurface draw,
EGLSurface read, EGLContext ctx)
{
@@ -643,21 +642,13 @@
impl_read = r->surface;
}
- EGLBoolean result;
- if (c) {
- result = c->cnx->egl.eglMakeCurrent(
- dp->disp[c->impl].dpy, impl_draw, impl_read, impl_ctx);
- } else {
- result = cur_c->cnx->egl.eglMakeCurrent(
- dp->disp[cur_c->impl].dpy, impl_draw, impl_read, impl_ctx);
- }
+ EGLBoolean result = const_cast<egl_display_t*>(dp)->makeCurrent(c, cur_c,
+ draw, read, ctx,
+ impl_draw, impl_read, impl_ctx);
if (result == EGL_TRUE) {
-
- loseCurrent(cur_c);
-
- if (ctx != EGL_NO_CONTEXT) {
+ if (c) {
setGLHooksThreadSpecific(c->cnx->hooks[c->version]);
egl_tls_t::setContext(ctx);
#if EGL_TRACE
@@ -667,8 +658,6 @@
_c.acquire();
_r.acquire();
_d.acquire();
- c->read = read;
- c->draw = draw;
} else {
setGLHooksThreadSpecific(&gHooksNoContext);
egl_tls_t::setContext(EGL_NO_CONTEXT);
@@ -904,7 +893,8 @@
cnx->hooks[GLESv1_INDEX]->ext.extensions[slot] =
cnx->hooks[GLESv2_INDEX]->ext.extensions[slot] =
#if EGL_TRACE
- debugHooks->ext.extensions[slot] = gHooksTrace.ext.extensions[slot] =
+ debugHooks->ext.extensions[slot] =
+ gHooksTrace.ext.extensions[slot] =
#endif
cnx->egl.eglGetProcAddress(procname);
}
@@ -1160,7 +1150,7 @@
clearError();
// If there is context bound to the thread, release it
- loseCurrent(get_context(getContext()));
+ egl_display_t::loseCurrent(get_context(getContext()));
for (int i=0 ; i<IMPL_NUM_IMPLEMENTATIONS ; i++) {
egl_connection_t* const cnx = &gEGLImpl[i];
diff --git a/opengl/libs/EGL/egl_display.cpp b/opengl/libs/EGL/egl_display.cpp
index 53eaf9a..5cf5236 100644
--- a/opengl/libs/EGL/egl_display.cpp
+++ b/opengl/libs/EGL/egl_display.cpp
@@ -342,6 +342,47 @@
return res;
}
+void egl_display_t::loseCurrent(egl_context_t * cur_c)
+{
+ if (cur_c) {
+ egl_surface_t * cur_r = get_surface(cur_c->read);
+ egl_surface_t * cur_d = get_surface(cur_c->draw);
+
+ // by construction, these are either 0 or valid (possibly terminated)
+ // it should be impossible for these to be invalid
+ ContextRef _cur_c(cur_c);
+ SurfaceRef _cur_r(cur_r);
+ SurfaceRef _cur_d(cur_d);
+
+ cur_c->onLooseCurrent();
+
+ _cur_c.release();
+ _cur_r.release();
+ _cur_d.release();
+ }
+}
+
+EGLBoolean egl_display_t::makeCurrent(egl_context_t* c, egl_context_t* cur_c,
+ EGLSurface draw, EGLSurface read, EGLContext ctx,
+ EGLSurface impl_draw, EGLSurface impl_read, EGLContext impl_ctx)
+{
+ Mutex::Autolock _l(lock);
+ EGLBoolean result;
+ if (c) {
+ result = c->cnx->egl.eglMakeCurrent(
+ disp[c->impl].dpy, impl_draw, impl_read, impl_ctx);
+ } else {
+ result = cur_c->cnx->egl.eglMakeCurrent(
+ disp[cur_c->impl].dpy, impl_draw, impl_read, impl_ctx);
+ }
+ if (result == EGL_TRUE) {
+ loseCurrent(cur_c);
+ if (c) {
+ c->onMakeCurrent(draw, read);
+ }
+ }
+ return result;
+}
// ----------------------------------------------------------------------------
}; // namespace android
diff --git a/opengl/libs/EGL/egl_display.h b/opengl/libs/EGL/egl_display.h
index 042ae07..4479e00 100644
--- a/opengl/libs/EGL/egl_display.h
+++ b/opengl/libs/EGL/egl_display.h
@@ -39,6 +39,7 @@
// ----------------------------------------------------------------------------
class egl_object_t;
+class egl_context_t;
class egl_connection_t;
// ----------------------------------------------------------------------------
@@ -84,10 +85,14 @@
// add reference to this object. returns true if this is a valid object.
bool getObject(egl_object_t* object) const;
-
static egl_display_t* get(EGLDisplay dpy);
static EGLDisplay getFromNativeDisplay(EGLNativeDisplayType disp);
+ EGLBoolean makeCurrent(egl_context_t* c, egl_context_t* cur_c,
+ EGLSurface draw, EGLSurface read, EGLContext ctx,
+ EGLSurface impl_draw, EGLSurface impl_read, EGLContext impl_ctx);
+ static void loseCurrent(egl_context_t * cur_c);
+
inline bool isReady() const { return (refs > 0); }
inline bool isValid() const { return magic == '_dpy'; }
inline bool isAlive() const { return isValid(); }
diff --git a/opengl/libs/EGL/egl_object.cpp b/opengl/libs/EGL/egl_object.cpp
index 26e8c3e..b660c53 100644
--- a/opengl/libs/EGL/egl_object.cpp
+++ b/opengl/libs/EGL/egl_object.cpp
@@ -62,5 +62,41 @@
}
// ----------------------------------------------------------------------------
+
+egl_context_t::egl_context_t(EGLDisplay dpy, EGLContext context, EGLConfig config,
+ int impl, egl_connection_t const* cnx, int version) :
+ egl_object_t(get_display(dpy)), dpy(dpy), context(context),
+ config(config), read(0), draw(0), impl(impl), cnx(cnx),
+ version(version)
+{
+}
+
+void egl_context_t::onLooseCurrent() {
+ read = NULL;
+ draw = NULL;
+}
+
+void egl_context_t::onMakeCurrent(EGLSurface draw, EGLSurface read) {
+ this->read = read;
+ this->draw = draw;
+
+ /*
+ * Here we cache the GL_EXTENSIONS string for this context and we
+ * add the extensions always handled by the wrapper
+ */
+
+ if (gl_extensions.isEmpty()) {
+ // call the implementation's glGetString(GL_EXTENSIONS)
+ const char* exts = (const char *)gEGLImpl[impl].hooks[version]->gl.glGetString(GL_EXTENSIONS);
+ gl_extensions.setTo(exts);
+ if (gl_extensions.find("GL_EXT_debug_marker") < 0) {
+ String8 temp("GL_EXT_debug_marker ");
+ temp.append(gl_extensions);
+ gl_extensions.setTo(temp);
+ }
+ }
+}
+
+// ----------------------------------------------------------------------------
}; // namespace android
// ----------------------------------------------------------------------------
diff --git a/opengl/libs/EGL/egl_object.h b/opengl/libs/EGL/egl_object.h
index 7106fa5..abd4cbb 100644
--- a/opengl/libs/EGL/egl_object.h
+++ b/opengl/libs/EGL/egl_object.h
@@ -28,6 +28,7 @@
#include <GLES/glext.h>
#include <utils/threads.h>
+#include <utils/String8.h>
#include <system/window.h>
@@ -158,11 +159,11 @@
typedef egl_object_t::LocalRef<egl_context_t, EGLContext> Ref;
egl_context_t(EGLDisplay dpy, EGLContext context, EGLConfig config,
- int impl, egl_connection_t const* cnx, int version) :
- egl_object_t(get_display(dpy)), dpy(dpy), context(context),
- config(config), read(0), draw(0), impl(impl), cnx(cnx),
- version(version) {
- }
+ int impl, egl_connection_t const* cnx, int version);
+
+ void onLooseCurrent();
+ void onMakeCurrent(EGLSurface draw, EGLSurface read);
+
EGLDisplay dpy;
EGLContext context;
EGLConfig config;
@@ -171,6 +172,7 @@
int impl;
egl_connection_t const* cnx;
int version;
+ String8 gl_extensions;
};
class egl_image_t: public egl_object_t {
diff --git a/opengl/libs/EGL/egldefs.h b/opengl/libs/EGL/egldefs.h
index 107acd9..ff20957 100644
--- a/opengl/libs/EGL/egldefs.h
+++ b/opengl/libs/EGL/egldefs.h
@@ -58,6 +58,7 @@
extern gl_hooks_t gHooksNoContext;
extern pthread_key_t gGLWrapperKey;
extern "C" void gl_unimplemented();
+extern "C" void gl_noop();
extern char const * const gl_names[];
extern char const * const egl_names[];
diff --git a/opengl/libs/EGL/getProcAddress.cpp b/opengl/libs/EGL/getProcAddress.cpp
index f89c865..8dcf38d 100644
--- a/opengl/libs/EGL/getProcAddress.cpp
+++ b/opengl/libs/EGL/getProcAddress.cpp
@@ -82,23 +82,41 @@
#endif
+
#define GL_EXTENSION_LIST(name) \
- name(0) name(1) name(2) name(3) \
- name(4) name(5) name(6) name(7) \
- name(8) name(9) name(10) name(11) \
- name(12) name(13) name(14) name(15) \
- name(16) name(17) name(18) name(19) \
- name(20) name(21) name(22) name(23) \
- name(24) name(25) name(26) name(27) \
- name(28) name(29) name(30) name(31) \
- name(32) name(33) name(34) name(35) \
- name(36) name(37) name(38) name(39) \
- name(40) name(41) name(42) name(43) \
- name(44) name(45) name(46) name(47) \
- name(48) name(49) name(50) name(51) \
- name(52) name(53) name(54) name(55) \
- name(56) name(57) name(58) name(59) \
- name(60) name(61) name(62) name(63)
+ name(0) name(1) name(2) name(3) name(4) name(5) name(6) name(7) \
+ name(8) name(9) name(10) name(11) name(12) name(13) name(14) name(15) \
+ name(16) name(17) name(18) name(19) name(20) name(21) name(22) name(23) \
+ name(24) name(25) name(26) name(27) name(28) name(29) name(30) name(31) \
+ name(32) name(33) name(34) name(35) name(36) name(37) name(38) name(39) \
+ name(40) name(41) name(42) name(43) name(44) name(45) name(46) name(47) \
+ name(48) name(49) name(50) name(51) name(52) name(53) name(54) name(55) \
+ name(56) name(57) name(58) name(59) name(60) name(61) name(62) name(63) \
+ name(64) name(65) name(66) name(67) name(68) name(69) name(70) name(71) \
+ name(72) name(73) name(74) name(75) name(76) name(77) name(78) name(79) \
+ name(80) name(81) name(82) name(83) name(84) name(85) name(86) name(87) \
+ name(88) name(89) name(90) name(91) name(92) name(93) name(94) name(95) \
+ name(96) name(97) name(98) name(99) \
+ name(100) name(101) name(102) name(103) name(104) name(105) name(106) name(107) \
+ name(108) name(109) name(110) name(111) name(112) name(113) name(114) name(115) \
+ name(116) name(117) name(118) name(119) name(120) name(121) name(122) name(123) \
+ name(124) name(125) name(126) name(127) name(128) name(129) name(130) name(131) \
+ name(132) name(133) name(134) name(135) name(136) name(137) name(138) name(139) \
+ name(140) name(141) name(142) name(143) name(144) name(145) name(146) name(147) \
+ name(148) name(149) name(150) name(151) name(152) name(153) name(154) name(155) \
+ name(156) name(157) name(158) name(159) name(160) name(161) name(162) name(163) \
+ name(164) name(165) name(166) name(167) name(168) name(169) name(170) name(171) \
+ name(172) name(173) name(174) name(175) name(176) name(177) name(178) name(179) \
+ name(180) name(181) name(182) name(183) name(184) name(185) name(186) name(187) \
+ name(188) name(189) name(190) name(191) name(192) name(193) name(194) name(195) \
+ name(196) name(197) name(198) name(199) \
+ name(200) name(201) name(202) name(203) name(204) name(205) name(206) name(207) \
+ name(208) name(209) name(210) name(211) name(212) name(213) name(214) name(215) \
+ name(216) name(217) name(218) name(219) name(220) name(221) name(222) name(223) \
+ name(224) name(225) name(226) name(227) name(228) name(229) name(230) name(231) \
+ name(232) name(233) name(234) name(235) name(236) name(237) name(238) name(239) \
+ name(240) name(241) name(242) name(243) name(244) name(245) name(246) name(247) \
+ name(248) name(249) name(250) name(251) name(252) name(253) name(254) name(255)
GL_EXTENSION_LIST( GL_EXTENSION )
diff --git a/opengl/libs/GLES2/gl2.cpp b/opengl/libs/GLES2/gl2.cpp
index df22b96..79aa3cd 100644
--- a/opengl/libs/GLES2/gl2.cpp
+++ b/opengl/libs/GLES2/gl2.cpp
@@ -110,6 +110,20 @@
#undef CALL_GL_API
#undef CALL_GL_API_RETURN
+/*
+ * glGetString() is special because we expose some extensions in the wrapper
+ */
+
+extern "C" const GLubyte * __glGetString(GLenum name);
+
+const GLubyte * glGetString(GLenum name)
+{
+ const GLubyte * ret = egl_get_string_for_current_context(name);
+ if (ret == NULL) {
+ ret = __glGetString(name);
+ }
+ return ret;
+}
/*
* These GL calls are special because they need to EGL to retrieve some
diff --git a/opengl/libs/GLES2/gl2_api.in b/opengl/libs/GLES2/gl2_api.in
index 5164450..9a89a52 100644
--- a/opengl/libs/GLES2/gl2_api.in
+++ b/opengl/libs/GLES2/gl2_api.in
@@ -211,7 +211,7 @@
void API_ENTRY(glGetShaderSource)(GLuint shader, GLsizei bufsize, GLsizei* length, GLchar* source) {
CALL_GL_API(glGetShaderSource, shader, bufsize, length, source);
}
-const GLubyte* API_ENTRY(glGetString)(GLenum name) {
+const GLubyte* API_ENTRY(__glGetString)(GLenum name) {
CALL_GL_API_RETURN(glGetString, name);
}
void API_ENTRY(glGetTexParameterfv)(GLenum target, GLenum pname, GLfloat* params) {
diff --git a/opengl/libs/GLES2/gl2ext_api.in b/opengl/libs/GLES2/gl2ext_api.in
index e965625..a8907fd 100644
--- a/opengl/libs/GLES2/gl2ext_api.in
+++ b/opengl/libs/GLES2/gl2ext_api.in
@@ -82,21 +82,204 @@
void API_ENTRY(glGetPerfMonitorCounterDataAMD)(GLuint monitor, GLenum pname, GLsizei dataSize, GLuint *data, GLint *bytesWritten) {
CALL_GL_API(glGetPerfMonitorCounterDataAMD, monitor, pname, dataSize, data, bytesWritten);
}
+void API_ENTRY(glBlitFramebufferANGLE)(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter) {
+ CALL_GL_API(glBlitFramebufferANGLE, srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1, mask, filter);
+}
+void API_ENTRY(glRenderbufferStorageMultisampleANGLE)(GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height) {
+ CALL_GL_API(glRenderbufferStorageMultisampleANGLE, target, samples, internalformat, width, height);
+}
+void API_ENTRY(glRenderbufferStorageMultisampleAPPLE)(GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height) {
+ CALL_GL_API(glRenderbufferStorageMultisampleAPPLE, target, samples, internalformat, width, height);
+}
+void API_ENTRY(glResolveMultisampleFramebufferAPPLE)(void) {
+ CALL_GL_API(glResolveMultisampleFramebufferAPPLE);
+}
+void API_ENTRY(glLabelObjectEXT)(GLenum type, GLuint object, GLsizei length, const GLchar *label) {
+ CALL_GL_API(glLabelObjectEXT, type, object, length, label);
+}
+void API_ENTRY(glGetObjectLabelEXT)(GLenum type, GLuint object, GLsizei bufSize, GLsizei *length, GLchar *label) {
+ CALL_GL_API(glGetObjectLabelEXT, type, object, bufSize, length, label);
+}
+void API_ENTRY(glInsertEventMarkerEXT)(GLsizei length, const GLchar *marker) {
+ CALL_GL_API(glInsertEventMarkerEXT, length, marker);
+}
+void API_ENTRY(glPushGroupMarkerEXT)(GLsizei length, const GLchar *marker) {
+ CALL_GL_API(glPushGroupMarkerEXT, length, marker);
+}
+void API_ENTRY(glPopGroupMarkerEXT)(void) {
+ CALL_GL_API(glPopGroupMarkerEXT);
+}
void API_ENTRY(glDiscardFramebufferEXT)(GLenum target, GLsizei numAttachments, const GLenum *attachments) {
CALL_GL_API(glDiscardFramebufferEXT, target, numAttachments, attachments);
}
+void API_ENTRY(glRenderbufferStorageMultisampleEXT)(GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height) {
+ CALL_GL_API(glRenderbufferStorageMultisampleEXT, target, samples, internalformat, width, height);
+}
+void API_ENTRY(glFramebufferTexture2DMultisampleEXT)(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level, GLsizei samples) {
+ CALL_GL_API(glFramebufferTexture2DMultisampleEXT, target, attachment, textarget, texture, level, samples);
+}
void API_ENTRY(glMultiDrawArraysEXT)(GLenum mode, GLint *first, GLsizei *count, GLsizei primcount) {
CALL_GL_API(glMultiDrawArraysEXT, mode, first, count, primcount);
}
void API_ENTRY(glMultiDrawElementsEXT)(GLenum mode, const GLsizei *count, GLenum type, const GLvoid* *indices, GLsizei primcount) {
CALL_GL_API(glMultiDrawElementsEXT, mode, count, type, indices, primcount);
}
+void API_ENTRY(glGenQueriesEXT)(GLsizei n, GLuint *ids) {
+ CALL_GL_API(glGenQueriesEXT, n, ids);
+}
+void API_ENTRY(glDeleteQueriesEXT)(GLsizei n, const GLuint *ids) {
+ CALL_GL_API(glDeleteQueriesEXT, n, ids);
+}
+GLboolean API_ENTRY(glIsQueryEXT)(GLuint id) {
+ CALL_GL_API_RETURN(glIsQueryEXT, id);
+}
+void API_ENTRY(glBeginQueryEXT)(GLenum target, GLuint id) {
+ CALL_GL_API(glBeginQueryEXT, target, id);
+}
+void API_ENTRY(glEndQueryEXT)(GLenum target) {
+ CALL_GL_API(glEndQueryEXT, target);
+}
+void API_ENTRY(glGetQueryivEXT)(GLenum target, GLenum pname, GLint *params) {
+ CALL_GL_API(glGetQueryivEXT, target, pname, params);
+}
+void API_ENTRY(glGetQueryObjectuivEXT)(GLuint id, GLenum pname, GLuint *params) {
+ CALL_GL_API(glGetQueryObjectuivEXT, id, pname, params);
+}
+GLenum API_ENTRY(glGetGraphicsResetStatusEXT)(void) {
+ CALL_GL_API_RETURN(glGetGraphicsResetStatusEXT);
+}
+void API_ENTRY(glReadnPixelsEXT)(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLsizei bufSize, void *data) {
+ CALL_GL_API(glReadnPixelsEXT, x, y, width, height, format, type, bufSize, data);
+}
+void API_ENTRY(glGetnUniformfvEXT)(GLuint program, GLint location, GLsizei bufSize, float *params) {
+ CALL_GL_API(glGetnUniformfvEXT, program, location, bufSize, params);
+}
+void API_ENTRY(glGetnUniformivEXT)(GLuint program, GLint location, GLsizei bufSize, GLint *params) {
+ CALL_GL_API(glGetnUniformivEXT, program, location, bufSize, params);
+}
+void API_ENTRY(glUseProgramStagesEXT)(GLuint pipeline, GLbitfield stages, GLuint program) {
+ CALL_GL_API(glUseProgramStagesEXT, pipeline, stages, program);
+}
+void API_ENTRY(glActiveShaderProgramEXT)(GLuint pipeline, GLuint program) {
+ CALL_GL_API(glActiveShaderProgramEXT, pipeline, program);
+}
+GLuint API_ENTRY(glCreateShaderProgramvEXT)(GLenum type, GLsizei count, const GLchar **strings) {
+ CALL_GL_API_RETURN(glCreateShaderProgramvEXT, type, count, strings);
+}
+void API_ENTRY(glBindProgramPipelineEXT)(GLuint pipeline) {
+ CALL_GL_API(glBindProgramPipelineEXT, pipeline);
+}
+void API_ENTRY(glDeleteProgramPipelinesEXT)(GLsizei n, const GLuint *pipelines) {
+ CALL_GL_API(glDeleteProgramPipelinesEXT, n, pipelines);
+}
+void API_ENTRY(glGenProgramPipelinesEXT)(GLsizei n, GLuint *pipelines) {
+ CALL_GL_API(glGenProgramPipelinesEXT, n, pipelines);
+}
+GLboolean API_ENTRY(glIsProgramPipelineEXT)(GLuint pipeline) {
+ CALL_GL_API_RETURN(glIsProgramPipelineEXT, pipeline);
+}
+void API_ENTRY(glProgramParameteriEXT)(GLuint program, GLenum pname, GLint value) {
+ CALL_GL_API(glProgramParameteriEXT, program, pname, value);
+}
+void API_ENTRY(glGetProgramPipelineivEXT)(GLuint pipeline, GLenum pname, GLint *params) {
+ CALL_GL_API(glGetProgramPipelineivEXT, pipeline, pname, params);
+}
+void API_ENTRY(glProgramUniform1iEXT)(GLuint program, GLint location, GLint x) {
+ CALL_GL_API(glProgramUniform1iEXT, program, location, x);
+}
+void API_ENTRY(glProgramUniform2iEXT)(GLuint program, GLint location, GLint x, GLint y) {
+ CALL_GL_API(glProgramUniform2iEXT, program, location, x, y);
+}
+void API_ENTRY(glProgramUniform3iEXT)(GLuint program, GLint location, GLint x, GLint y, GLint z) {
+ CALL_GL_API(glProgramUniform3iEXT, program, location, x, y, z);
+}
+void API_ENTRY(glProgramUniform4iEXT)(GLuint program, GLint location, GLint x, GLint y, GLint z, GLint w) {
+ CALL_GL_API(glProgramUniform4iEXT, program, location, x, y, z, w);
+}
+void API_ENTRY(glProgramUniform1fEXT)(GLuint program, GLint location, GLfloat x) {
+ CALL_GL_API(glProgramUniform1fEXT, program, location, x);
+}
+void API_ENTRY(glProgramUniform2fEXT)(GLuint program, GLint location, GLfloat x, GLfloat y) {
+ CALL_GL_API(glProgramUniform2fEXT, program, location, x, y);
+}
+void API_ENTRY(glProgramUniform3fEXT)(GLuint program, GLint location, GLfloat x, GLfloat y, GLfloat z) {
+ CALL_GL_API(glProgramUniform3fEXT, program, location, x, y, z);
+}
+void API_ENTRY(glProgramUniform4fEXT)(GLuint program, GLint location, GLfloat x, GLfloat y, GLfloat z, GLfloat w) {
+ CALL_GL_API(glProgramUniform4fEXT, program, location, x, y, z, w);
+}
+void API_ENTRY(glProgramUniform1ivEXT)(GLuint program, GLint location, GLsizei count, const GLint *value) {
+ CALL_GL_API(glProgramUniform1ivEXT, program, location, count, value);
+}
+void API_ENTRY(glProgramUniform2ivEXT)(GLuint program, GLint location, GLsizei count, const GLint *value) {
+ CALL_GL_API(glProgramUniform2ivEXT, program, location, count, value);
+}
+void API_ENTRY(glProgramUniform3ivEXT)(GLuint program, GLint location, GLsizei count, const GLint *value) {
+ CALL_GL_API(glProgramUniform3ivEXT, program, location, count, value);
+}
+void API_ENTRY(glProgramUniform4ivEXT)(GLuint program, GLint location, GLsizei count, const GLint *value) {
+ CALL_GL_API(glProgramUniform4ivEXT, program, location, count, value);
+}
+void API_ENTRY(glProgramUniform1fvEXT)(GLuint program, GLint location, GLsizei count, const GLfloat *value) {
+ CALL_GL_API(glProgramUniform1fvEXT, program, location, count, value);
+}
+void API_ENTRY(glProgramUniform2fvEXT)(GLuint program, GLint location, GLsizei count, const GLfloat *value) {
+ CALL_GL_API(glProgramUniform2fvEXT, program, location, count, value);
+}
+void API_ENTRY(glProgramUniform3fvEXT)(GLuint program, GLint location, GLsizei count, const GLfloat *value) {
+ CALL_GL_API(glProgramUniform3fvEXT, program, location, count, value);
+}
+void API_ENTRY(glProgramUniform4fvEXT)(GLuint program, GLint location, GLsizei count, const GLfloat *value) {
+ CALL_GL_API(glProgramUniform4fvEXT, program, location, count, value);
+}
+void API_ENTRY(glProgramUniformMatrix2fvEXT)(GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) {
+ CALL_GL_API(glProgramUniformMatrix2fvEXT, program, location, count, transpose, value);
+}
+void API_ENTRY(glProgramUniformMatrix3fvEXT)(GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) {
+ CALL_GL_API(glProgramUniformMatrix3fvEXT, program, location, count, transpose, value);
+}
+void API_ENTRY(glProgramUniformMatrix4fvEXT)(GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) {
+ CALL_GL_API(glProgramUniformMatrix4fvEXT, program, location, count, transpose, value);
+}
+void API_ENTRY(glValidateProgramPipelineEXT)(GLuint pipeline) {
+ CALL_GL_API(glValidateProgramPipelineEXT, pipeline);
+}
+void API_ENTRY(glGetProgramPipelineInfoLogEXT)(GLuint pipeline, GLsizei bufSize, GLsizei *length, GLchar *infoLog) {
+ CALL_GL_API(glGetProgramPipelineInfoLogEXT, pipeline, bufSize, length, infoLog);
+}
+void API_ENTRY(glTexStorage1DEXT)(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width) {
+ CALL_GL_API(glTexStorage1DEXT, target, levels, internalformat, width);
+}
+void API_ENTRY(glTexStorage2DEXT)(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height) {
+ CALL_GL_API(glTexStorage2DEXT, target, levels, internalformat, width, height);
+}
+void API_ENTRY(glTexStorage3DEXT)(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth) {
+ CALL_GL_API(glTexStorage3DEXT, target, levels, internalformat, width, height, depth);
+}
+void API_ENTRY(glTextureStorage1DEXT)(GLuint texture, GLenum target, GLsizei levels, GLenum internalformat, GLsizei width) {
+ CALL_GL_API(glTextureStorage1DEXT, texture, target, levels, internalformat, width);
+}
+void API_ENTRY(glTextureStorage2DEXT)(GLuint texture, GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height) {
+ CALL_GL_API(glTextureStorage2DEXT, texture, target, levels, internalformat, width, height);
+}
+void API_ENTRY(glTextureStorage3DEXT)(GLuint texture, GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth) {
+ CALL_GL_API(glTextureStorage3DEXT, texture, target, levels, internalformat, width, height, depth);
+}
void API_ENTRY(glRenderbufferStorageMultisampleIMG)(GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height) {
CALL_GL_API(glRenderbufferStorageMultisampleIMG, target, samples, internalformat, width, height);
}
void API_ENTRY(glFramebufferTexture2DMultisampleIMG)(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level, GLsizei samples) {
CALL_GL_API(glFramebufferTexture2DMultisampleIMG, target, attachment, textarget, texture, level, samples);
}
+void API_ENTRY(glCoverageMaskNV)(GLboolean mask) {
+ CALL_GL_API(glCoverageMaskNV, mask);
+}
+void API_ENTRY(glCoverageOperationNV)(GLenum operation) {
+ CALL_GL_API(glCoverageOperationNV, operation);
+}
+void API_ENTRY(glDrawBuffersNV)(GLsizei n, const GLenum *bufs) {
+ CALL_GL_API(glDrawBuffersNV, n, bufs);
+}
void API_ENTRY(glDeleteFencesNV)(GLsizei n, const GLuint *fences) {
CALL_GL_API(glDeleteFencesNV, n, fences);
}
@@ -118,11 +301,11 @@
void API_ENTRY(glSetFenceNV)(GLuint fence, GLenum condition) {
CALL_GL_API(glSetFenceNV, fence, condition);
}
-void API_ENTRY(glCoverageMaskNV)(GLboolean mask) {
- CALL_GL_API(glCoverageMaskNV, mask);
+void API_ENTRY(glReadBufferNV)(GLenum mode) {
+ CALL_GL_API(glReadBufferNV, mode);
}
-void API_ENTRY(glCoverageOperationNV)(GLenum operation) {
- CALL_GL_API(glCoverageOperationNV, operation);
+void API_ENTRY(glAlphaFuncQCOM)(GLenum func, GLclampf ref) {
+ CALL_GL_API(glAlphaFuncQCOM, func, ref);
}
void API_ENTRY(glGetDriverControlsQCOM)(GLint *num, GLsizei size, GLuint *driverControls) {
CALL_GL_API(glGetDriverControlsQCOM, num, size, driverControls);
diff --git a/opengl/libs/GLES2_dbg/generate_api_cpp.py b/opengl/libs/GLES2_dbg/generate_api_cpp.py
deleted file mode 100755
index 96cde57..0000000
--- a/opengl/libs/GLES2_dbg/generate_api_cpp.py
+++ /dev/null
@@ -1,219 +0,0 @@
-#!/usr/bin/python
-# -*- coding: utf-8 -*-
-
-#
-# Copyright 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.
-# 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.
-#
-
-import os
-import sys
-
-def RemoveAnnotation(line):
- if line.find(":") >= 0:
- annotation = line[line.find(":"): line.find(" ", line.find(":"))]
- return line.replace(annotation, "*")
- else:
- return line
-
-def generate_api(lines):
- externs = []
- i = 0
- # these have been hand written
- skipFunctions = ["glDrawArrays", "glDrawElements"]
-
- # these have an EXTEND_Debug_* macro for getting data
- extendFunctions = ["glCopyTexImage2D", "glCopyTexSubImage2D", "glReadPixels",
-"glShaderSource", "glTexImage2D", "glTexSubImage2D"]
-
- # these also needs to be forwarded to DbgContext
- contextFunctions = ["glUseProgram", "glEnableVertexAttribArray", "glDisableVertexAttribArray",
-"glVertexAttribPointer", "glBindBuffer", "glBufferData", "glBufferSubData", "glDeleteBuffers",]
-
- for line in lines:
- if line.find("API_ENTRY(") >= 0: # a function prototype
- returnType = line[0: line.find(" API_ENTRY(")]
- functionName = line[line.find("(") + 1: line.find(")")] #extract GL function name
- parameterList = line[line.find(")(") + 2: line.find(") {")]
-
- #if line.find("*") >= 0:
- # extern = "%s Debug_%s(%s);" % (returnType, functionName, parameterList)
- # externs.append(extern)
- # continue
-
- if functionName in skipFunctions:
- sys.stderr.write("!\n! skipping function '%s'\n!\n" % (functionName))
- continue
-
- parameters = parameterList.split(',')
- paramIndex = 0
- if line.find("*") >= 0 and (line.find("*") < line.find(":") or line.find("*") > line.rfind(":")): # unannotated pointer
- if not functionName in extendFunctions:
- # add function to list of functions that should be hand written, but generate code anyways
- extern = "%s Debug_%s(%s);" % (returnType, functionName, RemoveAnnotation(parameterList))
- sys.stderr.write("%s should be hand written\n" % (extern))
- print "// FIXME: this function has pointers, it should be hand written"
- externs.append(extern)
-
- print "%s Debug_%s(%s)\n{" % (returnType, functionName, RemoveAnnotation(parameterList))
- print " glesv2debugger::Message msg;"
-
- if parameterList == "void":
- parameters = []
- arguments = ""
- paramNames = []
- inout = ""
- getData = ""
-
- callerMembers = ""
- setCallerMembers = ""
- setMsgParameters = ""
-
- for parameter in parameters:
- const = parameter.find("const")
- parameter = parameter.replace("const", "")
- parameter = parameter.strip()
- paramType = parameter.split(' ')[0]
- paramName = parameter.split(' ')[1]
- annotation = ""
- arguments += paramName
- if parameter.find(":") >= 0: # has annotation
- assert inout == "" # only one parameter should be annotated
- sys.stderr.write("%s is annotated: %s \n" % (functionName, paramType))
- inout = paramType.split(":")[2]
- annotation = paramType.split(":")[1]
- paramType = paramType.split(":")[0]
- count = 1
- countArg = ""
- if annotation.find("*") >= 0: # [1,n] * param
- count = int(annotation.split("*")[0])
- countArg = annotation.split("*")[1]
- assert countArg in paramNames
- elif annotation in paramNames:
- count = 1
- countArg = annotation
- elif annotation == "GLstring":
- annotation = "strlen(%s)" % (paramName)
- else:
- count = int(annotation)
-
- setMsgParameters += " msg.set_arg%d(ToInt(%s));\n" % (paramIndex, paramName)
- if paramType.find("void") >= 0:
- getData += " msg.mutable_data()->assign(reinterpret_cast<const char *>(%s), %s * sizeof(char));" % (paramName, annotation)
- else:
- getData += " msg.mutable_data()->assign(reinterpret_cast<const char *>(%s), %s * sizeof(%s));" % (paramName, annotation, paramType)
- paramType += "*"
- else:
- if paramType == "GLfloat" or paramType == "GLclampf" or paramType.find("*") >= 0:
- setMsgParameters += " msg.set_arg%d(ToInt(%s));\n" % (paramIndex, paramName)
- else:
- setMsgParameters += " msg.set_arg%d(%s);\n" % (paramIndex, paramName)
- if paramIndex < len(parameters) - 1:
- arguments += ', '
- if const >= 0:
- paramType = "const " + paramType
- paramNames.append(paramName)
- paramIndex += 1
- callerMembers += " %s %s;\n" % (paramType, paramName)
- setCallerMembers += " caller.%s = %s;\n" % (paramName, paramName)
-
- print " struct : public FunctionCall {"
- print callerMembers
- print " const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {"
- if inout in ["out", "inout"]: # get timing excluding output data copy
- print " nsecs_t c0 = systemTime(timeMode);"
- if returnType == "void":
- print " _c->%s(%s);" % (functionName, arguments)
- else:
- print " const int * ret = reinterpret_cast<const int *>(_c->%s(%s));" % (functionName, arguments)
- print " msg.set_ret(ToInt(ret));"
- if inout in ["out", "inout"]:
- print " msg.set_time((systemTime(timeMode) - c0) * 1e-6f);"
- print " " + getData
- if functionName in extendFunctions:
- print "\
-#ifdef EXTEND_AFTER_CALL_Debug_%s\n\
- EXTEND_AFTER_CALL_Debug_%s;\n\
-#endif" % (functionName, functionName)
- if functionName in contextFunctions:
- print " getDbgContextThreadSpecific()->%s(%s);" % (functionName, arguments)
- if returnType == "void":
- print " return 0;"
- else:
- print " return ret;"
- print """ }
- } caller;"""
- print setCallerMembers
- print setMsgParameters
-
- if line.find("*") >= 0 or line.find(":") >= 0:
- print " // FIXME: check for pointer usage"
- if inout in ["in", "inout"]:
- print getData
- if functionName in extendFunctions:
- print "\
-#ifdef EXTEND_Debug_%s\n\
- EXTEND_Debug_%s;\n\
-#endif" % (functionName, functionName)
- print " int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_%s);"\
- % (functionName)
- if returnType != "void":
- if returnType == "GLboolean":
- print " return static_cast<GLboolean>(reinterpret_cast<int>(ret));"
- else:
- print " return reinterpret_cast<%s>(ret);" % (returnType)
- print "}\n"
-
-
- print "// FIXME: the following functions should be written by hand"
- for extern in externs:
- print extern
-
-if __name__ == "__main__":
- print """\
-/*
- ** Copyright 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.
- ** 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.
- */
-
-// auto generated by generate_api_cpp.py
-
-#include <utils/Debug.h>
-
-#include "src/header.h"
-#include "src/api.h"
-
-template<typename T> static int ToInt(const T & t)
-{
- COMPILE_TIME_ASSERT_FUNCTION_SCOPE(sizeof(T) == sizeof(int));
- return (int &)t;
-}
-"""
- lines = open("gl2_api_annotated.in").readlines()
- generate_api(lines)
- #lines = open("gl2ext_api.in").readlines()
- #generate_api(lines)
-
-
diff --git a/opengl/libs/GLES2_dbg/generate_caller_cpp.py b/opengl/libs/GLES2_dbg/generate_caller_cpp.py
deleted file mode 100755
index ee4208d..0000000
--- a/opengl/libs/GLES2_dbg/generate_caller_cpp.py
+++ /dev/null
@@ -1,199 +0,0 @@
-#!/usr/bin/python
-# -*- coding: utf-8 -*-
-
-#
-# Copyright 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.
-# 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.
-#
-
-import os
-import sys
-
-externs = []
-
-def generate_caller(lines):
- i = 0
- output = ""
- skipFunctions = []
-
- for line in lines:
- if line.find("API_ENTRY(") >= 0: # a function prototype
- returnType = line[0: line.find(" API_ENTRY(")]
- functionName = line[line.find("(") + 1: line.find(")")] #extract GL function name
- parameterList = line[line.find(")(") + 2: line.find(") {")]
-
- #if line.find("*") >= 0:
- # extern = "%s Debug_%s(%s);" % (returnType, functionName, parameterList)
- # externs.append(extern)
- # continue
-
- if functionName in skipFunctions:
- sys.stderr.write("!\n! skipping function '%s'\n!\n" % functionName)
- continue
- output += "\
- case glesv2debugger::Message_Function_%s:\n" % functionName
- parameters = parameterList.split(',')
- paramIndex = 0
- if line.find("*") >= 0 and (line.find("*") < line.find(":") or line.find("*") > line.rfind(":")): # unannotated pointer
- # add function to list of functions that should be hand written, but generate code anyways
- externs.append(functionName)
- output += "\
- ret = GenerateCall_%s(dbg, cmd, msg, prevRet);\n\
- break;\n" % (functionName)
- continue
- elif line.find(":out") >= 0 or line.find(":inout") >= 0:
- externs.append(functionName)
- output += "\
- ret = GenerateCall_%s(dbg, cmd, msg, prevRet);\n\
- break; // annotated output pointers\n" % (functionName)
- continue
-
- if parameterList == "void":
- parameters = []
- arguments = ""
- paramNames = []
- inout = ""
- getData = ""
-
- callerMembers = ""
-
- for parameter in parameters:
- const = parameter.find("const")
- parameter = parameter.replace("const", "")
- parameter = parameter.strip()
- paramType = parameter.split(' ')[0]
- paramName = parameter.split(' ')[1]
- annotation = ""
- if parameter.find(":") >= 0: # has annotation
- assert inout == "" # only one parameter should be annotated
- sys.stderr.write("%s is annotated: %s \n" % (functionName, paramType))
- inout = paramType.split(":")[2]
- annotation = paramType.split(":")[1]
- paramType = paramType.split(":")[0]
- count = 1
- countArg = ""
- if annotation.find("*") >= 0: # [1,n] * param
- count = int(annotation.split("*")[0])
- countArg = annotation.split("*")[1]
- assert countArg in paramNames
- elif annotation in paramNames:
- count = 1
- countArg = annotation
- elif annotation == "GLstring":
- annotation = "strlen(%s)" % (paramName)
- else:
- count = int(annotation)
-
- paramType += "*"
- arguments += "reinterpret_cast<%s>(const_cast<char *>(cmd.data().data()))" % (paramType)
- elif paramType == "GLboolean":
- arguments += "GLboolean(cmd.arg%d())" % (paramIndex)
- else:
- arguments += "static_cast<%s>(cmd.arg%d())" % (paramType, paramIndex)
-
- if paramIndex < len(parameters) - 1:
- arguments += ", "
- if len(arguments) - arguments.rfind("\n") > 60 :
- arguments += "\n\
- "
- if const >= 0:
- paramType = "const " + paramType
- paramNames.append(paramName)
- paramIndex += 1
-
- if returnType == "void":
- output += "\
- dbg->hooks->gl.%s(\n\
- %s);\n\
- break;\n" % (functionName, arguments)
- else:
- output += "\
- msg.set_ret(static_cast<int>(dbg->hooks->gl.%s(\n\
- %s)));\n\
- if (cmd.has_ret())\n\
- ret = reinterpret_cast<int *>(msg.ret());\n\
- break;\n" % (functionName, arguments)
- return output
-
-if __name__ == "__main__":
-
- lines = open("gl2_api_annotated.in").readlines()
- output = generate_caller(lines)
-
- out = open("src/caller.cpp", "w")
- out.write("""\
-/*
- ** Copyright 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.
- ** 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.
- */
-
-// auto generated by generate_caller_cpp.py
-// implement declarations in caller.h
-
-#include "header.h"
-
-namespace android {
-
-""")
-
- for extern in externs:
- out.write("\
-static const int * GenerateCall_%s(DbgContext * const dbg,\n\
- const glesv2debugger::Message & cmd, glesv2debugger::Message & msg, const int * const prevRet);\n" % (extern))
- print("\
-static const int * GenerateCall_%s(DbgContext * const dbg,\n\
- const glesv2debugger::Message & cmd,\n\
- glesv2debugger::Message & msg, const int * const prevRet)\n\
-{ assert(0); return prevRet; }\n" % (extern))
-
- out.write(
-"""
-#include "caller.h"
-
-const int * GenerateCall(DbgContext * const dbg, const glesv2debugger::Message & cmd,
- glesv2debugger::Message & msg, const int * const prevRet)
-{
- LOGD("GenerateCall function=%u", cmd.function());
- const int * ret = prevRet; // only some functions have return value
- nsecs_t c0 = systemTime(timeMode);
- switch (cmd.function()) {""")
-
- out.write(output)
-
- out.write("""\
- default:
- assert(0);
- }
- msg.set_time((systemTime(timeMode) - c0) * 1e-6f);
- msg.set_context_id(reinterpret_cast<int>(dbg));
- msg.set_function(cmd.function());
- msg.set_type(glesv2debugger::Message_Type_AfterCall);
- return ret;
-}
-
-}; // name space android {
-""")
-
-
diff --git a/opengl/libs/GLES2_dbg/generate_debug_in.py b/opengl/libs/GLES2_dbg/generate_debug_in.py
deleted file mode 100755
index 1280c6f..0000000
--- a/opengl/libs/GLES2_dbg/generate_debug_in.py
+++ /dev/null
@@ -1,80 +0,0 @@
-#!/usr/bin/python
-# -*- coding: utf-8 -*-
-
-#
-# Copyright 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.
-# 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.
-#
-
-import os
-import sys
-
-def append_functions(functions, lines):
- i = 0
- for line in lines:
- if line.find("API_ENTRY(") >= 0: # a function prototype
- returnType = line[0: line.find(" API_ENTRY(")]
- functionName = line[line.find("(") + 1: line.find(")")] #extract GL function name
- parameterList = line[line.find(")(") + 2: line.find(") {")]
-
- functions.append(functionName)
- #print functionName
- continue
-
- parameters = parameterList.split(',')
- paramIndex = 0
- if line.find("*") >= 0:
- print "// FIXME: this function has pointers, it should be hand written"
- externs.append("%s Tracing_%s(%s);" % (returnType, functionName, parameterList))
- print "%s Tracing_%s(%s)\n{" % (returnType, functionName, parameterList)
-
- if parameterList == "void":
- parameters = []
-
- arguments = ""
-
- for parameter in parameters:
- parameter = parameter.replace("const", "")
- parameter = parameter.strip()
- paramType = parameter.split(' ')[0]
- paramName = parameter.split(' ')[1]
-
- paramIndex += 1
-
- return functions
-
-
-
-if __name__ == "__main__":
- definedFunctions = []
- lines = open("gl2_api_annotated.in").readlines()
- definedFunctions = append_functions(definedFunctions, lines)
-
- output = open("../debug.in", "w")
- lines = open("../trace.in").readlines()
- output.write("// the following functions are not defined in GLESv2_dbg\n")
- for line in lines:
- functionName = ""
- if line.find("TRACE_GL(") >= 0: # a function prototype
- functionName = line.split(',')[1].strip()
- elif line.find("TRACE_GL_VOID(") >= 0: # a function prototype
- functionName = line[line.find("(") + 1: line.find(",")] #extract GL function name
- else:
- continue
- if functionName in definedFunctions:
- #print functionName
- continue
- else:
- output.write(line)
-
diff --git a/opengl/libs/GLES2_dbg/generate_debugger_message_proto.py b/opengl/libs/GLES2_dbg/generate_debugger_message_proto.py
deleted file mode 100755
index 535b13e..0000000
--- a/opengl/libs/GLES2_dbg/generate_debugger_message_proto.py
+++ /dev/null
@@ -1,155 +0,0 @@
-#!/usr/bin/python
-# -*- coding: utf-8 -*-
-
-#
-# Copyright 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.
-# 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.
-#
-
-import os
-
-def generate_egl_entries(output, lines, i):
- for line in lines:
- if line.find("EGL_ENTRY(") >= 0:
- line = line.split(",")[1].strip() #extract EGL function name
- output.write(" %s = %d;\n" % (line, i))
- i += 1
- return i
-
-
-def generate_gl_entries(output,lines,i):
- for line in lines:
- if line.find("API_ENTRY(") >= 0:
- line = line[line.find("(") + 1: line.find(")")] #extract GL function name
- output.write(" %s = %d;\n" % (line, i))
- i += 1
- return i
-
-
-if __name__ == "__main__":
- output = open("debugger_message.proto",'w')
- output.write("""\
-/*
- * 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.
- * 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.
- */
-
-// do not edit; auto generated by generate_debugger_message_proto.py
-
-package com.android.glesv2debugger;
-
-option optimize_for = LITE_RUNTIME;
-
-message Message
-{
- required int32 context_id = 1; // GL context id
- enum Function
- {
-""")
-
- i = 0;
-
- lines = open("gl2_api_annotated.in").readlines()
- i = generate_gl_entries(output, lines, i)
- output.write(" // end of GL functions\n")
-
- #lines = open("gl2ext_api.in").readlines()
- #i = generate_gl_entries(output, lines, i)
- #output.write(" // end of GL EXT functions\n")
-
- lines = open("../EGL/egl_entries.in").readlines()
- i = generate_egl_entries(output, lines, i)
- output.write(" // end of GL EXT functions\n")
-
- output.write(" ACK = %d;\n" % (i))
- i += 1
-
- output.write(" NEG = %d;\n" % (i))
- i += 1
-
- output.write(" CONTINUE = %d;\n" % (i))
- i += 1
-
- output.write(" SKIP = %d;\n" % (i))
- i += 1
-
- output.write(" SETPROP = %d;\n" % (i))
- i += 1
-
- output.write(""" }
- required Function function = 2 [default = NEG]; // type/function of message
- enum Type
- {
- BeforeCall = 0;
- AfterCall = 1;
- AfterGeneratedCall = 2;
- Response = 3; // currently used for misc messages
- CompleteCall = 4; // BeforeCall and AfterCall merged
- }
- required Type type = 3;
- required bool expect_response = 4;
- optional int32 ret = 5; // return value from previous GL call
- optional int32 arg0 = 6; // args to GL call
- optional int32 arg1 = 7;
- optional int32 arg2 = 8;
- optional int32 arg3 = 9;
- optional int32 arg4 = 16;
- optional int32 arg5 = 17;
- optional int32 arg6 = 18;
- optional int32 arg7 = 19; // glDrawArrays/Elements sets this to active number of attributes
- optional int32 arg8 = 20;
-
- optional bytes data = 10; // variable length data used for GL call
- enum DataType
- {
- ReferencedImage = 0; // for image sourced from ReadPixels
- NonreferencedImage = 1; // for image sourced from ReadPixels
- };
- // most data types can be inferred from function
- optional DataType data_type = 23;
- // these are used for image data when they cannot be determined from args
- optional int32 pixel_format = 24;
- optional int32 pixel_type = 25;
- optional int32 image_width = 26;
- optional int32 image_height = 27;
-
- optional float time = 11; // duration of previous GL call (ms)
- enum Prop
- {
- CaptureDraw = 0; // arg0 = number of glDrawArrays/Elements to glReadPixels
- TimeMode = 1; // arg0 = SYSTEM_TIME_* in utils/Timers.h
- ExpectResponse = 2; // arg0 = enum Function, arg1 = true/false
- CaptureSwap = 3; // arg0 = number of eglSwapBuffers to glReadPixels
- GLConstant = 4; // arg0 = GLenum, arg1 = constant; send GL impl. constants
- };
- optional Prop prop = 21; // used with SETPROP, value in arg0
- optional float clock = 22; // wall clock in seconds
-}
-""")
-
- output.close()
-
- os.system("aprotoc --cpp_out=src --java_out=../../../../../development/tools/glesv2debugger/src debugger_message.proto")
- os.system('mv -f "src/debugger_message.pb.cc" "src/debugger_message.pb.cpp"')
diff --git a/opengl/libs/GLES2_dbg/gl2_api_annotated.in b/opengl/libs/GLES2_dbg/gl2_api_annotated.in
deleted file mode 100644
index 227e2eb..0000000
--- a/opengl/libs/GLES2_dbg/gl2_api_annotated.in
+++ /dev/null
@@ -1,426 +0,0 @@
-void API_ENTRY(glActiveTexture)(GLenum texture) {
- CALL_GL_API(glActiveTexture, texture);
-}
-void API_ENTRY(glAttachShader)(GLuint program, GLuint shader) {
- CALL_GL_API(glAttachShader, program, shader);
-}
-void API_ENTRY(glBindAttribLocation)(GLuint program, GLuint index, const GLchar:GLstring:in name) {
- CALL_GL_API(glBindAttribLocation, program, index, name);
-}
-void API_ENTRY(glBindBuffer)(GLenum target, GLuint buffer) {
- CALL_GL_API(glBindBuffer, target, buffer);
-}
-void API_ENTRY(glBindFramebuffer)(GLenum target, GLuint framebuffer) {
- CALL_GL_API(glBindFramebuffer, target, framebuffer);
-}
-void API_ENTRY(glBindRenderbuffer)(GLenum target, GLuint renderbuffer) {
- CALL_GL_API(glBindRenderbuffer, target, renderbuffer);
-}
-void API_ENTRY(glBindTexture)(GLenum target, GLuint texture) {
- CALL_GL_API(glBindTexture, target, texture);
-}
-void API_ENTRY(glBlendColor)(GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha) {
- CALL_GL_API(glBlendColor, red, green, blue, alpha);
-}
-void API_ENTRY(glBlendEquation)( GLenum mode ) {
- CALL_GL_API(glBlendEquation, mode);
-}
-void API_ENTRY(glBlendEquationSeparate)(GLenum modeRGB, GLenum modeAlpha) {
- CALL_GL_API(glBlendEquationSeparate, modeRGB, modeAlpha);
-}
-void API_ENTRY(glBlendFunc)(GLenum sfactor, GLenum dfactor) {
- CALL_GL_API(glBlendFunc, sfactor, dfactor);
-}
-void API_ENTRY(glBlendFuncSeparate)(GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha) {
- CALL_GL_API(glBlendFuncSeparate, srcRGB, dstRGB, srcAlpha, dstAlpha);
-}
-void API_ENTRY(glBufferData)(GLenum target, GLsizeiptr size, const GLvoid:size:in data, GLenum usage) {
- CALL_GL_API(glBufferData, target, size, data, usage);
-}
-void API_ENTRY(glBufferSubData)(GLenum target, GLintptr offset, GLsizeiptr size, const GLvoid:size:in data) {
- CALL_GL_API(glBufferSubData, target, offset, size, data);
-}
-GLenum API_ENTRY(glCheckFramebufferStatus)(GLenum target) {
- CALL_GL_API_RETURN(glCheckFramebufferStatus, target);
-}
-void API_ENTRY(glClear)(GLbitfield mask) {
- CALL_GL_API(glClear, mask);
-}
-void API_ENTRY(glClearColor)(GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha) {
- CALL_GL_API(glClearColor, red, green, blue, alpha);
-}
-void API_ENTRY(glClearDepthf)(GLclampf depth) {
- CALL_GL_API(glClearDepthf, depth);
-}
-void API_ENTRY(glClearStencil)(GLint s) {
- CALL_GL_API(glClearStencil, s);
-}
-void API_ENTRY(glColorMask)(GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha) {
- CALL_GL_API(glColorMask, red, green, blue, alpha);
-}
-void API_ENTRY(glCompileShader)(GLuint shader) {
- CALL_GL_API(glCompileShader, shader);
-}
-void API_ENTRY(glCompressedTexImage2D)(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const GLvoid* data) {
- CALL_GL_API(glCompressedTexImage2D, target, level, internalformat, width, height, border, imageSize, data);
-}
-void API_ENTRY(glCompressedTexSubImage2D)(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const GLvoid* data) {
- CALL_GL_API(glCompressedTexSubImage2D, target, level, xoffset, yoffset, width, height, format, imageSize, data);
-}
-void API_ENTRY(glCopyTexImage2D)(GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border) {
- CALL_GL_API(glCopyTexImage2D, target, level, internalformat, x, y, width, height, border);
-}
-void API_ENTRY(glCopyTexSubImage2D)(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height) {
- CALL_GL_API(glCopyTexSubImage2D, target, level, xoffset, yoffset, x, y, width, height);
-}
-GLuint API_ENTRY(glCreateProgram)(void) {
- CALL_GL_API_RETURN(glCreateProgram);
-}
-GLuint API_ENTRY(glCreateShader)(GLenum type) {
- CALL_GL_API_RETURN(glCreateShader, type);
-}
-void API_ENTRY(glCullFace)(GLenum mode) {
- CALL_GL_API(glCullFace, mode);
-}
-void API_ENTRY(glDeleteBuffers)(GLsizei n, const GLuint:n:in buffers) {
- CALL_GL_API(glDeleteBuffers, n, buffers);
-}
-void API_ENTRY(glDeleteFramebuffers)(GLsizei n, const GLuint:n:in framebuffers) {
- CALL_GL_API(glDeleteFramebuffers, n, framebuffers);
-}
-void API_ENTRY(glDeleteProgram)(GLuint program) {
- CALL_GL_API(glDeleteProgram, program);
-}
-void API_ENTRY(glDeleteRenderbuffers)(GLsizei n, const GLuint:n:in renderbuffers) {
- CALL_GL_API(glDeleteRenderbuffers, n, renderbuffers);
-}
-void API_ENTRY(glDeleteShader)(GLuint shader) {
- CALL_GL_API(glDeleteShader, shader);
-}
-void API_ENTRY(glDeleteTextures)(GLsizei n, const GLuint:n:in textures) {
- CALL_GL_API(glDeleteTextures, n, textures);
-}
-void API_ENTRY(glDepthFunc)(GLenum func) {
- CALL_GL_API(glDepthFunc, func);
-}
-void API_ENTRY(glDepthMask)(GLboolean flag) {
- CALL_GL_API(glDepthMask, flag);
-}
-void API_ENTRY(glDepthRangef)(GLclampf zNear, GLclampf zFar) {
- CALL_GL_API(glDepthRangef, zNear, zFar);
-}
-void API_ENTRY(glDetachShader)(GLuint program, GLuint shader) {
- CALL_GL_API(glDetachShader, program, shader);
-}
-void API_ENTRY(glDisable)(GLenum cap) {
- CALL_GL_API(glDisable, cap);
-}
-void API_ENTRY(glDisableVertexAttribArray)(GLuint index) {
- CALL_GL_API(glDisableVertexAttribArray, index);
-}
-void API_ENTRY(glDrawArrays)(GLenum mode, GLint first, GLsizei count) {
- CALL_GL_API(glDrawArrays, mode, first, count);
-}
-void API_ENTRY(glDrawElements)(GLenum mode, GLsizei count, GLenum type, const GLvoid* indices) {
- CALL_GL_API(glDrawElements, mode, count, type, indices);
-}
-void API_ENTRY(glEnable)(GLenum cap) {
- CALL_GL_API(glEnable, cap);
-}
-void API_ENTRY(glEnableVertexAttribArray)(GLuint index) {
- CALL_GL_API(glEnableVertexAttribArray, index);
-}
-void API_ENTRY(glFinish)(void) {
- CALL_GL_API(glFinish);
-}
-void API_ENTRY(glFlush)(void) {
- CALL_GL_API(glFlush);
-}
-void API_ENTRY(glFramebufferRenderbuffer)(GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer) {
- CALL_GL_API(glFramebufferRenderbuffer, target, attachment, renderbuffertarget, renderbuffer);
-}
-void API_ENTRY(glFramebufferTexture2D)(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level) {
- CALL_GL_API(glFramebufferTexture2D, target, attachment, textarget, texture, level);
-}
-void API_ENTRY(glFrontFace)(GLenum mode) {
- CALL_GL_API(glFrontFace, mode);
-}
-void API_ENTRY(glGenBuffers)(GLsizei n, GLuint:n:out buffers) {
- CALL_GL_API(glGenBuffers, n, buffers);
-}
-void API_ENTRY(glGenerateMipmap)(GLenum target) {
- CALL_GL_API(glGenerateMipmap, target);
-}
-void API_ENTRY(glGenFramebuffers)(GLsizei n, GLuint:n:out framebuffers) {
- CALL_GL_API(glGenFramebuffers, n, framebuffers);
-}
-void API_ENTRY(glGenRenderbuffers)(GLsizei n, GLuint:n:out renderbuffers) {
- CALL_GL_API(glGenRenderbuffers, n, renderbuffers);
-}
-void API_ENTRY(glGenTextures)(GLsizei n, GLuint:n:out textures) {
- CALL_GL_API(glGenTextures, n, textures);
-}
-void API_ENTRY(glGetActiveAttrib)(GLuint program, GLuint index, GLsizei bufsize, GLsizei* length, GLint* size, GLenum* type, GLchar:GLstring:in name) {
- CALL_GL_API(glGetActiveAttrib, program, index, bufsize, length, size, type, name);
-}
-void API_ENTRY(glGetActiveUniform)(GLuint program, GLuint index, GLsizei bufsize, GLsizei* length, GLint* size, GLenum* type, GLchar:GLstring:in name) {
- CALL_GL_API(glGetActiveUniform, program, index, bufsize, length, size, type, name);
-}
-void API_ENTRY(glGetAttachedShaders)(GLuint program, GLsizei maxcount, GLsizei* count, GLuint* shaders) {
- CALL_GL_API(glGetAttachedShaders, program, maxcount, count, shaders);
-}
-int API_ENTRY(glGetAttribLocation)(GLuint program, const GLchar:GLstring:in name) {
- CALL_GL_API_RETURN(glGetAttribLocation, program, name);
-}
-void API_ENTRY(glGetBooleanv)(GLenum pname, GLboolean* params) {
- CALL_GL_API(glGetBooleanv, pname, params);
-}
-void API_ENTRY(glGetBufferParameteriv)(GLenum target, GLenum pname, GLint* params) {
- CALL_GL_API(glGetBufferParameteriv, target, pname, params);
-}
-GLenum API_ENTRY(glGetError)(void) {
- CALL_GL_API_RETURN(glGetError);
-}
-void API_ENTRY(glGetFloatv)(GLenum pname, GLfloat* params) {
- CALL_GL_API(glGetFloatv, pname, params);
-}
-void API_ENTRY(glGetFramebufferAttachmentParameteriv)(GLenum target, GLenum attachment, GLenum pname, GLint* params) {
- CALL_GL_API(glGetFramebufferAttachmentParameteriv, target, attachment, pname, params);
-}
-void API_ENTRY(glGetIntegerv)(GLenum pname, GLint* params) {
- CALL_GL_API(glGetIntegerv, pname, params);
-}
-void API_ENTRY(glGetProgramiv)(GLuint program, GLenum pname, GLint:1:out params) {
- CALL_GL_API(glGetProgramiv, program, pname, params);
-}
-void API_ENTRY(glGetProgramInfoLog)(GLuint program, GLsizei bufsize, GLsizei* length, GLchar:GLstring:out infolog) {
- CALL_GL_API(glGetProgramInfoLog, program, bufsize, length, infolog);
-}
-void API_ENTRY(glGetRenderbufferParameteriv)(GLenum target, GLenum pname, GLint* params) {
- CALL_GL_API(glGetRenderbufferParameteriv, target, pname, params);
-}
-void API_ENTRY(glGetShaderiv)(GLuint shader, GLenum pname, GLint:1:out params) {
- CALL_GL_API(glGetShaderiv, shader, pname, params);
-}
-void API_ENTRY(glGetShaderInfoLog)(GLuint shader, GLsizei bufsize, GLsizei* length, GLchar:GLstring:out infolog) {
- CALL_GL_API(glGetShaderInfoLog, shader, bufsize, length, infolog);
-}
-void API_ENTRY(glGetShaderPrecisionFormat)(GLenum shadertype, GLenum precisiontype, GLint* range, GLint* precision) {
- CALL_GL_API(glGetShaderPrecisionFormat, shadertype, precisiontype, range, precision);
-}
-void API_ENTRY(glGetShaderSource)(GLuint shader, GLsizei bufsize, GLsizei* length, GLchar:GLstring:out source) {
- CALL_GL_API(glGetShaderSource, shader, bufsize, length, source);
-}
-const GLubyte* API_ENTRY(glGetString)(GLenum name) {
- CALL_GL_API_RETURN(glGetString, name);
-}
-void API_ENTRY(glGetTexParameterfv)(GLenum target, GLenum pname, GLfloat* params) {
- CALL_GL_API(glGetTexParameterfv, target, pname, params);
-}
-void API_ENTRY(glGetTexParameteriv)(GLenum target, GLenum pname, GLint* params) {
- CALL_GL_API(glGetTexParameteriv, target, pname, params);
-}
-void API_ENTRY(glGetUniformfv)(GLuint program, GLint location, GLfloat* params) {
- CALL_GL_API(glGetUniformfv, program, location, params);
-}
-void API_ENTRY(glGetUniformiv)(GLuint program, GLint location, GLint* params) {
- CALL_GL_API(glGetUniformiv, program, location, params);
-}
-int API_ENTRY(glGetUniformLocation)(GLuint program, const GLchar:GLstring:in name) {
- CALL_GL_API_RETURN(glGetUniformLocation, program, name);
-}
-void API_ENTRY(glGetVertexAttribfv)(GLuint index, GLenum pname, GLfloat* params) {
- CALL_GL_API(glGetVertexAttribfv, index, pname, params);
-}
-void API_ENTRY(glGetVertexAttribiv)(GLuint index, GLenum pname, GLint* params) {
- CALL_GL_API(glGetVertexAttribiv, index, pname, params);
-}
-void API_ENTRY(glGetVertexAttribPointerv)(GLuint index, GLenum pname, GLvoid** pointer) {
- CALL_GL_API(glGetVertexAttribPointerv, index, pname, pointer);
-}
-void API_ENTRY(glHint)(GLenum target, GLenum mode) {
- CALL_GL_API(glHint, target, mode);
-}
-GLboolean API_ENTRY(glIsBuffer)(GLuint buffer) {
- CALL_GL_API_RETURN(glIsBuffer, buffer);
-}
-GLboolean API_ENTRY(glIsEnabled)(GLenum cap) {
- CALL_GL_API_RETURN(glIsEnabled, cap);
-}
-GLboolean API_ENTRY(glIsFramebuffer)(GLuint framebuffer) {
- CALL_GL_API_RETURN(glIsFramebuffer, framebuffer);
-}
-GLboolean API_ENTRY(glIsProgram)(GLuint program) {
- CALL_GL_API_RETURN(glIsProgram, program);
-}
-GLboolean API_ENTRY(glIsRenderbuffer)(GLuint renderbuffer) {
- CALL_GL_API_RETURN(glIsRenderbuffer, renderbuffer);
-}
-GLboolean API_ENTRY(glIsShader)(GLuint shader) {
- CALL_GL_API_RETURN(glIsShader, shader);
-}
-GLboolean API_ENTRY(glIsTexture)(GLuint texture) {
- CALL_GL_API_RETURN(glIsTexture, texture);
-}
-void API_ENTRY(glLineWidth)(GLfloat width) {
- CALL_GL_API(glLineWidth, width);
-}
-void API_ENTRY(glLinkProgram)(GLuint program) {
- CALL_GL_API(glLinkProgram, program);
-}
-void API_ENTRY(glPixelStorei)(GLenum pname, GLint param) {
- CALL_GL_API(glPixelStorei, pname, param);
-}
-void API_ENTRY(glPolygonOffset)(GLfloat factor, GLfloat units) {
- CALL_GL_API(glPolygonOffset, factor, units);
-}
-void API_ENTRY(glReadPixels)(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLvoid* pixels) {
- CALL_GL_API(glReadPixels, x, y, width, height, format, type, pixels);
-}
-void API_ENTRY(glReleaseShaderCompiler)(void) {
- CALL_GL_API(glReleaseShaderCompiler);
-}
-void API_ENTRY(glRenderbufferStorage)(GLenum target, GLenum internalformat, GLsizei width, GLsizei height) {
- CALL_GL_API(glRenderbufferStorage, target, internalformat, width, height);
-}
-void API_ENTRY(glSampleCoverage)(GLclampf value, GLboolean invert) {
- CALL_GL_API(glSampleCoverage, value, invert);
-}
-void API_ENTRY(glScissor)(GLint x, GLint y, GLsizei width, GLsizei height) {
- CALL_GL_API(glScissor, x, y, width, height);
-}
-void API_ENTRY(glShaderBinary)(GLsizei n, const GLuint* shaders, GLenum binaryformat, const GLvoid* binary, GLsizei length) {
- CALL_GL_API(glShaderBinary, n, shaders, binaryformat, binary, length);
-}
-void API_ENTRY(glShaderSource)(GLuint shader, GLsizei count, const GLchar** string, const GLint* length) {
- CALL_GL_API(glShaderSource, shader, count, string, length);
-}
-void API_ENTRY(glStencilFunc)(GLenum func, GLint ref, GLuint mask) {
- CALL_GL_API(glStencilFunc, func, ref, mask);
-}
-void API_ENTRY(glStencilFuncSeparate)(GLenum face, GLenum func, GLint ref, GLuint mask) {
- CALL_GL_API(glStencilFuncSeparate, face, func, ref, mask);
-}
-void API_ENTRY(glStencilMask)(GLuint mask) {
- CALL_GL_API(glStencilMask, mask);
-}
-void API_ENTRY(glStencilMaskSeparate)(GLenum face, GLuint mask) {
- CALL_GL_API(glStencilMaskSeparate, face, mask);
-}
-void API_ENTRY(glStencilOp)(GLenum fail, GLenum zfail, GLenum zpass) {
- CALL_GL_API(glStencilOp, fail, zfail, zpass);
-}
-void API_ENTRY(glStencilOpSeparate)(GLenum face, GLenum fail, GLenum zfail, GLenum zpass) {
- CALL_GL_API(glStencilOpSeparate, face, fail, zfail, zpass);
-}
-void API_ENTRY(glTexImage2D)(GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const GLvoid* pixels) {
- CALL_GL_API(glTexImage2D, target, level, internalformat, width, height, border, format, type, pixels);
-}
-void API_ENTRY(glTexParameterf)(GLenum target, GLenum pname, GLfloat param) {
- CALL_GL_API(glTexParameterf, target, pname, param);
-}
-void API_ENTRY(glTexParameterfv)(GLenum target, GLenum pname, const GLfloat* params) {
- CALL_GL_API(glTexParameterfv, target, pname, params);
-}
-void API_ENTRY(glTexParameteri)(GLenum target, GLenum pname, GLint param) {
- CALL_GL_API(glTexParameteri, target, pname, param);
-}
-void API_ENTRY(glTexParameteriv)(GLenum target, GLenum pname, const GLint* params) {
- CALL_GL_API(glTexParameteriv, target, pname, params);
-}
-void API_ENTRY(glTexSubImage2D)(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid* pixels) {
- CALL_GL_API(glTexSubImage2D, target, level, xoffset, yoffset, width, height, format, type, pixels);
-}
-void API_ENTRY(glUniform1f)(GLint location, GLfloat x) {
- CALL_GL_API(glUniform1f, location, x);
-}
-void API_ENTRY(glUniform1fv)(GLint location, GLsizei count, const GLfloat:1*count:in v) {
- CALL_GL_API(glUniform1fv, location, count, v);
-}
-void API_ENTRY(glUniform1i)(GLint location, GLint x) {
- CALL_GL_API(glUniform1i, location, x);
-}
-void API_ENTRY(glUniform1iv)(GLint location, GLsizei count, const GLint:1*count:in v) {
- CALL_GL_API(glUniform1iv, location, count, v);
-}
-void API_ENTRY(glUniform2f)(GLint location, GLfloat x, GLfloat y) {
- CALL_GL_API(glUniform2f, location, x, y);
-}
-void API_ENTRY(glUniform2fv)(GLint location, GLsizei count, const GLfloat:2*count:in v) {
- CALL_GL_API(glUniform2fv, location, count, v);
-}
-void API_ENTRY(glUniform2i)(GLint location, GLint x, GLint y) {
- CALL_GL_API(glUniform2i, location, x, y);
-}
-void API_ENTRY(glUniform2iv)(GLint location, GLsizei count, const GLint:2*count:in v) {
- CALL_GL_API(glUniform2iv, location, count, v);
-}
-void API_ENTRY(glUniform3f)(GLint location, GLfloat x, GLfloat y, GLfloat z) {
- CALL_GL_API(glUniform3f, location, x, y, z);
-}
-void API_ENTRY(glUniform3fv)(GLint location, GLsizei count, const GLfloat:3*count:in v) {
- CALL_GL_API(glUniform3fv, location, count, v);
-}
-void API_ENTRY(glUniform3i)(GLint location, GLint x, GLint y, GLint z) {
- CALL_GL_API(glUniform3i, location, x, y, z);
-}
-void API_ENTRY(glUniform3iv)(GLint location, GLsizei count, const GLint:3*count:in v) {
- CALL_GL_API(glUniform3iv, location, count, v);
-}
-void API_ENTRY(glUniform4f)(GLint location, GLfloat x, GLfloat y, GLfloat z, GLfloat w) {
- CALL_GL_API(glUniform4f, location, x, y, z, w);
-}
-void API_ENTRY(glUniform4fv)(GLint location, GLsizei count, const GLfloat:4*count:in v) {
- CALL_GL_API(glUniform4fv, location, count, v);
-}
-void API_ENTRY(glUniform4i)(GLint location, GLint x, GLint y, GLint z, GLint w) {
- CALL_GL_API(glUniform4i, location, x, y, z, w);
-}
-void API_ENTRY(glUniform4iv)(GLint location, GLsizei count, const GLint:4*count:in v) {
- CALL_GL_API(glUniform4iv, location, count, v);
-}
-void API_ENTRY(glUniformMatrix2fv)(GLint location, GLsizei count, GLboolean transpose, const GLfloat:4*count:in value) {
- CALL_GL_API(glUniformMatrix2fv, location, count, transpose, value);
-}
-void API_ENTRY(glUniformMatrix3fv)(GLint location, GLsizei count, GLboolean transpose, const GLfloat:9*count:in value) {
- CALL_GL_API(glUniformMatrix3fv, location, count, transpose, value);
-}
-void API_ENTRY(glUniformMatrix4fv)(GLint location, GLsizei count, GLboolean transpose, const GLfloat:16*count:in value) {
- CALL_GL_API(glUniformMatrix4fv, location, count, transpose, value);
-}
-void API_ENTRY(glUseProgram)(GLuint program) {
- CALL_GL_API(glUseProgram, program);
-}
-void API_ENTRY(glValidateProgram)(GLuint program) {
- CALL_GL_API(glValidateProgram, program);
-}
-void API_ENTRY(glVertexAttrib1f)(GLuint indx, GLfloat x) {
- CALL_GL_API(glVertexAttrib1f, indx, x);
-}
-void API_ENTRY(glVertexAttrib1fv)(GLuint indx, const GLfloat:1:in values) {
- CALL_GL_API(glVertexAttrib1fv, indx, values);
-}
-void API_ENTRY(glVertexAttrib2f)(GLuint indx, GLfloat x, GLfloat y) {
- CALL_GL_API(glVertexAttrib2f, indx, x, y);
-}
-void API_ENTRY(glVertexAttrib2fv)(GLuint indx, const GLfloat:2:in values) {
- CALL_GL_API(glVertexAttrib2fv, indx, values);
-}
-void API_ENTRY(glVertexAttrib3f)(GLuint indx, GLfloat x, GLfloat y, GLfloat z) {
- CALL_GL_API(glVertexAttrib3f, indx, x, y, z);
-}
-void API_ENTRY(glVertexAttrib3fv)(GLuint indx, const GLfloat:3:in values) {
- CALL_GL_API(glVertexAttrib3fv, indx, values);
-}
-void API_ENTRY(glVertexAttrib4f)(GLuint indx, GLfloat x, GLfloat y, GLfloat z, GLfloat w) {
- CALL_GL_API(glVertexAttrib4f, indx, x, y, z, w);
-}
-void API_ENTRY(glVertexAttrib4fv)(GLuint indx, const GLfloat:4:in values) {
- CALL_GL_API(glVertexAttrib4fv, indx, values);
-}
-void API_ENTRY(glVertexAttribPointer)(GLuint indx, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const GLvoid* ptr) {
- CALL_GL_API(glVertexAttribPointer, indx, size, type, normalized, stride, ptr);
-}
-void API_ENTRY(glViewport)(GLint x, GLint y, GLsizei width, GLsizei height) {
- CALL_GL_API(glViewport, x, y, width, height);
-}
diff --git a/opengl/libs/GLES2_dbg/src/api.cpp b/opengl/libs/GLES2_dbg/src/api.cpp
deleted file mode 100644
index c483547..0000000
--- a/opengl/libs/GLES2_dbg/src/api.cpp
+++ /dev/null
@@ -1,3540 +0,0 @@
-/*
- ** Copyright 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.
- ** 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.
- */
-
-// auto generated by generate_api_cpp.py
-
-#include <utils/Debug.h>
-
-#include "src/header.h"
-#include "src/api.h"
-
-template<typename T> static int ToInt(const T & t)
-{
- COMPILE_TIME_ASSERT_FUNCTION_SCOPE(sizeof(T) == sizeof(int));
- return (int &)t;
-}
-
-void Debug_glActiveTexture(GLenum texture)
-{
- glesv2debugger::Message msg;
- struct : public FunctionCall {
- GLenum texture;
-
- const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
- _c->glActiveTexture(texture);
- return 0;
- }
- } caller;
- caller.texture = texture;
-
- msg.set_arg0(texture);
-
- int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glActiveTexture);
-}
-
-void Debug_glAttachShader(GLuint program, GLuint shader)
-{
- glesv2debugger::Message msg;
- struct : public FunctionCall {
- GLuint program;
- GLuint shader;
-
- const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
- _c->glAttachShader(program, shader);
- return 0;
- }
- } caller;
- caller.program = program;
- caller.shader = shader;
-
- msg.set_arg0(program);
- msg.set_arg1(shader);
-
- int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glAttachShader);
-}
-
-void Debug_glBindAttribLocation(GLuint program, GLuint index, const GLchar* name)
-{
- glesv2debugger::Message msg;
- struct : public FunctionCall {
- GLuint program;
- GLuint index;
- const GLchar* name;
-
- const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
- _c->glBindAttribLocation(program, index, name);
- return 0;
- }
- } caller;
- caller.program = program;
- caller.index = index;
- caller.name = name;
-
- msg.set_arg0(program);
- msg.set_arg1(index);
- msg.set_arg2(ToInt(name));
-
- // FIXME: check for pointer usage
- msg.mutable_data()->assign(reinterpret_cast<const char *>(name), strlen(name) * sizeof(GLchar));
- int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glBindAttribLocation);
-}
-
-void Debug_glBindBuffer(GLenum target, GLuint buffer)
-{
- glesv2debugger::Message msg;
- struct : public FunctionCall {
- GLenum target;
- GLuint buffer;
-
- const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
- _c->glBindBuffer(target, buffer);
- getDbgContextThreadSpecific()->glBindBuffer(target, buffer);
- return 0;
- }
- } caller;
- caller.target = target;
- caller.buffer = buffer;
-
- msg.set_arg0(target);
- msg.set_arg1(buffer);
-
- int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glBindBuffer);
-}
-
-void Debug_glBindFramebuffer(GLenum target, GLuint framebuffer)
-{
- glesv2debugger::Message msg;
- struct : public FunctionCall {
- GLenum target;
- GLuint framebuffer;
-
- const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
- _c->glBindFramebuffer(target, framebuffer);
- return 0;
- }
- } caller;
- caller.target = target;
- caller.framebuffer = framebuffer;
-
- msg.set_arg0(target);
- msg.set_arg1(framebuffer);
-
- int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glBindFramebuffer);
-}
-
-void Debug_glBindRenderbuffer(GLenum target, GLuint renderbuffer)
-{
- glesv2debugger::Message msg;
- struct : public FunctionCall {
- GLenum target;
- GLuint renderbuffer;
-
- const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
- _c->glBindRenderbuffer(target, renderbuffer);
- return 0;
- }
- } caller;
- caller.target = target;
- caller.renderbuffer = renderbuffer;
-
- msg.set_arg0(target);
- msg.set_arg1(renderbuffer);
-
- int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glBindRenderbuffer);
-}
-
-void Debug_glBindTexture(GLenum target, GLuint texture)
-{
- glesv2debugger::Message msg;
- struct : public FunctionCall {
- GLenum target;
- GLuint texture;
-
- const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
- _c->glBindTexture(target, texture);
- return 0;
- }
- } caller;
- caller.target = target;
- caller.texture = texture;
-
- msg.set_arg0(target);
- msg.set_arg1(texture);
-
- int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glBindTexture);
-}
-
-void Debug_glBlendColor(GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha)
-{
- glesv2debugger::Message msg;
- struct : public FunctionCall {
- GLclampf red;
- GLclampf green;
- GLclampf blue;
- GLclampf alpha;
-
- const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
- _c->glBlendColor(red, green, blue, alpha);
- return 0;
- }
- } caller;
- caller.red = red;
- caller.green = green;
- caller.blue = blue;
- caller.alpha = alpha;
-
- msg.set_arg0(ToInt(red));
- msg.set_arg1(ToInt(green));
- msg.set_arg2(ToInt(blue));
- msg.set_arg3(ToInt(alpha));
-
- int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glBlendColor);
-}
-
-void Debug_glBlendEquation( GLenum mode )
-{
- glesv2debugger::Message msg;
- struct : public FunctionCall {
- GLenum mode;
-
- const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
- _c->glBlendEquation(mode);
- return 0;
- }
- } caller;
- caller.mode = mode;
-
- msg.set_arg0(mode);
-
- int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glBlendEquation);
-}
-
-void Debug_glBlendEquationSeparate(GLenum modeRGB, GLenum modeAlpha)
-{
- glesv2debugger::Message msg;
- struct : public FunctionCall {
- GLenum modeRGB;
- GLenum modeAlpha;
-
- const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
- _c->glBlendEquationSeparate(modeRGB, modeAlpha);
- return 0;
- }
- } caller;
- caller.modeRGB = modeRGB;
- caller.modeAlpha = modeAlpha;
-
- msg.set_arg0(modeRGB);
- msg.set_arg1(modeAlpha);
-
- int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glBlendEquationSeparate);
-}
-
-void Debug_glBlendFunc(GLenum sfactor, GLenum dfactor)
-{
- glesv2debugger::Message msg;
- struct : public FunctionCall {
- GLenum sfactor;
- GLenum dfactor;
-
- const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
- _c->glBlendFunc(sfactor, dfactor);
- return 0;
- }
- } caller;
- caller.sfactor = sfactor;
- caller.dfactor = dfactor;
-
- msg.set_arg0(sfactor);
- msg.set_arg1(dfactor);
-
- int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glBlendFunc);
-}
-
-void Debug_glBlendFuncSeparate(GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha)
-{
- glesv2debugger::Message msg;
- struct : public FunctionCall {
- GLenum srcRGB;
- GLenum dstRGB;
- GLenum srcAlpha;
- GLenum dstAlpha;
-
- const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
- _c->glBlendFuncSeparate(srcRGB, dstRGB, srcAlpha, dstAlpha);
- return 0;
- }
- } caller;
- caller.srcRGB = srcRGB;
- caller.dstRGB = dstRGB;
- caller.srcAlpha = srcAlpha;
- caller.dstAlpha = dstAlpha;
-
- msg.set_arg0(srcRGB);
- msg.set_arg1(dstRGB);
- msg.set_arg2(srcAlpha);
- msg.set_arg3(dstAlpha);
-
- int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glBlendFuncSeparate);
-}
-
-void Debug_glBufferData(GLenum target, GLsizeiptr size, const GLvoid* data, GLenum usage)
-{
- glesv2debugger::Message msg;
- struct : public FunctionCall {
- GLenum target;
- GLsizeiptr size;
- const GLvoid* data;
- GLenum usage;
-
- const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
- _c->glBufferData(target, size, data, usage);
- getDbgContextThreadSpecific()->glBufferData(target, size, data, usage);
- return 0;
- }
- } caller;
- caller.target = target;
- caller.size = size;
- caller.data = data;
- caller.usage = usage;
-
- msg.set_arg0(target);
- msg.set_arg1(size);
- msg.set_arg2(ToInt(data));
- msg.set_arg3(usage);
-
- // FIXME: check for pointer usage
- msg.mutable_data()->assign(reinterpret_cast<const char *>(data), size * sizeof(char));
- int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glBufferData);
-}
-
-void Debug_glBufferSubData(GLenum target, GLintptr offset, GLsizeiptr size, const GLvoid* data)
-{
- glesv2debugger::Message msg;
- struct : public FunctionCall {
- GLenum target;
- GLintptr offset;
- GLsizeiptr size;
- const GLvoid* data;
-
- const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
- _c->glBufferSubData(target, offset, size, data);
- getDbgContextThreadSpecific()->glBufferSubData(target, offset, size, data);
- return 0;
- }
- } caller;
- caller.target = target;
- caller.offset = offset;
- caller.size = size;
- caller.data = data;
-
- msg.set_arg0(target);
- msg.set_arg1(offset);
- msg.set_arg2(size);
- msg.set_arg3(ToInt(data));
-
- // FIXME: check for pointer usage
- msg.mutable_data()->assign(reinterpret_cast<const char *>(data), size * sizeof(char));
- int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glBufferSubData);
-}
-
-GLenum Debug_glCheckFramebufferStatus(GLenum target)
-{
- glesv2debugger::Message msg;
- struct : public FunctionCall {
- GLenum target;
-
- const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
- const int * ret = reinterpret_cast<const int *>(_c->glCheckFramebufferStatus(target));
- msg.set_ret(ToInt(ret));
- return ret;
- }
- } caller;
- caller.target = target;
-
- msg.set_arg0(target);
-
- int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glCheckFramebufferStatus);
- return reinterpret_cast<GLenum>(ret);
-}
-
-void Debug_glClear(GLbitfield mask)
-{
- glesv2debugger::Message msg;
- struct : public FunctionCall {
- GLbitfield mask;
-
- const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
- _c->glClear(mask);
- return 0;
- }
- } caller;
- caller.mask = mask;
-
- msg.set_arg0(mask);
-
- int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glClear);
-}
-
-void Debug_glClearColor(GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha)
-{
- glesv2debugger::Message msg;
- struct : public FunctionCall {
- GLclampf red;
- GLclampf green;
- GLclampf blue;
- GLclampf alpha;
-
- const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
- _c->glClearColor(red, green, blue, alpha);
- return 0;
- }
- } caller;
- caller.red = red;
- caller.green = green;
- caller.blue = blue;
- caller.alpha = alpha;
-
- msg.set_arg0(ToInt(red));
- msg.set_arg1(ToInt(green));
- msg.set_arg2(ToInt(blue));
- msg.set_arg3(ToInt(alpha));
-
- int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glClearColor);
-}
-
-void Debug_glClearDepthf(GLclampf depth)
-{
- glesv2debugger::Message msg;
- struct : public FunctionCall {
- GLclampf depth;
-
- const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
- _c->glClearDepthf(depth);
- return 0;
- }
- } caller;
- caller.depth = depth;
-
- msg.set_arg0(ToInt(depth));
-
- int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glClearDepthf);
-}
-
-void Debug_glClearStencil(GLint s)
-{
- glesv2debugger::Message msg;
- struct : public FunctionCall {
- GLint s;
-
- const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
- _c->glClearStencil(s);
- return 0;
- }
- } caller;
- caller.s = s;
-
- msg.set_arg0(s);
-
- int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glClearStencil);
-}
-
-void Debug_glColorMask(GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha)
-{
- glesv2debugger::Message msg;
- struct : public FunctionCall {
- GLboolean red;
- GLboolean green;
- GLboolean blue;
- GLboolean alpha;
-
- const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
- _c->glColorMask(red, green, blue, alpha);
- return 0;
- }
- } caller;
- caller.red = red;
- caller.green = green;
- caller.blue = blue;
- caller.alpha = alpha;
-
- msg.set_arg0(red);
- msg.set_arg1(green);
- msg.set_arg2(blue);
- msg.set_arg3(alpha);
-
- int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glColorMask);
-}
-
-void Debug_glCompileShader(GLuint shader)
-{
- glesv2debugger::Message msg;
- struct : public FunctionCall {
- GLuint shader;
-
- const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
- _c->glCompileShader(shader);
- return 0;
- }
- } caller;
- caller.shader = shader;
-
- msg.set_arg0(shader);
-
- int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glCompileShader);
-}
-
-// FIXME: this function has pointers, it should be hand written
-void Debug_glCompressedTexImage2D(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const GLvoid* data)
-{
- glesv2debugger::Message msg;
- struct : public FunctionCall {
- GLenum target;
- GLint level;
- GLenum internalformat;
- GLsizei width;
- GLsizei height;
- GLint border;
- GLsizei imageSize;
- const GLvoid* data;
-
- const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
- _c->glCompressedTexImage2D(target, level, internalformat, width, height, border, imageSize, data);
- return 0;
- }
- } caller;
- caller.target = target;
- caller.level = level;
- caller.internalformat = internalformat;
- caller.width = width;
- caller.height = height;
- caller.border = border;
- caller.imageSize = imageSize;
- caller.data = data;
-
- msg.set_arg0(target);
- msg.set_arg1(level);
- msg.set_arg2(internalformat);
- msg.set_arg3(width);
- msg.set_arg4(height);
- msg.set_arg5(border);
- msg.set_arg6(imageSize);
- msg.set_arg7(ToInt(data));
-
- // FIXME: check for pointer usage
- int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glCompressedTexImage2D);
-}
-
-// FIXME: this function has pointers, it should be hand written
-void Debug_glCompressedTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const GLvoid* data)
-{
- glesv2debugger::Message msg;
- struct : public FunctionCall {
- GLenum target;
- GLint level;
- GLint xoffset;
- GLint yoffset;
- GLsizei width;
- GLsizei height;
- GLenum format;
- GLsizei imageSize;
- const GLvoid* data;
-
- const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
- _c->glCompressedTexSubImage2D(target, level, xoffset, yoffset, width, height, format, imageSize, data);
- return 0;
- }
- } caller;
- caller.target = target;
- caller.level = level;
- caller.xoffset = xoffset;
- caller.yoffset = yoffset;
- caller.width = width;
- caller.height = height;
- caller.format = format;
- caller.imageSize = imageSize;
- caller.data = data;
-
- msg.set_arg0(target);
- msg.set_arg1(level);
- msg.set_arg2(xoffset);
- msg.set_arg3(yoffset);
- msg.set_arg4(width);
- msg.set_arg5(height);
- msg.set_arg6(format);
- msg.set_arg7(imageSize);
- msg.set_arg8(ToInt(data));
-
- // FIXME: check for pointer usage
- int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glCompressedTexSubImage2D);
-}
-
-void Debug_glCopyTexImage2D(GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border)
-{
- glesv2debugger::Message msg;
- struct : public FunctionCall {
- GLenum target;
- GLint level;
- GLenum internalformat;
- GLint x;
- GLint y;
- GLsizei width;
- GLsizei height;
- GLint border;
-
- const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
- _c->glCopyTexImage2D(target, level, internalformat, x, y, width, height, border);
-#ifdef EXTEND_AFTER_CALL_Debug_glCopyTexImage2D
- EXTEND_AFTER_CALL_Debug_glCopyTexImage2D;
-#endif
- return 0;
- }
- } caller;
- caller.target = target;
- caller.level = level;
- caller.internalformat = internalformat;
- caller.x = x;
- caller.y = y;
- caller.width = width;
- caller.height = height;
- caller.border = border;
-
- msg.set_arg0(target);
- msg.set_arg1(level);
- msg.set_arg2(internalformat);
- msg.set_arg3(x);
- msg.set_arg4(y);
- msg.set_arg5(width);
- msg.set_arg6(height);
- msg.set_arg7(border);
-
-#ifdef EXTEND_Debug_glCopyTexImage2D
- EXTEND_Debug_glCopyTexImage2D;
-#endif
- int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glCopyTexImage2D);
-}
-
-void Debug_glCopyTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height)
-{
- glesv2debugger::Message msg;
- struct : public FunctionCall {
- GLenum target;
- GLint level;
- GLint xoffset;
- GLint yoffset;
- GLint x;
- GLint y;
- GLsizei width;
- GLsizei height;
-
- const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
- _c->glCopyTexSubImage2D(target, level, xoffset, yoffset, x, y, width, height);
-#ifdef EXTEND_AFTER_CALL_Debug_glCopyTexSubImage2D
- EXTEND_AFTER_CALL_Debug_glCopyTexSubImage2D;
-#endif
- return 0;
- }
- } caller;
- caller.target = target;
- caller.level = level;
- caller.xoffset = xoffset;
- caller.yoffset = yoffset;
- caller.x = x;
- caller.y = y;
- caller.width = width;
- caller.height = height;
-
- msg.set_arg0(target);
- msg.set_arg1(level);
- msg.set_arg2(xoffset);
- msg.set_arg3(yoffset);
- msg.set_arg4(x);
- msg.set_arg5(y);
- msg.set_arg6(width);
- msg.set_arg7(height);
-
-#ifdef EXTEND_Debug_glCopyTexSubImage2D
- EXTEND_Debug_glCopyTexSubImage2D;
-#endif
- int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glCopyTexSubImage2D);
-}
-
-GLuint Debug_glCreateProgram(void)
-{
- glesv2debugger::Message msg;
- struct : public FunctionCall {
-
- const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
- const int * ret = reinterpret_cast<const int *>(_c->glCreateProgram());
- msg.set_ret(ToInt(ret));
- return ret;
- }
- } caller;
-
-
- int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glCreateProgram);
- return reinterpret_cast<GLuint>(ret);
-}
-
-GLuint Debug_glCreateShader(GLenum type)
-{
- glesv2debugger::Message msg;
- struct : public FunctionCall {
- GLenum type;
-
- const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
- const int * ret = reinterpret_cast<const int *>(_c->glCreateShader(type));
- msg.set_ret(ToInt(ret));
- return ret;
- }
- } caller;
- caller.type = type;
-
- msg.set_arg0(type);
-
- int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glCreateShader);
- return reinterpret_cast<GLuint>(ret);
-}
-
-void Debug_glCullFace(GLenum mode)
-{
- glesv2debugger::Message msg;
- struct : public FunctionCall {
- GLenum mode;
-
- const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
- _c->glCullFace(mode);
- return 0;
- }
- } caller;
- caller.mode = mode;
-
- msg.set_arg0(mode);
-
- int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glCullFace);
-}
-
-void Debug_glDeleteBuffers(GLsizei n, const GLuint* buffers)
-{
- glesv2debugger::Message msg;
- struct : public FunctionCall {
- GLsizei n;
- const GLuint* buffers;
-
- const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
- _c->glDeleteBuffers(n, buffers);
- getDbgContextThreadSpecific()->glDeleteBuffers(n, buffers);
- return 0;
- }
- } caller;
- caller.n = n;
- caller.buffers = buffers;
-
- msg.set_arg0(n);
- msg.set_arg1(ToInt(buffers));
-
- // FIXME: check for pointer usage
- msg.mutable_data()->assign(reinterpret_cast<const char *>(buffers), n * sizeof(GLuint));
- int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glDeleteBuffers);
-}
-
-void Debug_glDeleteFramebuffers(GLsizei n, const GLuint* framebuffers)
-{
- glesv2debugger::Message msg;
- struct : public FunctionCall {
- GLsizei n;
- const GLuint* framebuffers;
-
- const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
- _c->glDeleteFramebuffers(n, framebuffers);
- return 0;
- }
- } caller;
- caller.n = n;
- caller.framebuffers = framebuffers;
-
- msg.set_arg0(n);
- msg.set_arg1(ToInt(framebuffers));
-
- // FIXME: check for pointer usage
- msg.mutable_data()->assign(reinterpret_cast<const char *>(framebuffers), n * sizeof(GLuint));
- int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glDeleteFramebuffers);
-}
-
-void Debug_glDeleteProgram(GLuint program)
-{
- glesv2debugger::Message msg;
- struct : public FunctionCall {
- GLuint program;
-
- const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
- _c->glDeleteProgram(program);
- return 0;
- }
- } caller;
- caller.program = program;
-
- msg.set_arg0(program);
-
- int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glDeleteProgram);
-}
-
-void Debug_glDeleteRenderbuffers(GLsizei n, const GLuint* renderbuffers)
-{
- glesv2debugger::Message msg;
- struct : public FunctionCall {
- GLsizei n;
- const GLuint* renderbuffers;
-
- const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
- _c->glDeleteRenderbuffers(n, renderbuffers);
- return 0;
- }
- } caller;
- caller.n = n;
- caller.renderbuffers = renderbuffers;
-
- msg.set_arg0(n);
- msg.set_arg1(ToInt(renderbuffers));
-
- // FIXME: check for pointer usage
- msg.mutable_data()->assign(reinterpret_cast<const char *>(renderbuffers), n * sizeof(GLuint));
- int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glDeleteRenderbuffers);
-}
-
-void Debug_glDeleteShader(GLuint shader)
-{
- glesv2debugger::Message msg;
- struct : public FunctionCall {
- GLuint shader;
-
- const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
- _c->glDeleteShader(shader);
- return 0;
- }
- } caller;
- caller.shader = shader;
-
- msg.set_arg0(shader);
-
- int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glDeleteShader);
-}
-
-void Debug_glDeleteTextures(GLsizei n, const GLuint* textures)
-{
- glesv2debugger::Message msg;
- struct : public FunctionCall {
- GLsizei n;
- const GLuint* textures;
-
- const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
- _c->glDeleteTextures(n, textures);
- return 0;
- }
- } caller;
- caller.n = n;
- caller.textures = textures;
-
- msg.set_arg0(n);
- msg.set_arg1(ToInt(textures));
-
- // FIXME: check for pointer usage
- msg.mutable_data()->assign(reinterpret_cast<const char *>(textures), n * sizeof(GLuint));
- int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glDeleteTextures);
-}
-
-void Debug_glDepthFunc(GLenum func)
-{
- glesv2debugger::Message msg;
- struct : public FunctionCall {
- GLenum func;
-
- const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
- _c->glDepthFunc(func);
- return 0;
- }
- } caller;
- caller.func = func;
-
- msg.set_arg0(func);
-
- int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glDepthFunc);
-}
-
-void Debug_glDepthMask(GLboolean flag)
-{
- glesv2debugger::Message msg;
- struct : public FunctionCall {
- GLboolean flag;
-
- const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
- _c->glDepthMask(flag);
- return 0;
- }
- } caller;
- caller.flag = flag;
-
- msg.set_arg0(flag);
-
- int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glDepthMask);
-}
-
-void Debug_glDepthRangef(GLclampf zNear, GLclampf zFar)
-{
- glesv2debugger::Message msg;
- struct : public FunctionCall {
- GLclampf zNear;
- GLclampf zFar;
-
- const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
- _c->glDepthRangef(zNear, zFar);
- return 0;
- }
- } caller;
- caller.zNear = zNear;
- caller.zFar = zFar;
-
- msg.set_arg0(ToInt(zNear));
- msg.set_arg1(ToInt(zFar));
-
- int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glDepthRangef);
-}
-
-void Debug_glDetachShader(GLuint program, GLuint shader)
-{
- glesv2debugger::Message msg;
- struct : public FunctionCall {
- GLuint program;
- GLuint shader;
-
- const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
- _c->glDetachShader(program, shader);
- return 0;
- }
- } caller;
- caller.program = program;
- caller.shader = shader;
-
- msg.set_arg0(program);
- msg.set_arg1(shader);
-
- int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glDetachShader);
-}
-
-void Debug_glDisable(GLenum cap)
-{
- glesv2debugger::Message msg;
- struct : public FunctionCall {
- GLenum cap;
-
- const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
- _c->glDisable(cap);
- return 0;
- }
- } caller;
- caller.cap = cap;
-
- msg.set_arg0(cap);
-
- int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glDisable);
-}
-
-void Debug_glDisableVertexAttribArray(GLuint index)
-{
- glesv2debugger::Message msg;
- struct : public FunctionCall {
- GLuint index;
-
- const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
- _c->glDisableVertexAttribArray(index);
- getDbgContextThreadSpecific()->glDisableVertexAttribArray(index);
- return 0;
- }
- } caller;
- caller.index = index;
-
- msg.set_arg0(index);
-
- int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glDisableVertexAttribArray);
-}
-
-void Debug_glEnable(GLenum cap)
-{
- glesv2debugger::Message msg;
- struct : public FunctionCall {
- GLenum cap;
-
- const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
- _c->glEnable(cap);
- return 0;
- }
- } caller;
- caller.cap = cap;
-
- msg.set_arg0(cap);
-
- int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glEnable);
-}
-
-void Debug_glEnableVertexAttribArray(GLuint index)
-{
- glesv2debugger::Message msg;
- struct : public FunctionCall {
- GLuint index;
-
- const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
- _c->glEnableVertexAttribArray(index);
- getDbgContextThreadSpecific()->glEnableVertexAttribArray(index);
- return 0;
- }
- } caller;
- caller.index = index;
-
- msg.set_arg0(index);
-
- int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glEnableVertexAttribArray);
-}
-
-void Debug_glFinish(void)
-{
- glesv2debugger::Message msg;
- struct : public FunctionCall {
-
- const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
- _c->glFinish();
- return 0;
- }
- } caller;
-
-
- int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glFinish);
-}
-
-void Debug_glFlush(void)
-{
- glesv2debugger::Message msg;
- struct : public FunctionCall {
-
- const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
- _c->glFlush();
- return 0;
- }
- } caller;
-
-
- int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glFlush);
-}
-
-void Debug_glFramebufferRenderbuffer(GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer)
-{
- glesv2debugger::Message msg;
- struct : public FunctionCall {
- GLenum target;
- GLenum attachment;
- GLenum renderbuffertarget;
- GLuint renderbuffer;
-
- const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
- _c->glFramebufferRenderbuffer(target, attachment, renderbuffertarget, renderbuffer);
- return 0;
- }
- } caller;
- caller.target = target;
- caller.attachment = attachment;
- caller.renderbuffertarget = renderbuffertarget;
- caller.renderbuffer = renderbuffer;
-
- msg.set_arg0(target);
- msg.set_arg1(attachment);
- msg.set_arg2(renderbuffertarget);
- msg.set_arg3(renderbuffer);
-
- int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glFramebufferRenderbuffer);
-}
-
-void Debug_glFramebufferTexture2D(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level)
-{
- glesv2debugger::Message msg;
- struct : public FunctionCall {
- GLenum target;
- GLenum attachment;
- GLenum textarget;
- GLuint texture;
- GLint level;
-
- const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
- _c->glFramebufferTexture2D(target, attachment, textarget, texture, level);
- return 0;
- }
- } caller;
- caller.target = target;
- caller.attachment = attachment;
- caller.textarget = textarget;
- caller.texture = texture;
- caller.level = level;
-
- msg.set_arg0(target);
- msg.set_arg1(attachment);
- msg.set_arg2(textarget);
- msg.set_arg3(texture);
- msg.set_arg4(level);
-
- int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glFramebufferTexture2D);
-}
-
-void Debug_glFrontFace(GLenum mode)
-{
- glesv2debugger::Message msg;
- struct : public FunctionCall {
- GLenum mode;
-
- const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
- _c->glFrontFace(mode);
- return 0;
- }
- } caller;
- caller.mode = mode;
-
- msg.set_arg0(mode);
-
- int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glFrontFace);
-}
-
-void Debug_glGenBuffers(GLsizei n, GLuint* buffers)
-{
- glesv2debugger::Message msg;
- struct : public FunctionCall {
- GLsizei n;
- GLuint* buffers;
-
- const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
- nsecs_t c0 = systemTime(timeMode);
- _c->glGenBuffers(n, buffers);
- msg.set_time((systemTime(timeMode) - c0) * 1e-6f);
- msg.mutable_data()->assign(reinterpret_cast<const char *>(buffers), n * sizeof(GLuint));
- return 0;
- }
- } caller;
- caller.n = n;
- caller.buffers = buffers;
-
- msg.set_arg0(n);
- msg.set_arg1(ToInt(buffers));
-
- // FIXME: check for pointer usage
- int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glGenBuffers);
-}
-
-void Debug_glGenerateMipmap(GLenum target)
-{
- glesv2debugger::Message msg;
- struct : public FunctionCall {
- GLenum target;
-
- const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
- _c->glGenerateMipmap(target);
- return 0;
- }
- } caller;
- caller.target = target;
-
- msg.set_arg0(target);
-
- int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glGenerateMipmap);
-}
-
-void Debug_glGenFramebuffers(GLsizei n, GLuint* framebuffers)
-{
- glesv2debugger::Message msg;
- struct : public FunctionCall {
- GLsizei n;
- GLuint* framebuffers;
-
- const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
- nsecs_t c0 = systemTime(timeMode);
- _c->glGenFramebuffers(n, framebuffers);
- msg.set_time((systemTime(timeMode) - c0) * 1e-6f);
- msg.mutable_data()->assign(reinterpret_cast<const char *>(framebuffers), n * sizeof(GLuint));
- return 0;
- }
- } caller;
- caller.n = n;
- caller.framebuffers = framebuffers;
-
- msg.set_arg0(n);
- msg.set_arg1(ToInt(framebuffers));
-
- // FIXME: check for pointer usage
- int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glGenFramebuffers);
-}
-
-void Debug_glGenRenderbuffers(GLsizei n, GLuint* renderbuffers)
-{
- glesv2debugger::Message msg;
- struct : public FunctionCall {
- GLsizei n;
- GLuint* renderbuffers;
-
- const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
- nsecs_t c0 = systemTime(timeMode);
- _c->glGenRenderbuffers(n, renderbuffers);
- msg.set_time((systemTime(timeMode) - c0) * 1e-6f);
- msg.mutable_data()->assign(reinterpret_cast<const char *>(renderbuffers), n * sizeof(GLuint));
- return 0;
- }
- } caller;
- caller.n = n;
- caller.renderbuffers = renderbuffers;
-
- msg.set_arg0(n);
- msg.set_arg1(ToInt(renderbuffers));
-
- // FIXME: check for pointer usage
- int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glGenRenderbuffers);
-}
-
-void Debug_glGenTextures(GLsizei n, GLuint* textures)
-{
- glesv2debugger::Message msg;
- struct : public FunctionCall {
- GLsizei n;
- GLuint* textures;
-
- const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
- nsecs_t c0 = systemTime(timeMode);
- _c->glGenTextures(n, textures);
- msg.set_time((systemTime(timeMode) - c0) * 1e-6f);
- msg.mutable_data()->assign(reinterpret_cast<const char *>(textures), n * sizeof(GLuint));
- return 0;
- }
- } caller;
- caller.n = n;
- caller.textures = textures;
-
- msg.set_arg0(n);
- msg.set_arg1(ToInt(textures));
-
- // FIXME: check for pointer usage
- int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glGenTextures);
-}
-
-// FIXME: this function has pointers, it should be hand written
-void Debug_glGetActiveAttrib(GLuint program, GLuint index, GLsizei bufsize, GLsizei* length, GLint* size, GLenum* type, GLchar* name)
-{
- glesv2debugger::Message msg;
- struct : public FunctionCall {
- GLuint program;
- GLuint index;
- GLsizei bufsize;
- GLsizei* length;
- GLint* size;
- GLenum* type;
- GLchar* name;
-
- const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
- _c->glGetActiveAttrib(program, index, bufsize, length, size, type, name);
- return 0;
- }
- } caller;
- caller.program = program;
- caller.index = index;
- caller.bufsize = bufsize;
- caller.length = length;
- caller.size = size;
- caller.type = type;
- caller.name = name;
-
- msg.set_arg0(program);
- msg.set_arg1(index);
- msg.set_arg2(bufsize);
- msg.set_arg3(ToInt(length));
- msg.set_arg4(ToInt(size));
- msg.set_arg5(ToInt(type));
- msg.set_arg6(ToInt(name));
-
- // FIXME: check for pointer usage
- msg.mutable_data()->assign(reinterpret_cast<const char *>(name), strlen(name) * sizeof(GLchar));
- int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glGetActiveAttrib);
-}
-
-// FIXME: this function has pointers, it should be hand written
-void Debug_glGetActiveUniform(GLuint program, GLuint index, GLsizei bufsize, GLsizei* length, GLint* size, GLenum* type, GLchar* name)
-{
- glesv2debugger::Message msg;
- struct : public FunctionCall {
- GLuint program;
- GLuint index;
- GLsizei bufsize;
- GLsizei* length;
- GLint* size;
- GLenum* type;
- GLchar* name;
-
- const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
- _c->glGetActiveUniform(program, index, bufsize, length, size, type, name);
- return 0;
- }
- } caller;
- caller.program = program;
- caller.index = index;
- caller.bufsize = bufsize;
- caller.length = length;
- caller.size = size;
- caller.type = type;
- caller.name = name;
-
- msg.set_arg0(program);
- msg.set_arg1(index);
- msg.set_arg2(bufsize);
- msg.set_arg3(ToInt(length));
- msg.set_arg4(ToInt(size));
- msg.set_arg5(ToInt(type));
- msg.set_arg6(ToInt(name));
-
- // FIXME: check for pointer usage
- msg.mutable_data()->assign(reinterpret_cast<const char *>(name), strlen(name) * sizeof(GLchar));
- int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glGetActiveUniform);
-}
-
-// FIXME: this function has pointers, it should be hand written
-void Debug_glGetAttachedShaders(GLuint program, GLsizei maxcount, GLsizei* count, GLuint* shaders)
-{
- glesv2debugger::Message msg;
- struct : public FunctionCall {
- GLuint program;
- GLsizei maxcount;
- GLsizei* count;
- GLuint* shaders;
-
- const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
- _c->glGetAttachedShaders(program, maxcount, count, shaders);
- return 0;
- }
- } caller;
- caller.program = program;
- caller.maxcount = maxcount;
- caller.count = count;
- caller.shaders = shaders;
-
- msg.set_arg0(program);
- msg.set_arg1(maxcount);
- msg.set_arg2(ToInt(count));
- msg.set_arg3(ToInt(shaders));
-
- // FIXME: check for pointer usage
- int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glGetAttachedShaders);
-}
-
-int Debug_glGetAttribLocation(GLuint program, const GLchar* name)
-{
- glesv2debugger::Message msg;
- struct : public FunctionCall {
- GLuint program;
- const GLchar* name;
-
- const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
- const int * ret = reinterpret_cast<const int *>(_c->glGetAttribLocation(program, name));
- msg.set_ret(ToInt(ret));
- return ret;
- }
- } caller;
- caller.program = program;
- caller.name = name;
-
- msg.set_arg0(program);
- msg.set_arg1(ToInt(name));
-
- // FIXME: check for pointer usage
- msg.mutable_data()->assign(reinterpret_cast<const char *>(name), strlen(name) * sizeof(GLchar));
- int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glGetAttribLocation);
- return reinterpret_cast<int>(ret);
-}
-
-// FIXME: this function has pointers, it should be hand written
-void Debug_glGetBooleanv(GLenum pname, GLboolean* params)
-{
- glesv2debugger::Message msg;
- struct : public FunctionCall {
- GLenum pname;
- GLboolean* params;
-
- const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
- _c->glGetBooleanv(pname, params);
- return 0;
- }
- } caller;
- caller.pname = pname;
- caller.params = params;
-
- msg.set_arg0(pname);
- msg.set_arg1(ToInt(params));
-
- // FIXME: check for pointer usage
- int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glGetBooleanv);
-}
-
-// FIXME: this function has pointers, it should be hand written
-void Debug_glGetBufferParameteriv(GLenum target, GLenum pname, GLint* params)
-{
- glesv2debugger::Message msg;
- struct : public FunctionCall {
- GLenum target;
- GLenum pname;
- GLint* params;
-
- const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
- _c->glGetBufferParameteriv(target, pname, params);
- return 0;
- }
- } caller;
- caller.target = target;
- caller.pname = pname;
- caller.params = params;
-
- msg.set_arg0(target);
- msg.set_arg1(pname);
- msg.set_arg2(ToInt(params));
-
- // FIXME: check for pointer usage
- int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glGetBufferParameteriv);
-}
-
-GLenum Debug_glGetError(void)
-{
- glesv2debugger::Message msg;
- struct : public FunctionCall {
-
- const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
- const int * ret = reinterpret_cast<const int *>(_c->glGetError());
- msg.set_ret(ToInt(ret));
- return ret;
- }
- } caller;
-
-
- int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glGetError);
- return reinterpret_cast<GLenum>(ret);
-}
-
-// FIXME: this function has pointers, it should be hand written
-void Debug_glGetFloatv(GLenum pname, GLfloat* params)
-{
- glesv2debugger::Message msg;
- struct : public FunctionCall {
- GLenum pname;
- GLfloat* params;
-
- const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
- _c->glGetFloatv(pname, params);
- return 0;
- }
- } caller;
- caller.pname = pname;
- caller.params = params;
-
- msg.set_arg0(pname);
- msg.set_arg1(ToInt(params));
-
- // FIXME: check for pointer usage
- int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glGetFloatv);
-}
-
-// FIXME: this function has pointers, it should be hand written
-void Debug_glGetFramebufferAttachmentParameteriv(GLenum target, GLenum attachment, GLenum pname, GLint* params)
-{
- glesv2debugger::Message msg;
- struct : public FunctionCall {
- GLenum target;
- GLenum attachment;
- GLenum pname;
- GLint* params;
-
- const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
- _c->glGetFramebufferAttachmentParameteriv(target, attachment, pname, params);
- return 0;
- }
- } caller;
- caller.target = target;
- caller.attachment = attachment;
- caller.pname = pname;
- caller.params = params;
-
- msg.set_arg0(target);
- msg.set_arg1(attachment);
- msg.set_arg2(pname);
- msg.set_arg3(ToInt(params));
-
- // FIXME: check for pointer usage
- int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glGetFramebufferAttachmentParameteriv);
-}
-
-// FIXME: this function has pointers, it should be hand written
-void Debug_glGetIntegerv(GLenum pname, GLint* params)
-{
- glesv2debugger::Message msg;
- struct : public FunctionCall {
- GLenum pname;
- GLint* params;
-
- const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
- _c->glGetIntegerv(pname, params);
- return 0;
- }
- } caller;
- caller.pname = pname;
- caller.params = params;
-
- msg.set_arg0(pname);
- msg.set_arg1(ToInt(params));
-
- // FIXME: check for pointer usage
- int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glGetIntegerv);
-}
-
-void Debug_glGetProgramiv(GLuint program, GLenum pname, GLint* params)
-{
- glesv2debugger::Message msg;
- struct : public FunctionCall {
- GLuint program;
- GLenum pname;
- GLint* params;
-
- const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
- nsecs_t c0 = systemTime(timeMode);
- _c->glGetProgramiv(program, pname, params);
- msg.set_time((systemTime(timeMode) - c0) * 1e-6f);
- msg.mutable_data()->assign(reinterpret_cast<const char *>(params), 1 * sizeof(GLint));
- return 0;
- }
- } caller;
- caller.program = program;
- caller.pname = pname;
- caller.params = params;
-
- msg.set_arg0(program);
- msg.set_arg1(pname);
- msg.set_arg2(ToInt(params));
-
- // FIXME: check for pointer usage
- int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glGetProgramiv);
-}
-
-// FIXME: this function has pointers, it should be hand written
-void Debug_glGetProgramInfoLog(GLuint program, GLsizei bufsize, GLsizei* length, GLchar* infolog)
-{
- glesv2debugger::Message msg;
- struct : public FunctionCall {
- GLuint program;
- GLsizei bufsize;
- GLsizei* length;
- GLchar* infolog;
-
- const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
- nsecs_t c0 = systemTime(timeMode);
- _c->glGetProgramInfoLog(program, bufsize, length, infolog);
- msg.set_time((systemTime(timeMode) - c0) * 1e-6f);
- msg.mutable_data()->assign(reinterpret_cast<const char *>(infolog), strlen(infolog) * sizeof(GLchar));
- return 0;
- }
- } caller;
- caller.program = program;
- caller.bufsize = bufsize;
- caller.length = length;
- caller.infolog = infolog;
-
- msg.set_arg0(program);
- msg.set_arg1(bufsize);
- msg.set_arg2(ToInt(length));
- msg.set_arg3(ToInt(infolog));
-
- // FIXME: check for pointer usage
- int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glGetProgramInfoLog);
-}
-
-// FIXME: this function has pointers, it should be hand written
-void Debug_glGetRenderbufferParameteriv(GLenum target, GLenum pname, GLint* params)
-{
- glesv2debugger::Message msg;
- struct : public FunctionCall {
- GLenum target;
- GLenum pname;
- GLint* params;
-
- const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
- _c->glGetRenderbufferParameteriv(target, pname, params);
- return 0;
- }
- } caller;
- caller.target = target;
- caller.pname = pname;
- caller.params = params;
-
- msg.set_arg0(target);
- msg.set_arg1(pname);
- msg.set_arg2(ToInt(params));
-
- // FIXME: check for pointer usage
- int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glGetRenderbufferParameteriv);
-}
-
-void Debug_glGetShaderiv(GLuint shader, GLenum pname, GLint* params)
-{
- glesv2debugger::Message msg;
- struct : public FunctionCall {
- GLuint shader;
- GLenum pname;
- GLint* params;
-
- const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
- nsecs_t c0 = systemTime(timeMode);
- _c->glGetShaderiv(shader, pname, params);
- msg.set_time((systemTime(timeMode) - c0) * 1e-6f);
- msg.mutable_data()->assign(reinterpret_cast<const char *>(params), 1 * sizeof(GLint));
- return 0;
- }
- } caller;
- caller.shader = shader;
- caller.pname = pname;
- caller.params = params;
-
- msg.set_arg0(shader);
- msg.set_arg1(pname);
- msg.set_arg2(ToInt(params));
-
- // FIXME: check for pointer usage
- int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glGetShaderiv);
-}
-
-// FIXME: this function has pointers, it should be hand written
-void Debug_glGetShaderInfoLog(GLuint shader, GLsizei bufsize, GLsizei* length, GLchar* infolog)
-{
- glesv2debugger::Message msg;
- struct : public FunctionCall {
- GLuint shader;
- GLsizei bufsize;
- GLsizei* length;
- GLchar* infolog;
-
- const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
- nsecs_t c0 = systemTime(timeMode);
- _c->glGetShaderInfoLog(shader, bufsize, length, infolog);
- msg.set_time((systemTime(timeMode) - c0) * 1e-6f);
- msg.mutable_data()->assign(reinterpret_cast<const char *>(infolog), strlen(infolog) * sizeof(GLchar));
- return 0;
- }
- } caller;
- caller.shader = shader;
- caller.bufsize = bufsize;
- caller.length = length;
- caller.infolog = infolog;
-
- msg.set_arg0(shader);
- msg.set_arg1(bufsize);
- msg.set_arg2(ToInt(length));
- msg.set_arg3(ToInt(infolog));
-
- // FIXME: check for pointer usage
- int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glGetShaderInfoLog);
-}
-
-// FIXME: this function has pointers, it should be hand written
-void Debug_glGetShaderPrecisionFormat(GLenum shadertype, GLenum precisiontype, GLint* range, GLint* precision)
-{
- glesv2debugger::Message msg;
- struct : public FunctionCall {
- GLenum shadertype;
- GLenum precisiontype;
- GLint* range;
- GLint* precision;
-
- const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
- _c->glGetShaderPrecisionFormat(shadertype, precisiontype, range, precision);
- return 0;
- }
- } caller;
- caller.shadertype = shadertype;
- caller.precisiontype = precisiontype;
- caller.range = range;
- caller.precision = precision;
-
- msg.set_arg0(shadertype);
- msg.set_arg1(precisiontype);
- msg.set_arg2(ToInt(range));
- msg.set_arg3(ToInt(precision));
-
- // FIXME: check for pointer usage
- int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glGetShaderPrecisionFormat);
-}
-
-// FIXME: this function has pointers, it should be hand written
-void Debug_glGetShaderSource(GLuint shader, GLsizei bufsize, GLsizei* length, GLchar* source)
-{
- glesv2debugger::Message msg;
- struct : public FunctionCall {
- GLuint shader;
- GLsizei bufsize;
- GLsizei* length;
- GLchar* source;
-
- const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
- nsecs_t c0 = systemTime(timeMode);
- _c->glGetShaderSource(shader, bufsize, length, source);
- msg.set_time((systemTime(timeMode) - c0) * 1e-6f);
- msg.mutable_data()->assign(reinterpret_cast<const char *>(source), strlen(source) * sizeof(GLchar));
- return 0;
- }
- } caller;
- caller.shader = shader;
- caller.bufsize = bufsize;
- caller.length = length;
- caller.source = source;
-
- msg.set_arg0(shader);
- msg.set_arg1(bufsize);
- msg.set_arg2(ToInt(length));
- msg.set_arg3(ToInt(source));
-
- // FIXME: check for pointer usage
- int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glGetShaderSource);
-}
-
-// FIXME: this function has pointers, it should be hand written
-const GLubyte* Debug_glGetString(GLenum name)
-{
- glesv2debugger::Message msg;
- struct : public FunctionCall {
- GLenum name;
-
- const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
- const int * ret = reinterpret_cast<const int *>(_c->glGetString(name));
- msg.set_ret(ToInt(ret));
- return ret;
- }
- } caller;
- caller.name = name;
-
- msg.set_arg0(name);
-
- // FIXME: check for pointer usage
- int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glGetString);
- return reinterpret_cast<const GLubyte*>(ret);
-}
-
-// FIXME: this function has pointers, it should be hand written
-void Debug_glGetTexParameterfv(GLenum target, GLenum pname, GLfloat* params)
-{
- glesv2debugger::Message msg;
- struct : public FunctionCall {
- GLenum target;
- GLenum pname;
- GLfloat* params;
-
- const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
- _c->glGetTexParameterfv(target, pname, params);
- return 0;
- }
- } caller;
- caller.target = target;
- caller.pname = pname;
- caller.params = params;
-
- msg.set_arg0(target);
- msg.set_arg1(pname);
- msg.set_arg2(ToInt(params));
-
- // FIXME: check for pointer usage
- int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glGetTexParameterfv);
-}
-
-// FIXME: this function has pointers, it should be hand written
-void Debug_glGetTexParameteriv(GLenum target, GLenum pname, GLint* params)
-{
- glesv2debugger::Message msg;
- struct : public FunctionCall {
- GLenum target;
- GLenum pname;
- GLint* params;
-
- const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
- _c->glGetTexParameteriv(target, pname, params);
- return 0;
- }
- } caller;
- caller.target = target;
- caller.pname = pname;
- caller.params = params;
-
- msg.set_arg0(target);
- msg.set_arg1(pname);
- msg.set_arg2(ToInt(params));
-
- // FIXME: check for pointer usage
- int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glGetTexParameteriv);
-}
-
-// FIXME: this function has pointers, it should be hand written
-void Debug_glGetUniformfv(GLuint program, GLint location, GLfloat* params)
-{
- glesv2debugger::Message msg;
- struct : public FunctionCall {
- GLuint program;
- GLint location;
- GLfloat* params;
-
- const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
- _c->glGetUniformfv(program, location, params);
- return 0;
- }
- } caller;
- caller.program = program;
- caller.location = location;
- caller.params = params;
-
- msg.set_arg0(program);
- msg.set_arg1(location);
- msg.set_arg2(ToInt(params));
-
- // FIXME: check for pointer usage
- int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glGetUniformfv);
-}
-
-// FIXME: this function has pointers, it should be hand written
-void Debug_glGetUniformiv(GLuint program, GLint location, GLint* params)
-{
- glesv2debugger::Message msg;
- struct : public FunctionCall {
- GLuint program;
- GLint location;
- GLint* params;
-
- const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
- _c->glGetUniformiv(program, location, params);
- return 0;
- }
- } caller;
- caller.program = program;
- caller.location = location;
- caller.params = params;
-
- msg.set_arg0(program);
- msg.set_arg1(location);
- msg.set_arg2(ToInt(params));
-
- // FIXME: check for pointer usage
- int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glGetUniformiv);
-}
-
-int Debug_glGetUniformLocation(GLuint program, const GLchar* name)
-{
- glesv2debugger::Message msg;
- struct : public FunctionCall {
- GLuint program;
- const GLchar* name;
-
- const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
- const int * ret = reinterpret_cast<const int *>(_c->glGetUniformLocation(program, name));
- msg.set_ret(ToInt(ret));
- return ret;
- }
- } caller;
- caller.program = program;
- caller.name = name;
-
- msg.set_arg0(program);
- msg.set_arg1(ToInt(name));
-
- // FIXME: check for pointer usage
- msg.mutable_data()->assign(reinterpret_cast<const char *>(name), strlen(name) * sizeof(GLchar));
- int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glGetUniformLocation);
- return reinterpret_cast<int>(ret);
-}
-
-// FIXME: this function has pointers, it should be hand written
-void Debug_glGetVertexAttribfv(GLuint index, GLenum pname, GLfloat* params)
-{
- glesv2debugger::Message msg;
- struct : public FunctionCall {
- GLuint index;
- GLenum pname;
- GLfloat* params;
-
- const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
- _c->glGetVertexAttribfv(index, pname, params);
- return 0;
- }
- } caller;
- caller.index = index;
- caller.pname = pname;
- caller.params = params;
-
- msg.set_arg0(index);
- msg.set_arg1(pname);
- msg.set_arg2(ToInt(params));
-
- // FIXME: check for pointer usage
- int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glGetVertexAttribfv);
-}
-
-// FIXME: this function has pointers, it should be hand written
-void Debug_glGetVertexAttribiv(GLuint index, GLenum pname, GLint* params)
-{
- glesv2debugger::Message msg;
- struct : public FunctionCall {
- GLuint index;
- GLenum pname;
- GLint* params;
-
- const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
- _c->glGetVertexAttribiv(index, pname, params);
- return 0;
- }
- } caller;
- caller.index = index;
- caller.pname = pname;
- caller.params = params;
-
- msg.set_arg0(index);
- msg.set_arg1(pname);
- msg.set_arg2(ToInt(params));
-
- // FIXME: check for pointer usage
- int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glGetVertexAttribiv);
-}
-
-// FIXME: this function has pointers, it should be hand written
-void Debug_glGetVertexAttribPointerv(GLuint index, GLenum pname, GLvoid** pointer)
-{
- glesv2debugger::Message msg;
- struct : public FunctionCall {
- GLuint index;
- GLenum pname;
- GLvoid** pointer;
-
- const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
- _c->glGetVertexAttribPointerv(index, pname, pointer);
- return 0;
- }
- } caller;
- caller.index = index;
- caller.pname = pname;
- caller.pointer = pointer;
-
- msg.set_arg0(index);
- msg.set_arg1(pname);
- msg.set_arg2(ToInt(pointer));
-
- // FIXME: check for pointer usage
- int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glGetVertexAttribPointerv);
-}
-
-void Debug_glHint(GLenum target, GLenum mode)
-{
- glesv2debugger::Message msg;
- struct : public FunctionCall {
- GLenum target;
- GLenum mode;
-
- const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
- _c->glHint(target, mode);
- return 0;
- }
- } caller;
- caller.target = target;
- caller.mode = mode;
-
- msg.set_arg0(target);
- msg.set_arg1(mode);
-
- int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glHint);
-}
-
-GLboolean Debug_glIsBuffer(GLuint buffer)
-{
- glesv2debugger::Message msg;
- struct : public FunctionCall {
- GLuint buffer;
-
- const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
- const int * ret = reinterpret_cast<const int *>(_c->glIsBuffer(buffer));
- msg.set_ret(ToInt(ret));
- return ret;
- }
- } caller;
- caller.buffer = buffer;
-
- msg.set_arg0(buffer);
-
- int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glIsBuffer);
- return static_cast<GLboolean>(reinterpret_cast<int>(ret));
-}
-
-GLboolean Debug_glIsEnabled(GLenum cap)
-{
- glesv2debugger::Message msg;
- struct : public FunctionCall {
- GLenum cap;
-
- const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
- const int * ret = reinterpret_cast<const int *>(_c->glIsEnabled(cap));
- msg.set_ret(ToInt(ret));
- return ret;
- }
- } caller;
- caller.cap = cap;
-
- msg.set_arg0(cap);
-
- int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glIsEnabled);
- return static_cast<GLboolean>(reinterpret_cast<int>(ret));
-}
-
-GLboolean Debug_glIsFramebuffer(GLuint framebuffer)
-{
- glesv2debugger::Message msg;
- struct : public FunctionCall {
- GLuint framebuffer;
-
- const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
- const int * ret = reinterpret_cast<const int *>(_c->glIsFramebuffer(framebuffer));
- msg.set_ret(ToInt(ret));
- return ret;
- }
- } caller;
- caller.framebuffer = framebuffer;
-
- msg.set_arg0(framebuffer);
-
- int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glIsFramebuffer);
- return static_cast<GLboolean>(reinterpret_cast<int>(ret));
-}
-
-GLboolean Debug_glIsProgram(GLuint program)
-{
- glesv2debugger::Message msg;
- struct : public FunctionCall {
- GLuint program;
-
- const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
- const int * ret = reinterpret_cast<const int *>(_c->glIsProgram(program));
- msg.set_ret(ToInt(ret));
- return ret;
- }
- } caller;
- caller.program = program;
-
- msg.set_arg0(program);
-
- int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glIsProgram);
- return static_cast<GLboolean>(reinterpret_cast<int>(ret));
-}
-
-GLboolean Debug_glIsRenderbuffer(GLuint renderbuffer)
-{
- glesv2debugger::Message msg;
- struct : public FunctionCall {
- GLuint renderbuffer;
-
- const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
- const int * ret = reinterpret_cast<const int *>(_c->glIsRenderbuffer(renderbuffer));
- msg.set_ret(ToInt(ret));
- return ret;
- }
- } caller;
- caller.renderbuffer = renderbuffer;
-
- msg.set_arg0(renderbuffer);
-
- int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glIsRenderbuffer);
- return static_cast<GLboolean>(reinterpret_cast<int>(ret));
-}
-
-GLboolean Debug_glIsShader(GLuint shader)
-{
- glesv2debugger::Message msg;
- struct : public FunctionCall {
- GLuint shader;
-
- const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
- const int * ret = reinterpret_cast<const int *>(_c->glIsShader(shader));
- msg.set_ret(ToInt(ret));
- return ret;
- }
- } caller;
- caller.shader = shader;
-
- msg.set_arg0(shader);
-
- int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glIsShader);
- return static_cast<GLboolean>(reinterpret_cast<int>(ret));
-}
-
-GLboolean Debug_glIsTexture(GLuint texture)
-{
- glesv2debugger::Message msg;
- struct : public FunctionCall {
- GLuint texture;
-
- const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
- const int * ret = reinterpret_cast<const int *>(_c->glIsTexture(texture));
- msg.set_ret(ToInt(ret));
- return ret;
- }
- } caller;
- caller.texture = texture;
-
- msg.set_arg0(texture);
-
- int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glIsTexture);
- return static_cast<GLboolean>(reinterpret_cast<int>(ret));
-}
-
-void Debug_glLineWidth(GLfloat width)
-{
- glesv2debugger::Message msg;
- struct : public FunctionCall {
- GLfloat width;
-
- const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
- _c->glLineWidth(width);
- return 0;
- }
- } caller;
- caller.width = width;
-
- msg.set_arg0(ToInt(width));
-
- int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glLineWidth);
-}
-
-void Debug_glLinkProgram(GLuint program)
-{
- glesv2debugger::Message msg;
- struct : public FunctionCall {
- GLuint program;
-
- const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
- _c->glLinkProgram(program);
- return 0;
- }
- } caller;
- caller.program = program;
-
- msg.set_arg0(program);
-
- int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glLinkProgram);
-}
-
-void Debug_glPixelStorei(GLenum pname, GLint param)
-{
- glesv2debugger::Message msg;
- struct : public FunctionCall {
- GLenum pname;
- GLint param;
-
- const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
- _c->glPixelStorei(pname, param);
- return 0;
- }
- } caller;
- caller.pname = pname;
- caller.param = param;
-
- msg.set_arg0(pname);
- msg.set_arg1(param);
-
- int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glPixelStorei);
-}
-
-void Debug_glPolygonOffset(GLfloat factor, GLfloat units)
-{
- glesv2debugger::Message msg;
- struct : public FunctionCall {
- GLfloat factor;
- GLfloat units;
-
- const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
- _c->glPolygonOffset(factor, units);
- return 0;
- }
- } caller;
- caller.factor = factor;
- caller.units = units;
-
- msg.set_arg0(ToInt(factor));
- msg.set_arg1(ToInt(units));
-
- int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glPolygonOffset);
-}
-
-void Debug_glReadPixels(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLvoid* pixels)
-{
- glesv2debugger::Message msg;
- struct : public FunctionCall {
- GLint x;
- GLint y;
- GLsizei width;
- GLsizei height;
- GLenum format;
- GLenum type;
- GLvoid* pixels;
-
- const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
- _c->glReadPixels(x, y, width, height, format, type, pixels);
-#ifdef EXTEND_AFTER_CALL_Debug_glReadPixels
- EXTEND_AFTER_CALL_Debug_glReadPixels;
-#endif
- return 0;
- }
- } caller;
- caller.x = x;
- caller.y = y;
- caller.width = width;
- caller.height = height;
- caller.format = format;
- caller.type = type;
- caller.pixels = pixels;
-
- msg.set_arg0(x);
- msg.set_arg1(y);
- msg.set_arg2(width);
- msg.set_arg3(height);
- msg.set_arg4(format);
- msg.set_arg5(type);
- msg.set_arg6(ToInt(pixels));
-
- // FIXME: check for pointer usage
-#ifdef EXTEND_Debug_glReadPixels
- EXTEND_Debug_glReadPixels;
-#endif
- int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glReadPixels);
-}
-
-void Debug_glReleaseShaderCompiler(void)
-{
- glesv2debugger::Message msg;
- struct : public FunctionCall {
-
- const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
- _c->glReleaseShaderCompiler();
- return 0;
- }
- } caller;
-
-
- int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glReleaseShaderCompiler);
-}
-
-void Debug_glRenderbufferStorage(GLenum target, GLenum internalformat, GLsizei width, GLsizei height)
-{
- glesv2debugger::Message msg;
- struct : public FunctionCall {
- GLenum target;
- GLenum internalformat;
- GLsizei width;
- GLsizei height;
-
- const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
- _c->glRenderbufferStorage(target, internalformat, width, height);
- return 0;
- }
- } caller;
- caller.target = target;
- caller.internalformat = internalformat;
- caller.width = width;
- caller.height = height;
-
- msg.set_arg0(target);
- msg.set_arg1(internalformat);
- msg.set_arg2(width);
- msg.set_arg3(height);
-
- int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glRenderbufferStorage);
-}
-
-void Debug_glSampleCoverage(GLclampf value, GLboolean invert)
-{
- glesv2debugger::Message msg;
- struct : public FunctionCall {
- GLclampf value;
- GLboolean invert;
-
- const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
- _c->glSampleCoverage(value, invert);
- return 0;
- }
- } caller;
- caller.value = value;
- caller.invert = invert;
-
- msg.set_arg0(ToInt(value));
- msg.set_arg1(invert);
-
- int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glSampleCoverage);
-}
-
-void Debug_glScissor(GLint x, GLint y, GLsizei width, GLsizei height)
-{
- glesv2debugger::Message msg;
- struct : public FunctionCall {
- GLint x;
- GLint y;
- GLsizei width;
- GLsizei height;
-
- const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
- _c->glScissor(x, y, width, height);
- return 0;
- }
- } caller;
- caller.x = x;
- caller.y = y;
- caller.width = width;
- caller.height = height;
-
- msg.set_arg0(x);
- msg.set_arg1(y);
- msg.set_arg2(width);
- msg.set_arg3(height);
-
- int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glScissor);
-}
-
-// FIXME: this function has pointers, it should be hand written
-void Debug_glShaderBinary(GLsizei n, const GLuint* shaders, GLenum binaryformat, const GLvoid* binary, GLsizei length)
-{
- glesv2debugger::Message msg;
- struct : public FunctionCall {
- GLsizei n;
- const GLuint* shaders;
- GLenum binaryformat;
- const GLvoid* binary;
- GLsizei length;
-
- const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
- _c->glShaderBinary(n, shaders, binaryformat, binary, length);
- return 0;
- }
- } caller;
- caller.n = n;
- caller.shaders = shaders;
- caller.binaryformat = binaryformat;
- caller.binary = binary;
- caller.length = length;
-
- msg.set_arg0(n);
- msg.set_arg1(ToInt(shaders));
- msg.set_arg2(binaryformat);
- msg.set_arg3(ToInt(binary));
- msg.set_arg4(length);
-
- // FIXME: check for pointer usage
- int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glShaderBinary);
-}
-
-void Debug_glShaderSource(GLuint shader, GLsizei count, const GLchar** string, const GLint* length)
-{
- glesv2debugger::Message msg;
- struct : public FunctionCall {
- GLuint shader;
- GLsizei count;
- const GLchar** string;
- const GLint* length;
-
- const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
- _c->glShaderSource(shader, count, string, length);
-#ifdef EXTEND_AFTER_CALL_Debug_glShaderSource
- EXTEND_AFTER_CALL_Debug_glShaderSource;
-#endif
- return 0;
- }
- } caller;
- caller.shader = shader;
- caller.count = count;
- caller.string = string;
- caller.length = length;
-
- msg.set_arg0(shader);
- msg.set_arg1(count);
- msg.set_arg2(ToInt(string));
- msg.set_arg3(ToInt(length));
-
- // FIXME: check for pointer usage
-#ifdef EXTEND_Debug_glShaderSource
- EXTEND_Debug_glShaderSource;
-#endif
- int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glShaderSource);
-}
-
-void Debug_glStencilFunc(GLenum func, GLint ref, GLuint mask)
-{
- glesv2debugger::Message msg;
- struct : public FunctionCall {
- GLenum func;
- GLint ref;
- GLuint mask;
-
- const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
- _c->glStencilFunc(func, ref, mask);
- return 0;
- }
- } caller;
- caller.func = func;
- caller.ref = ref;
- caller.mask = mask;
-
- msg.set_arg0(func);
- msg.set_arg1(ref);
- msg.set_arg2(mask);
-
- int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glStencilFunc);
-}
-
-void Debug_glStencilFuncSeparate(GLenum face, GLenum func, GLint ref, GLuint mask)
-{
- glesv2debugger::Message msg;
- struct : public FunctionCall {
- GLenum face;
- GLenum func;
- GLint ref;
- GLuint mask;
-
- const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
- _c->glStencilFuncSeparate(face, func, ref, mask);
- return 0;
- }
- } caller;
- caller.face = face;
- caller.func = func;
- caller.ref = ref;
- caller.mask = mask;
-
- msg.set_arg0(face);
- msg.set_arg1(func);
- msg.set_arg2(ref);
- msg.set_arg3(mask);
-
- int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glStencilFuncSeparate);
-}
-
-void Debug_glStencilMask(GLuint mask)
-{
- glesv2debugger::Message msg;
- struct : public FunctionCall {
- GLuint mask;
-
- const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
- _c->glStencilMask(mask);
- return 0;
- }
- } caller;
- caller.mask = mask;
-
- msg.set_arg0(mask);
-
- int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glStencilMask);
-}
-
-void Debug_glStencilMaskSeparate(GLenum face, GLuint mask)
-{
- glesv2debugger::Message msg;
- struct : public FunctionCall {
- GLenum face;
- GLuint mask;
-
- const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
- _c->glStencilMaskSeparate(face, mask);
- return 0;
- }
- } caller;
- caller.face = face;
- caller.mask = mask;
-
- msg.set_arg0(face);
- msg.set_arg1(mask);
-
- int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glStencilMaskSeparate);
-}
-
-void Debug_glStencilOp(GLenum fail, GLenum zfail, GLenum zpass)
-{
- glesv2debugger::Message msg;
- struct : public FunctionCall {
- GLenum fail;
- GLenum zfail;
- GLenum zpass;
-
- const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
- _c->glStencilOp(fail, zfail, zpass);
- return 0;
- }
- } caller;
- caller.fail = fail;
- caller.zfail = zfail;
- caller.zpass = zpass;
-
- msg.set_arg0(fail);
- msg.set_arg1(zfail);
- msg.set_arg2(zpass);
-
- int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glStencilOp);
-}
-
-void Debug_glStencilOpSeparate(GLenum face, GLenum fail, GLenum zfail, GLenum zpass)
-{
- glesv2debugger::Message msg;
- struct : public FunctionCall {
- GLenum face;
- GLenum fail;
- GLenum zfail;
- GLenum zpass;
-
- const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
- _c->glStencilOpSeparate(face, fail, zfail, zpass);
- return 0;
- }
- } caller;
- caller.face = face;
- caller.fail = fail;
- caller.zfail = zfail;
- caller.zpass = zpass;
-
- msg.set_arg0(face);
- msg.set_arg1(fail);
- msg.set_arg2(zfail);
- msg.set_arg3(zpass);
-
- int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glStencilOpSeparate);
-}
-
-void Debug_glTexImage2D(GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const GLvoid* pixels)
-{
- glesv2debugger::Message msg;
- struct : public FunctionCall {
- GLenum target;
- GLint level;
- GLint internalformat;
- GLsizei width;
- GLsizei height;
- GLint border;
- GLenum format;
- GLenum type;
- const GLvoid* pixels;
-
- const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
- _c->glTexImage2D(target, level, internalformat, width, height, border, format, type, pixels);
-#ifdef EXTEND_AFTER_CALL_Debug_glTexImage2D
- EXTEND_AFTER_CALL_Debug_glTexImage2D;
-#endif
- return 0;
- }
- } caller;
- caller.target = target;
- caller.level = level;
- caller.internalformat = internalformat;
- caller.width = width;
- caller.height = height;
- caller.border = border;
- caller.format = format;
- caller.type = type;
- caller.pixels = pixels;
-
- msg.set_arg0(target);
- msg.set_arg1(level);
- msg.set_arg2(internalformat);
- msg.set_arg3(width);
- msg.set_arg4(height);
- msg.set_arg5(border);
- msg.set_arg6(format);
- msg.set_arg7(type);
- msg.set_arg8(ToInt(pixels));
-
- // FIXME: check for pointer usage
-#ifdef EXTEND_Debug_glTexImage2D
- EXTEND_Debug_glTexImage2D;
-#endif
- int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glTexImage2D);
-}
-
-void Debug_glTexParameterf(GLenum target, GLenum pname, GLfloat param)
-{
- glesv2debugger::Message msg;
- struct : public FunctionCall {
- GLenum target;
- GLenum pname;
- GLfloat param;
-
- const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
- _c->glTexParameterf(target, pname, param);
- return 0;
- }
- } caller;
- caller.target = target;
- caller.pname = pname;
- caller.param = param;
-
- msg.set_arg0(target);
- msg.set_arg1(pname);
- msg.set_arg2(ToInt(param));
-
- int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glTexParameterf);
-}
-
-// FIXME: this function has pointers, it should be hand written
-void Debug_glTexParameterfv(GLenum target, GLenum pname, const GLfloat* params)
-{
- glesv2debugger::Message msg;
- struct : public FunctionCall {
- GLenum target;
- GLenum pname;
- const GLfloat* params;
-
- const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
- _c->glTexParameterfv(target, pname, params);
- return 0;
- }
- } caller;
- caller.target = target;
- caller.pname = pname;
- caller.params = params;
-
- msg.set_arg0(target);
- msg.set_arg1(pname);
- msg.set_arg2(ToInt(params));
-
- // FIXME: check for pointer usage
- int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glTexParameterfv);
-}
-
-void Debug_glTexParameteri(GLenum target, GLenum pname, GLint param)
-{
- glesv2debugger::Message msg;
- struct : public FunctionCall {
- GLenum target;
- GLenum pname;
- GLint param;
-
- const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
- _c->glTexParameteri(target, pname, param);
- return 0;
- }
- } caller;
- caller.target = target;
- caller.pname = pname;
- caller.param = param;
-
- msg.set_arg0(target);
- msg.set_arg1(pname);
- msg.set_arg2(param);
-
- int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glTexParameteri);
-}
-
-// FIXME: this function has pointers, it should be hand written
-void Debug_glTexParameteriv(GLenum target, GLenum pname, const GLint* params)
-{
- glesv2debugger::Message msg;
- struct : public FunctionCall {
- GLenum target;
- GLenum pname;
- const GLint* params;
-
- const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
- _c->glTexParameteriv(target, pname, params);
- return 0;
- }
- } caller;
- caller.target = target;
- caller.pname = pname;
- caller.params = params;
-
- msg.set_arg0(target);
- msg.set_arg1(pname);
- msg.set_arg2(ToInt(params));
-
- // FIXME: check for pointer usage
- int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glTexParameteriv);
-}
-
-void Debug_glTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid* pixels)
-{
- glesv2debugger::Message msg;
- struct : public FunctionCall {
- GLenum target;
- GLint level;
- GLint xoffset;
- GLint yoffset;
- GLsizei width;
- GLsizei height;
- GLenum format;
- GLenum type;
- const GLvoid* pixels;
-
- const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
- _c->glTexSubImage2D(target, level, xoffset, yoffset, width, height, format, type, pixels);
-#ifdef EXTEND_AFTER_CALL_Debug_glTexSubImage2D
- EXTEND_AFTER_CALL_Debug_glTexSubImage2D;
-#endif
- return 0;
- }
- } caller;
- caller.target = target;
- caller.level = level;
- caller.xoffset = xoffset;
- caller.yoffset = yoffset;
- caller.width = width;
- caller.height = height;
- caller.format = format;
- caller.type = type;
- caller.pixels = pixels;
-
- msg.set_arg0(target);
- msg.set_arg1(level);
- msg.set_arg2(xoffset);
- msg.set_arg3(yoffset);
- msg.set_arg4(width);
- msg.set_arg5(height);
- msg.set_arg6(format);
- msg.set_arg7(type);
- msg.set_arg8(ToInt(pixels));
-
- // FIXME: check for pointer usage
-#ifdef EXTEND_Debug_glTexSubImage2D
- EXTEND_Debug_glTexSubImage2D;
-#endif
- int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glTexSubImage2D);
-}
-
-void Debug_glUniform1f(GLint location, GLfloat x)
-{
- glesv2debugger::Message msg;
- struct : public FunctionCall {
- GLint location;
- GLfloat x;
-
- const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
- _c->glUniform1f(location, x);
- return 0;
- }
- } caller;
- caller.location = location;
- caller.x = x;
-
- msg.set_arg0(location);
- msg.set_arg1(ToInt(x));
-
- int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glUniform1f);
-}
-
-void Debug_glUniform1fv(GLint location, GLsizei count, const GLfloat* v)
-{
- glesv2debugger::Message msg;
- struct : public FunctionCall {
- GLint location;
- GLsizei count;
- const GLfloat* v;
-
- const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
- _c->glUniform1fv(location, count, v);
- return 0;
- }
- } caller;
- caller.location = location;
- caller.count = count;
- caller.v = v;
-
- msg.set_arg0(location);
- msg.set_arg1(count);
- msg.set_arg2(ToInt(v));
-
- // FIXME: check for pointer usage
- msg.mutable_data()->assign(reinterpret_cast<const char *>(v), 1*count * sizeof(GLfloat));
- int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glUniform1fv);
-}
-
-void Debug_glUniform1i(GLint location, GLint x)
-{
- glesv2debugger::Message msg;
- struct : public FunctionCall {
- GLint location;
- GLint x;
-
- const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
- _c->glUniform1i(location, x);
- return 0;
- }
- } caller;
- caller.location = location;
- caller.x = x;
-
- msg.set_arg0(location);
- msg.set_arg1(x);
-
- int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glUniform1i);
-}
-
-void Debug_glUniform1iv(GLint location, GLsizei count, const GLint* v)
-{
- glesv2debugger::Message msg;
- struct : public FunctionCall {
- GLint location;
- GLsizei count;
- const GLint* v;
-
- const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
- _c->glUniform1iv(location, count, v);
- return 0;
- }
- } caller;
- caller.location = location;
- caller.count = count;
- caller.v = v;
-
- msg.set_arg0(location);
- msg.set_arg1(count);
- msg.set_arg2(ToInt(v));
-
- // FIXME: check for pointer usage
- msg.mutable_data()->assign(reinterpret_cast<const char *>(v), 1*count * sizeof(GLint));
- int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glUniform1iv);
-}
-
-void Debug_glUniform2f(GLint location, GLfloat x, GLfloat y)
-{
- glesv2debugger::Message msg;
- struct : public FunctionCall {
- GLint location;
- GLfloat x;
- GLfloat y;
-
- const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
- _c->glUniform2f(location, x, y);
- return 0;
- }
- } caller;
- caller.location = location;
- caller.x = x;
- caller.y = y;
-
- msg.set_arg0(location);
- msg.set_arg1(ToInt(x));
- msg.set_arg2(ToInt(y));
-
- int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glUniform2f);
-}
-
-void Debug_glUniform2fv(GLint location, GLsizei count, const GLfloat* v)
-{
- glesv2debugger::Message msg;
- struct : public FunctionCall {
- GLint location;
- GLsizei count;
- const GLfloat* v;
-
- const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
- _c->glUniform2fv(location, count, v);
- return 0;
- }
- } caller;
- caller.location = location;
- caller.count = count;
- caller.v = v;
-
- msg.set_arg0(location);
- msg.set_arg1(count);
- msg.set_arg2(ToInt(v));
-
- // FIXME: check for pointer usage
- msg.mutable_data()->assign(reinterpret_cast<const char *>(v), 2*count * sizeof(GLfloat));
- int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glUniform2fv);
-}
-
-void Debug_glUniform2i(GLint location, GLint x, GLint y)
-{
- glesv2debugger::Message msg;
- struct : public FunctionCall {
- GLint location;
- GLint x;
- GLint y;
-
- const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
- _c->glUniform2i(location, x, y);
- return 0;
- }
- } caller;
- caller.location = location;
- caller.x = x;
- caller.y = y;
-
- msg.set_arg0(location);
- msg.set_arg1(x);
- msg.set_arg2(y);
-
- int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glUniform2i);
-}
-
-void Debug_glUniform2iv(GLint location, GLsizei count, const GLint* v)
-{
- glesv2debugger::Message msg;
- struct : public FunctionCall {
- GLint location;
- GLsizei count;
- const GLint* v;
-
- const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
- _c->glUniform2iv(location, count, v);
- return 0;
- }
- } caller;
- caller.location = location;
- caller.count = count;
- caller.v = v;
-
- msg.set_arg0(location);
- msg.set_arg1(count);
- msg.set_arg2(ToInt(v));
-
- // FIXME: check for pointer usage
- msg.mutable_data()->assign(reinterpret_cast<const char *>(v), 2*count * sizeof(GLint));
- int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glUniform2iv);
-}
-
-void Debug_glUniform3f(GLint location, GLfloat x, GLfloat y, GLfloat z)
-{
- glesv2debugger::Message msg;
- struct : public FunctionCall {
- GLint location;
- GLfloat x;
- GLfloat y;
- GLfloat z;
-
- const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
- _c->glUniform3f(location, x, y, z);
- return 0;
- }
- } caller;
- caller.location = location;
- caller.x = x;
- caller.y = y;
- caller.z = z;
-
- msg.set_arg0(location);
- msg.set_arg1(ToInt(x));
- msg.set_arg2(ToInt(y));
- msg.set_arg3(ToInt(z));
-
- int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glUniform3f);
-}
-
-void Debug_glUniform3fv(GLint location, GLsizei count, const GLfloat* v)
-{
- glesv2debugger::Message msg;
- struct : public FunctionCall {
- GLint location;
- GLsizei count;
- const GLfloat* v;
-
- const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
- _c->glUniform3fv(location, count, v);
- return 0;
- }
- } caller;
- caller.location = location;
- caller.count = count;
- caller.v = v;
-
- msg.set_arg0(location);
- msg.set_arg1(count);
- msg.set_arg2(ToInt(v));
-
- // FIXME: check for pointer usage
- msg.mutable_data()->assign(reinterpret_cast<const char *>(v), 3*count * sizeof(GLfloat));
- int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glUniform3fv);
-}
-
-void Debug_glUniform3i(GLint location, GLint x, GLint y, GLint z)
-{
- glesv2debugger::Message msg;
- struct : public FunctionCall {
- GLint location;
- GLint x;
- GLint y;
- GLint z;
-
- const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
- _c->glUniform3i(location, x, y, z);
- return 0;
- }
- } caller;
- caller.location = location;
- caller.x = x;
- caller.y = y;
- caller.z = z;
-
- msg.set_arg0(location);
- msg.set_arg1(x);
- msg.set_arg2(y);
- msg.set_arg3(z);
-
- int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glUniform3i);
-}
-
-void Debug_glUniform3iv(GLint location, GLsizei count, const GLint* v)
-{
- glesv2debugger::Message msg;
- struct : public FunctionCall {
- GLint location;
- GLsizei count;
- const GLint* v;
-
- const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
- _c->glUniform3iv(location, count, v);
- return 0;
- }
- } caller;
- caller.location = location;
- caller.count = count;
- caller.v = v;
-
- msg.set_arg0(location);
- msg.set_arg1(count);
- msg.set_arg2(ToInt(v));
-
- // FIXME: check for pointer usage
- msg.mutable_data()->assign(reinterpret_cast<const char *>(v), 3*count * sizeof(GLint));
- int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glUniform3iv);
-}
-
-void Debug_glUniform4f(GLint location, GLfloat x, GLfloat y, GLfloat z, GLfloat w)
-{
- glesv2debugger::Message msg;
- struct : public FunctionCall {
- GLint location;
- GLfloat x;
- GLfloat y;
- GLfloat z;
- GLfloat w;
-
- const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
- _c->glUniform4f(location, x, y, z, w);
- return 0;
- }
- } caller;
- caller.location = location;
- caller.x = x;
- caller.y = y;
- caller.z = z;
- caller.w = w;
-
- msg.set_arg0(location);
- msg.set_arg1(ToInt(x));
- msg.set_arg2(ToInt(y));
- msg.set_arg3(ToInt(z));
- msg.set_arg4(ToInt(w));
-
- int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glUniform4f);
-}
-
-void Debug_glUniform4fv(GLint location, GLsizei count, const GLfloat* v)
-{
- glesv2debugger::Message msg;
- struct : public FunctionCall {
- GLint location;
- GLsizei count;
- const GLfloat* v;
-
- const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
- _c->glUniform4fv(location, count, v);
- return 0;
- }
- } caller;
- caller.location = location;
- caller.count = count;
- caller.v = v;
-
- msg.set_arg0(location);
- msg.set_arg1(count);
- msg.set_arg2(ToInt(v));
-
- // FIXME: check for pointer usage
- msg.mutable_data()->assign(reinterpret_cast<const char *>(v), 4*count * sizeof(GLfloat));
- int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glUniform4fv);
-}
-
-void Debug_glUniform4i(GLint location, GLint x, GLint y, GLint z, GLint w)
-{
- glesv2debugger::Message msg;
- struct : public FunctionCall {
- GLint location;
- GLint x;
- GLint y;
- GLint z;
- GLint w;
-
- const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
- _c->glUniform4i(location, x, y, z, w);
- return 0;
- }
- } caller;
- caller.location = location;
- caller.x = x;
- caller.y = y;
- caller.z = z;
- caller.w = w;
-
- msg.set_arg0(location);
- msg.set_arg1(x);
- msg.set_arg2(y);
- msg.set_arg3(z);
- msg.set_arg4(w);
-
- int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glUniform4i);
-}
-
-void Debug_glUniform4iv(GLint location, GLsizei count, const GLint* v)
-{
- glesv2debugger::Message msg;
- struct : public FunctionCall {
- GLint location;
- GLsizei count;
- const GLint* v;
-
- const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
- _c->glUniform4iv(location, count, v);
- return 0;
- }
- } caller;
- caller.location = location;
- caller.count = count;
- caller.v = v;
-
- msg.set_arg0(location);
- msg.set_arg1(count);
- msg.set_arg2(ToInt(v));
-
- // FIXME: check for pointer usage
- msg.mutable_data()->assign(reinterpret_cast<const char *>(v), 4*count * sizeof(GLint));
- int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glUniform4iv);
-}
-
-void Debug_glUniformMatrix2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value)
-{
- glesv2debugger::Message msg;
- struct : public FunctionCall {
- GLint location;
- GLsizei count;
- GLboolean transpose;
- const GLfloat* value;
-
- const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
- _c->glUniformMatrix2fv(location, count, transpose, value);
- return 0;
- }
- } caller;
- caller.location = location;
- caller.count = count;
- caller.transpose = transpose;
- caller.value = value;
-
- msg.set_arg0(location);
- msg.set_arg1(count);
- msg.set_arg2(transpose);
- msg.set_arg3(ToInt(value));
-
- // FIXME: check for pointer usage
- msg.mutable_data()->assign(reinterpret_cast<const char *>(value), 4*count * sizeof(GLfloat));
- int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glUniformMatrix2fv);
-}
-
-void Debug_glUniformMatrix3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value)
-{
- glesv2debugger::Message msg;
- struct : public FunctionCall {
- GLint location;
- GLsizei count;
- GLboolean transpose;
- const GLfloat* value;
-
- const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
- _c->glUniformMatrix3fv(location, count, transpose, value);
- return 0;
- }
- } caller;
- caller.location = location;
- caller.count = count;
- caller.transpose = transpose;
- caller.value = value;
-
- msg.set_arg0(location);
- msg.set_arg1(count);
- msg.set_arg2(transpose);
- msg.set_arg3(ToInt(value));
-
- // FIXME: check for pointer usage
- msg.mutable_data()->assign(reinterpret_cast<const char *>(value), 9*count * sizeof(GLfloat));
- int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glUniformMatrix3fv);
-}
-
-void Debug_glUniformMatrix4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value)
-{
- glesv2debugger::Message msg;
- struct : public FunctionCall {
- GLint location;
- GLsizei count;
- GLboolean transpose;
- const GLfloat* value;
-
- const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
- _c->glUniformMatrix4fv(location, count, transpose, value);
- return 0;
- }
- } caller;
- caller.location = location;
- caller.count = count;
- caller.transpose = transpose;
- caller.value = value;
-
- msg.set_arg0(location);
- msg.set_arg1(count);
- msg.set_arg2(transpose);
- msg.set_arg3(ToInt(value));
-
- // FIXME: check for pointer usage
- msg.mutable_data()->assign(reinterpret_cast<const char *>(value), 16*count * sizeof(GLfloat));
- int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glUniformMatrix4fv);
-}
-
-void Debug_glUseProgram(GLuint program)
-{
- glesv2debugger::Message msg;
- struct : public FunctionCall {
- GLuint program;
-
- const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
- _c->glUseProgram(program);
- getDbgContextThreadSpecific()->glUseProgram(program);
- return 0;
- }
- } caller;
- caller.program = program;
-
- msg.set_arg0(program);
-
- int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glUseProgram);
-}
-
-void Debug_glValidateProgram(GLuint program)
-{
- glesv2debugger::Message msg;
- struct : public FunctionCall {
- GLuint program;
-
- const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
- _c->glValidateProgram(program);
- return 0;
- }
- } caller;
- caller.program = program;
-
- msg.set_arg0(program);
-
- int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glValidateProgram);
-}
-
-void Debug_glVertexAttrib1f(GLuint indx, GLfloat x)
-{
- glesv2debugger::Message msg;
- struct : public FunctionCall {
- GLuint indx;
- GLfloat x;
-
- const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
- _c->glVertexAttrib1f(indx, x);
- return 0;
- }
- } caller;
- caller.indx = indx;
- caller.x = x;
-
- msg.set_arg0(indx);
- msg.set_arg1(ToInt(x));
-
- int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glVertexAttrib1f);
-}
-
-void Debug_glVertexAttrib1fv(GLuint indx, const GLfloat* values)
-{
- glesv2debugger::Message msg;
- struct : public FunctionCall {
- GLuint indx;
- const GLfloat* values;
-
- const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
- _c->glVertexAttrib1fv(indx, values);
- return 0;
- }
- } caller;
- caller.indx = indx;
- caller.values = values;
-
- msg.set_arg0(indx);
- msg.set_arg1(ToInt(values));
-
- // FIXME: check for pointer usage
- msg.mutable_data()->assign(reinterpret_cast<const char *>(values), 1 * sizeof(GLfloat));
- int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glVertexAttrib1fv);
-}
-
-void Debug_glVertexAttrib2f(GLuint indx, GLfloat x, GLfloat y)
-{
- glesv2debugger::Message msg;
- struct : public FunctionCall {
- GLuint indx;
- GLfloat x;
- GLfloat y;
-
- const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
- _c->glVertexAttrib2f(indx, x, y);
- return 0;
- }
- } caller;
- caller.indx = indx;
- caller.x = x;
- caller.y = y;
-
- msg.set_arg0(indx);
- msg.set_arg1(ToInt(x));
- msg.set_arg2(ToInt(y));
-
- int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glVertexAttrib2f);
-}
-
-void Debug_glVertexAttrib2fv(GLuint indx, const GLfloat* values)
-{
- glesv2debugger::Message msg;
- struct : public FunctionCall {
- GLuint indx;
- const GLfloat* values;
-
- const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
- _c->glVertexAttrib2fv(indx, values);
- return 0;
- }
- } caller;
- caller.indx = indx;
- caller.values = values;
-
- msg.set_arg0(indx);
- msg.set_arg1(ToInt(values));
-
- // FIXME: check for pointer usage
- msg.mutable_data()->assign(reinterpret_cast<const char *>(values), 2 * sizeof(GLfloat));
- int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glVertexAttrib2fv);
-}
-
-void Debug_glVertexAttrib3f(GLuint indx, GLfloat x, GLfloat y, GLfloat z)
-{
- glesv2debugger::Message msg;
- struct : public FunctionCall {
- GLuint indx;
- GLfloat x;
- GLfloat y;
- GLfloat z;
-
- const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
- _c->glVertexAttrib3f(indx, x, y, z);
- return 0;
- }
- } caller;
- caller.indx = indx;
- caller.x = x;
- caller.y = y;
- caller.z = z;
-
- msg.set_arg0(indx);
- msg.set_arg1(ToInt(x));
- msg.set_arg2(ToInt(y));
- msg.set_arg3(ToInt(z));
-
- int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glVertexAttrib3f);
-}
-
-void Debug_glVertexAttrib3fv(GLuint indx, const GLfloat* values)
-{
- glesv2debugger::Message msg;
- struct : public FunctionCall {
- GLuint indx;
- const GLfloat* values;
-
- const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
- _c->glVertexAttrib3fv(indx, values);
- return 0;
- }
- } caller;
- caller.indx = indx;
- caller.values = values;
-
- msg.set_arg0(indx);
- msg.set_arg1(ToInt(values));
-
- // FIXME: check for pointer usage
- msg.mutable_data()->assign(reinterpret_cast<const char *>(values), 3 * sizeof(GLfloat));
- int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glVertexAttrib3fv);
-}
-
-void Debug_glVertexAttrib4f(GLuint indx, GLfloat x, GLfloat y, GLfloat z, GLfloat w)
-{
- glesv2debugger::Message msg;
- struct : public FunctionCall {
- GLuint indx;
- GLfloat x;
- GLfloat y;
- GLfloat z;
- GLfloat w;
-
- const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
- _c->glVertexAttrib4f(indx, x, y, z, w);
- return 0;
- }
- } caller;
- caller.indx = indx;
- caller.x = x;
- caller.y = y;
- caller.z = z;
- caller.w = w;
-
- msg.set_arg0(indx);
- msg.set_arg1(ToInt(x));
- msg.set_arg2(ToInt(y));
- msg.set_arg3(ToInt(z));
- msg.set_arg4(ToInt(w));
-
- int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glVertexAttrib4f);
-}
-
-void Debug_glVertexAttrib4fv(GLuint indx, const GLfloat* values)
-{
- glesv2debugger::Message msg;
- struct : public FunctionCall {
- GLuint indx;
- const GLfloat* values;
-
- const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
- _c->glVertexAttrib4fv(indx, values);
- return 0;
- }
- } caller;
- caller.indx = indx;
- caller.values = values;
-
- msg.set_arg0(indx);
- msg.set_arg1(ToInt(values));
-
- // FIXME: check for pointer usage
- msg.mutable_data()->assign(reinterpret_cast<const char *>(values), 4 * sizeof(GLfloat));
- int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glVertexAttrib4fv);
-}
-
-// FIXME: this function has pointers, it should be hand written
-void Debug_glVertexAttribPointer(GLuint indx, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const GLvoid* ptr)
-{
- glesv2debugger::Message msg;
- struct : public FunctionCall {
- GLuint indx;
- GLint size;
- GLenum type;
- GLboolean normalized;
- GLsizei stride;
- const GLvoid* ptr;
-
- const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
- _c->glVertexAttribPointer(indx, size, type, normalized, stride, ptr);
- getDbgContextThreadSpecific()->glVertexAttribPointer(indx, size, type, normalized, stride, ptr);
- return 0;
- }
- } caller;
- caller.indx = indx;
- caller.size = size;
- caller.type = type;
- caller.normalized = normalized;
- caller.stride = stride;
- caller.ptr = ptr;
-
- msg.set_arg0(indx);
- msg.set_arg1(size);
- msg.set_arg2(type);
- msg.set_arg3(normalized);
- msg.set_arg4(stride);
- msg.set_arg5(ToInt(ptr));
-
- // FIXME: check for pointer usage
- int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glVertexAttribPointer);
-}
-
-void Debug_glViewport(GLint x, GLint y, GLsizei width, GLsizei height)
-{
- glesv2debugger::Message msg;
- struct : public FunctionCall {
- GLint x;
- GLint y;
- GLsizei width;
- GLsizei height;
-
- const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
- _c->glViewport(x, y, width, height);
- return 0;
- }
- } caller;
- caller.x = x;
- caller.y = y;
- caller.width = width;
- caller.height = height;
-
- msg.set_arg0(x);
- msg.set_arg1(y);
- msg.set_arg2(width);
- msg.set_arg3(height);
-
- int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glViewport);
-}
-
-// FIXME: the following functions should be written by hand
-void Debug_glCompressedTexImage2D(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const GLvoid* data);
-void Debug_glCompressedTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const GLvoid* data);
-void Debug_glGetActiveAttrib(GLuint program, GLuint index, GLsizei bufsize, GLsizei* length, GLint* size, GLenum* type, GLchar* name);
-void Debug_glGetActiveUniform(GLuint program, GLuint index, GLsizei bufsize, GLsizei* length, GLint* size, GLenum* type, GLchar* name);
-void Debug_glGetAttachedShaders(GLuint program, GLsizei maxcount, GLsizei* count, GLuint* shaders);
-void Debug_glGetBooleanv(GLenum pname, GLboolean* params);
-void Debug_glGetBufferParameteriv(GLenum target, GLenum pname, GLint* params);
-void Debug_glGetFloatv(GLenum pname, GLfloat* params);
-void Debug_glGetFramebufferAttachmentParameteriv(GLenum target, GLenum attachment, GLenum pname, GLint* params);
-void Debug_glGetIntegerv(GLenum pname, GLint* params);
-void Debug_glGetProgramInfoLog(GLuint program, GLsizei bufsize, GLsizei* length, GLchar* infolog);
-void Debug_glGetRenderbufferParameteriv(GLenum target, GLenum pname, GLint* params);
-void Debug_glGetShaderInfoLog(GLuint shader, GLsizei bufsize, GLsizei* length, GLchar* infolog);
-void Debug_glGetShaderPrecisionFormat(GLenum shadertype, GLenum precisiontype, GLint* range, GLint* precision);
-void Debug_glGetShaderSource(GLuint shader, GLsizei bufsize, GLsizei* length, GLchar* source);
-const GLubyte* Debug_glGetString(GLenum name);
-void Debug_glGetTexParameterfv(GLenum target, GLenum pname, GLfloat* params);
-void Debug_glGetTexParameteriv(GLenum target, GLenum pname, GLint* params);
-void Debug_glGetUniformfv(GLuint program, GLint location, GLfloat* params);
-void Debug_glGetUniformiv(GLuint program, GLint location, GLint* params);
-void Debug_glGetVertexAttribfv(GLuint index, GLenum pname, GLfloat* params);
-void Debug_glGetVertexAttribiv(GLuint index, GLenum pname, GLint* params);
-void Debug_glGetVertexAttribPointerv(GLuint index, GLenum pname, GLvoid** pointer);
-void Debug_glShaderBinary(GLsizei n, const GLuint* shaders, GLenum binaryformat, const GLvoid* binary, GLsizei length);
-void Debug_glTexParameterfv(GLenum target, GLenum pname, const GLfloat* params);
-void Debug_glTexParameteriv(GLenum target, GLenum pname, const GLint* params);
-void Debug_glVertexAttribPointer(GLuint indx, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const GLvoid* ptr);
diff --git a/opengl/libs/GLES2_dbg/src/api.h b/opengl/libs/GLES2_dbg/src/api.h
deleted file mode 100644
index 0b227bc..0000000
--- a/opengl/libs/GLES2_dbg/src/api.h
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
- ** Copyright 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.
- ** 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 EXTEND_Debug_glCopyTexImage2D \
- DbgContext * const dbg = getDbgContextThreadSpecific(); \
- void * readData = dbg->GetReadPixelsBuffer(4 * width * height); \
- /* pick easy format for client to convert */ \
- dbg->hooks->gl.glReadPixels(x, y, width, height, GL_RGBA, GL_UNSIGNED_BYTE, readData); \
- dbg->CompressReadPixelBuffer(msg.mutable_data()); \
- msg.set_data_type(msg.ReferencedImage); \
- msg.set_pixel_format(GL_RGBA); \
- msg.set_pixel_type(GL_UNSIGNED_BYTE);
-
-#define EXTEND_Debug_glCopyTexSubImage2D EXTEND_Debug_glCopyTexImage2D
-
-#define EXTEND_AFTER_CALL_Debug_glReadPixels \
- { \
- DbgContext * const dbg = getDbgContextThreadSpecific(); \
- if (dbg->IsReadPixelBuffer(pixels)) { \
- dbg->CompressReadPixelBuffer(msg.mutable_data()); \
- msg.set_data_type(msg.ReferencedImage); \
- } else { \
- const unsigned int size = width * height * GetBytesPerPixel(format, type); \
- dbg->Compress(pixels, size, msg.mutable_data()); \
- msg.set_data_type(msg.NonreferencedImage); \
- } \
- }
-
-#define EXTEND_Debug_glShaderSource \
- std::string * const data = msg.mutable_data(); \
- for (unsigned i = 0; i < count; i++) \
- if (!length || length[i] < 0) \
- data->append(string[i]); \
- else \
- data->append(string[i], length[i]);
-
-#define EXTEND_Debug_glTexImage2D \
- if (pixels) { \
- DbgContext * const dbg = getDbgContextThreadSpecific(); \
- const unsigned size = GetBytesPerPixel(format, type) * width * height; \
- assert(0 < size); \
- dbg->Compress(pixels, size, msg.mutable_data()); \
- }
-
-#define EXTEND_Debug_glTexSubImage2D EXTEND_Debug_glTexImage2D
diff --git a/opengl/libs/GLES2_dbg/src/caller.cpp b/opengl/libs/GLES2_dbg/src/caller.cpp
deleted file mode 100644
index 70d23d6..0000000
--- a/opengl/libs/GLES2_dbg/src/caller.cpp
+++ /dev/null
@@ -1,778 +0,0 @@
-/*
- ** Copyright 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.
- ** 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.
- */
-
-// auto generated by generate_caller_cpp.py
-// implement declarations in caller.h
-
-#include "header.h"
-
-namespace android {
-
-static const int * GenerateCall_glCompressedTexImage2D(DbgContext * const dbg,
- const glesv2debugger::Message & cmd, glesv2debugger::Message & msg, const int * const prevRet);
-static const int * GenerateCall_glCompressedTexSubImage2D(DbgContext * const dbg,
- const glesv2debugger::Message & cmd, glesv2debugger::Message & msg, const int * const prevRet);
-static const int * GenerateCall_glDrawElements(DbgContext * const dbg,
- const glesv2debugger::Message & cmd, glesv2debugger::Message & msg, const int * const prevRet);
-static const int * GenerateCall_glGenBuffers(DbgContext * const dbg,
- const glesv2debugger::Message & cmd, glesv2debugger::Message & msg, const int * const prevRet);
-static const int * GenerateCall_glGenFramebuffers(DbgContext * const dbg,
- const glesv2debugger::Message & cmd, glesv2debugger::Message & msg, const int * const prevRet);
-static const int * GenerateCall_glGenRenderbuffers(DbgContext * const dbg,
- const glesv2debugger::Message & cmd, glesv2debugger::Message & msg, const int * const prevRet);
-static const int * GenerateCall_glGenTextures(DbgContext * const dbg,
- const glesv2debugger::Message & cmd, glesv2debugger::Message & msg, const int * const prevRet);
-static const int * GenerateCall_glGetActiveAttrib(DbgContext * const dbg,
- const glesv2debugger::Message & cmd, glesv2debugger::Message & msg, const int * const prevRet);
-static const int * GenerateCall_glGetActiveUniform(DbgContext * const dbg,
- const glesv2debugger::Message & cmd, glesv2debugger::Message & msg, const int * const prevRet);
-static const int * GenerateCall_glGetAttachedShaders(DbgContext * const dbg,
- const glesv2debugger::Message & cmd, glesv2debugger::Message & msg, const int * const prevRet);
-static const int * GenerateCall_glGetBooleanv(DbgContext * const dbg,
- const glesv2debugger::Message & cmd, glesv2debugger::Message & msg, const int * const prevRet);
-static const int * GenerateCall_glGetBufferParameteriv(DbgContext * const dbg,
- const glesv2debugger::Message & cmd, glesv2debugger::Message & msg, const int * const prevRet);
-static const int * GenerateCall_glGetFloatv(DbgContext * const dbg,
- const glesv2debugger::Message & cmd, glesv2debugger::Message & msg, const int * const prevRet);
-static const int * GenerateCall_glGetFramebufferAttachmentParameteriv(DbgContext * const dbg,
- const glesv2debugger::Message & cmd, glesv2debugger::Message & msg, const int * const prevRet);
-static const int * GenerateCall_glGetIntegerv(DbgContext * const dbg,
- const glesv2debugger::Message & cmd, glesv2debugger::Message & msg, const int * const prevRet);
-static const int * GenerateCall_glGetProgramiv(DbgContext * const dbg,
- const glesv2debugger::Message & cmd, glesv2debugger::Message & msg, const int * const prevRet);
-static const int * GenerateCall_glGetProgramInfoLog(DbgContext * const dbg,
- const glesv2debugger::Message & cmd, glesv2debugger::Message & msg, const int * const prevRet);
-static const int * GenerateCall_glGetRenderbufferParameteriv(DbgContext * const dbg,
- const glesv2debugger::Message & cmd, glesv2debugger::Message & msg, const int * const prevRet);
-static const int * GenerateCall_glGetShaderiv(DbgContext * const dbg,
- const glesv2debugger::Message & cmd, glesv2debugger::Message & msg, const int * const prevRet);
-static const int * GenerateCall_glGetShaderInfoLog(DbgContext * const dbg,
- const glesv2debugger::Message & cmd, glesv2debugger::Message & msg, const int * const prevRet);
-static const int * GenerateCall_glGetShaderPrecisionFormat(DbgContext * const dbg,
- const glesv2debugger::Message & cmd, glesv2debugger::Message & msg, const int * const prevRet);
-static const int * GenerateCall_glGetShaderSource(DbgContext * const dbg,
- const glesv2debugger::Message & cmd, glesv2debugger::Message & msg, const int * const prevRet);
-static const int * GenerateCall_glGetString(DbgContext * const dbg,
- const glesv2debugger::Message & cmd, glesv2debugger::Message & msg, const int * const prevRet);
-static const int * GenerateCall_glGetTexParameterfv(DbgContext * const dbg,
- const glesv2debugger::Message & cmd, glesv2debugger::Message & msg, const int * const prevRet);
-static const int * GenerateCall_glGetTexParameteriv(DbgContext * const dbg,
- const glesv2debugger::Message & cmd, glesv2debugger::Message & msg, const int * const prevRet);
-static const int * GenerateCall_glGetUniformfv(DbgContext * const dbg,
- const glesv2debugger::Message & cmd, glesv2debugger::Message & msg, const int * const prevRet);
-static const int * GenerateCall_glGetUniformiv(DbgContext * const dbg,
- const glesv2debugger::Message & cmd, glesv2debugger::Message & msg, const int * const prevRet);
-static const int * GenerateCall_glGetVertexAttribfv(DbgContext * const dbg,
- const glesv2debugger::Message & cmd, glesv2debugger::Message & msg, const int * const prevRet);
-static const int * GenerateCall_glGetVertexAttribiv(DbgContext * const dbg,
- const glesv2debugger::Message & cmd, glesv2debugger::Message & msg, const int * const prevRet);
-static const int * GenerateCall_glGetVertexAttribPointerv(DbgContext * const dbg,
- const glesv2debugger::Message & cmd, glesv2debugger::Message & msg, const int * const prevRet);
-static const int * GenerateCall_glReadPixels(DbgContext * const dbg,
- const glesv2debugger::Message & cmd, glesv2debugger::Message & msg, const int * const prevRet);
-static const int * GenerateCall_glShaderBinary(DbgContext * const dbg,
- const glesv2debugger::Message & cmd, glesv2debugger::Message & msg, const int * const prevRet);
-static const int * GenerateCall_glShaderSource(DbgContext * const dbg,
- const glesv2debugger::Message & cmd, glesv2debugger::Message & msg, const int * const prevRet);
-static const int * GenerateCall_glTexImage2D(DbgContext * const dbg,
- const glesv2debugger::Message & cmd, glesv2debugger::Message & msg, const int * const prevRet);
-static const int * GenerateCall_glTexParameterfv(DbgContext * const dbg,
- const glesv2debugger::Message & cmd, glesv2debugger::Message & msg, const int * const prevRet);
-static const int * GenerateCall_glTexParameteriv(DbgContext * const dbg,
- const glesv2debugger::Message & cmd, glesv2debugger::Message & msg, const int * const prevRet);
-static const int * GenerateCall_glTexSubImage2D(DbgContext * const dbg,
- const glesv2debugger::Message & cmd, glesv2debugger::Message & msg, const int * const prevRet);
-static const int * GenerateCall_glVertexAttribPointer(DbgContext * const dbg,
- const glesv2debugger::Message & cmd, glesv2debugger::Message & msg, const int * const prevRet);
-
-#include "caller.h"
-
-const int * GenerateCall(DbgContext * const dbg, const glesv2debugger::Message & cmd,
- glesv2debugger::Message & msg, const int * const prevRet)
-{
- ALOGD("GenerateCall function=%u", cmd.function());
- const int * ret = prevRet; // only some functions have return value
- nsecs_t c0 = systemTime(timeMode);
- switch (cmd.function()) { case glesv2debugger::Message_Function_glActiveTexture:
- dbg->hooks->gl.glActiveTexture(
- static_cast<GLenum>(cmd.arg0()));
- break;
- case glesv2debugger::Message_Function_glAttachShader:
- dbg->hooks->gl.glAttachShader(
- static_cast<GLuint>(cmd.arg0()), static_cast<GLuint>(cmd.arg1())
- );
- break;
- case glesv2debugger::Message_Function_glBindAttribLocation:
- dbg->hooks->gl.glBindAttribLocation(
- static_cast<GLuint>(cmd.arg0()), static_cast<GLuint>(cmd.arg1()),
- reinterpret_cast<GLchar*>(const_cast<char *>(cmd.data().data()))
- );
- break;
- case glesv2debugger::Message_Function_glBindBuffer:
- dbg->hooks->gl.glBindBuffer(
- static_cast<GLenum>(cmd.arg0()), static_cast<GLuint>(cmd.arg1())
- );
- break;
- case glesv2debugger::Message_Function_glBindFramebuffer:
- dbg->hooks->gl.glBindFramebuffer(
- static_cast<GLenum>(cmd.arg0()), static_cast<GLuint>(cmd.arg1())
- );
- break;
- case glesv2debugger::Message_Function_glBindRenderbuffer:
- dbg->hooks->gl.glBindRenderbuffer(
- static_cast<GLenum>(cmd.arg0()), static_cast<GLuint>(cmd.arg1())
- );
- break;
- case glesv2debugger::Message_Function_glBindTexture:
- dbg->hooks->gl.glBindTexture(
- static_cast<GLenum>(cmd.arg0()), static_cast<GLuint>(cmd.arg1())
- );
- break;
- case glesv2debugger::Message_Function_glBlendColor:
- dbg->hooks->gl.glBlendColor(
- static_cast<GLclampf>(cmd.arg0()), static_cast<GLclampf>(cmd.arg1()),
- static_cast<GLclampf>(cmd.arg2()), static_cast<GLclampf>(cmd.arg3())
- );
- break;
- case glesv2debugger::Message_Function_glBlendEquation:
- dbg->hooks->gl.glBlendEquation(
- static_cast<GLenum>(cmd.arg0()));
- break;
- case glesv2debugger::Message_Function_glBlendEquationSeparate:
- dbg->hooks->gl.glBlendEquationSeparate(
- static_cast<GLenum>(cmd.arg0()), static_cast<GLenum>(cmd.arg1())
- );
- break;
- case glesv2debugger::Message_Function_glBlendFunc:
- dbg->hooks->gl.glBlendFunc(
- static_cast<GLenum>(cmd.arg0()), static_cast<GLenum>(cmd.arg1())
- );
- break;
- case glesv2debugger::Message_Function_glBlendFuncSeparate:
- dbg->hooks->gl.glBlendFuncSeparate(
- static_cast<GLenum>(cmd.arg0()), static_cast<GLenum>(cmd.arg1()),
- static_cast<GLenum>(cmd.arg2()), static_cast<GLenum>(cmd.arg3())
- );
- break;
- case glesv2debugger::Message_Function_glBufferData:
- dbg->hooks->gl.glBufferData(
- static_cast<GLenum>(cmd.arg0()), static_cast<GLsizeiptr>(cmd.arg1()),
- reinterpret_cast<GLvoid*>(const_cast<char *>(cmd.data().data())),
- static_cast<GLenum>(cmd.arg3()));
- break;
- case glesv2debugger::Message_Function_glBufferSubData:
- dbg->hooks->gl.glBufferSubData(
- static_cast<GLenum>(cmd.arg0()), static_cast<GLintptr>(cmd.arg1()),
- static_cast<GLsizeiptr>(cmd.arg2()), reinterpret_cast<GLvoid*>(const_cast<char *>(cmd.data().data()))
- );
- break;
- case glesv2debugger::Message_Function_glCheckFramebufferStatus:
- msg.set_ret(static_cast<int>(dbg->hooks->gl.glCheckFramebufferStatus(
- static_cast<GLenum>(cmd.arg0()))));
- if (cmd.has_ret())
- ret = reinterpret_cast<int *>(msg.ret());
- break;
- case glesv2debugger::Message_Function_glClear:
- dbg->hooks->gl.glClear(
- static_cast<GLbitfield>(cmd.arg0()));
- break;
- case glesv2debugger::Message_Function_glClearColor:
- dbg->hooks->gl.glClearColor(
- static_cast<GLclampf>(cmd.arg0()), static_cast<GLclampf>(cmd.arg1()),
- static_cast<GLclampf>(cmd.arg2()), static_cast<GLclampf>(cmd.arg3())
- );
- break;
- case glesv2debugger::Message_Function_glClearDepthf:
- dbg->hooks->gl.glClearDepthf(
- static_cast<GLclampf>(cmd.arg0()));
- break;
- case glesv2debugger::Message_Function_glClearStencil:
- dbg->hooks->gl.glClearStencil(
- static_cast<GLint>(cmd.arg0()));
- break;
- case glesv2debugger::Message_Function_glColorMask:
- dbg->hooks->gl.glColorMask(
- GLboolean(cmd.arg0()), GLboolean(cmd.arg1()), GLboolean(cmd.arg2()),
- GLboolean(cmd.arg3()));
- break;
- case glesv2debugger::Message_Function_glCompileShader:
- dbg->hooks->gl.glCompileShader(
- static_cast<GLuint>(cmd.arg0()));
- break;
- case glesv2debugger::Message_Function_glCompressedTexImage2D:
- ret = GenerateCall_glCompressedTexImage2D(dbg, cmd, msg, prevRet);
- break;
- case glesv2debugger::Message_Function_glCompressedTexSubImage2D:
- ret = GenerateCall_glCompressedTexSubImage2D(dbg, cmd, msg, prevRet);
- break;
- case glesv2debugger::Message_Function_glCopyTexImage2D:
- dbg->hooks->gl.glCopyTexImage2D(
- static_cast<GLenum>(cmd.arg0()), static_cast<GLint>(cmd.arg1()),
- static_cast<GLenum>(cmd.arg2()), static_cast<GLint>(cmd.arg3()),
- static_cast<GLint>(cmd.arg4()), static_cast<GLsizei>(cmd.arg5()),
- static_cast<GLsizei>(cmd.arg6()), static_cast<GLint>(cmd.arg7())
- );
- break;
- case glesv2debugger::Message_Function_glCopyTexSubImage2D:
- dbg->hooks->gl.glCopyTexSubImage2D(
- static_cast<GLenum>(cmd.arg0()), static_cast<GLint>(cmd.arg1()),
- static_cast<GLint>(cmd.arg2()), static_cast<GLint>(cmd.arg3()),
- static_cast<GLint>(cmd.arg4()), static_cast<GLint>(cmd.arg5()),
- static_cast<GLsizei>(cmd.arg6()), static_cast<GLsizei>(cmd.arg7())
- );
- break;
- case glesv2debugger::Message_Function_glCreateProgram:
- msg.set_ret(static_cast<int>(dbg->hooks->gl.glCreateProgram(
- )));
- if (cmd.has_ret())
- ret = reinterpret_cast<int *>(msg.ret());
- break;
- case glesv2debugger::Message_Function_glCreateShader:
- msg.set_ret(static_cast<int>(dbg->hooks->gl.glCreateShader(
- static_cast<GLenum>(cmd.arg0()))));
- if (cmd.has_ret())
- ret = reinterpret_cast<int *>(msg.ret());
- break;
- case glesv2debugger::Message_Function_glCullFace:
- dbg->hooks->gl.glCullFace(
- static_cast<GLenum>(cmd.arg0()));
- break;
- case glesv2debugger::Message_Function_glDeleteBuffers:
- dbg->hooks->gl.glDeleteBuffers(
- static_cast<GLsizei>(cmd.arg0()), reinterpret_cast<GLuint*>(const_cast<char *>(cmd.data().data()))
- );
- break;
- case glesv2debugger::Message_Function_glDeleteFramebuffers:
- dbg->hooks->gl.glDeleteFramebuffers(
- static_cast<GLsizei>(cmd.arg0()), reinterpret_cast<GLuint*>(const_cast<char *>(cmd.data().data()))
- );
- break;
- case glesv2debugger::Message_Function_glDeleteProgram:
- dbg->hooks->gl.glDeleteProgram(
- static_cast<GLuint>(cmd.arg0()));
- break;
- case glesv2debugger::Message_Function_glDeleteRenderbuffers:
- dbg->hooks->gl.glDeleteRenderbuffers(
- static_cast<GLsizei>(cmd.arg0()), reinterpret_cast<GLuint*>(const_cast<char *>(cmd.data().data()))
- );
- break;
- case glesv2debugger::Message_Function_glDeleteShader:
- dbg->hooks->gl.glDeleteShader(
- static_cast<GLuint>(cmd.arg0()));
- break;
- case glesv2debugger::Message_Function_glDeleteTextures:
- dbg->hooks->gl.glDeleteTextures(
- static_cast<GLsizei>(cmd.arg0()), reinterpret_cast<GLuint*>(const_cast<char *>(cmd.data().data()))
- );
- break;
- case glesv2debugger::Message_Function_glDepthFunc:
- dbg->hooks->gl.glDepthFunc(
- static_cast<GLenum>(cmd.arg0()));
- break;
- case glesv2debugger::Message_Function_glDepthMask:
- dbg->hooks->gl.glDepthMask(
- GLboolean(cmd.arg0()));
- break;
- case glesv2debugger::Message_Function_glDepthRangef:
- dbg->hooks->gl.glDepthRangef(
- static_cast<GLclampf>(cmd.arg0()), static_cast<GLclampf>(cmd.arg1())
- );
- break;
- case glesv2debugger::Message_Function_glDetachShader:
- dbg->hooks->gl.glDetachShader(
- static_cast<GLuint>(cmd.arg0()), static_cast<GLuint>(cmd.arg1())
- );
- break;
- case glesv2debugger::Message_Function_glDisable:
- dbg->hooks->gl.glDisable(
- static_cast<GLenum>(cmd.arg0()));
- break;
- case glesv2debugger::Message_Function_glDisableVertexAttribArray:
- dbg->hooks->gl.glDisableVertexAttribArray(
- static_cast<GLuint>(cmd.arg0()));
- break;
- case glesv2debugger::Message_Function_glDrawArrays:
- dbg->hooks->gl.glDrawArrays(
- static_cast<GLenum>(cmd.arg0()), static_cast<GLint>(cmd.arg1()),
- static_cast<GLsizei>(cmd.arg2()));
- break;
- case glesv2debugger::Message_Function_glDrawElements:
- ret = GenerateCall_glDrawElements(dbg, cmd, msg, prevRet);
- break;
- case glesv2debugger::Message_Function_glEnable:
- dbg->hooks->gl.glEnable(
- static_cast<GLenum>(cmd.arg0()));
- break;
- case glesv2debugger::Message_Function_glEnableVertexAttribArray:
- dbg->hooks->gl.glEnableVertexAttribArray(
- static_cast<GLuint>(cmd.arg0()));
- break;
- case glesv2debugger::Message_Function_glFinish:
- dbg->hooks->gl.glFinish(
- );
- break;
- case glesv2debugger::Message_Function_glFlush:
- dbg->hooks->gl.glFlush(
- );
- break;
- case glesv2debugger::Message_Function_glFramebufferRenderbuffer:
- dbg->hooks->gl.glFramebufferRenderbuffer(
- static_cast<GLenum>(cmd.arg0()), static_cast<GLenum>(cmd.arg1()),
- static_cast<GLenum>(cmd.arg2()), static_cast<GLuint>(cmd.arg3())
- );
- break;
- case glesv2debugger::Message_Function_glFramebufferTexture2D:
- dbg->hooks->gl.glFramebufferTexture2D(
- static_cast<GLenum>(cmd.arg0()), static_cast<GLenum>(cmd.arg1()),
- static_cast<GLenum>(cmd.arg2()), static_cast<GLuint>(cmd.arg3()),
- static_cast<GLint>(cmd.arg4()));
- break;
- case glesv2debugger::Message_Function_glFrontFace:
- dbg->hooks->gl.glFrontFace(
- static_cast<GLenum>(cmd.arg0()));
- break;
- case glesv2debugger::Message_Function_glGenBuffers:
- ret = GenerateCall_glGenBuffers(dbg, cmd, msg, prevRet);
- break; // annotated output pointers
- case glesv2debugger::Message_Function_glGenerateMipmap:
- dbg->hooks->gl.glGenerateMipmap(
- static_cast<GLenum>(cmd.arg0()));
- break;
- case glesv2debugger::Message_Function_glGenFramebuffers:
- ret = GenerateCall_glGenFramebuffers(dbg, cmd, msg, prevRet);
- break; // annotated output pointers
- case glesv2debugger::Message_Function_glGenRenderbuffers:
- ret = GenerateCall_glGenRenderbuffers(dbg, cmd, msg, prevRet);
- break; // annotated output pointers
- case glesv2debugger::Message_Function_glGenTextures:
- ret = GenerateCall_glGenTextures(dbg, cmd, msg, prevRet);
- break; // annotated output pointers
- case glesv2debugger::Message_Function_glGetActiveAttrib:
- ret = GenerateCall_glGetActiveAttrib(dbg, cmd, msg, prevRet);
- break;
- case glesv2debugger::Message_Function_glGetActiveUniform:
- ret = GenerateCall_glGetActiveUniform(dbg, cmd, msg, prevRet);
- break;
- case glesv2debugger::Message_Function_glGetAttachedShaders:
- ret = GenerateCall_glGetAttachedShaders(dbg, cmd, msg, prevRet);
- break;
- case glesv2debugger::Message_Function_glGetAttribLocation:
- msg.set_ret(static_cast<int>(dbg->hooks->gl.glGetAttribLocation(
- static_cast<GLuint>(cmd.arg0()), reinterpret_cast<GLchar*>(const_cast<char *>(cmd.data().data()))
- )));
- if (cmd.has_ret())
- ret = reinterpret_cast<int *>(msg.ret());
- break;
- case glesv2debugger::Message_Function_glGetBooleanv:
- ret = GenerateCall_glGetBooleanv(dbg, cmd, msg, prevRet);
- break;
- case glesv2debugger::Message_Function_glGetBufferParameteriv:
- ret = GenerateCall_glGetBufferParameteriv(dbg, cmd, msg, prevRet);
- break;
- case glesv2debugger::Message_Function_glGetError:
- msg.set_ret(static_cast<int>(dbg->hooks->gl.glGetError(
- )));
- if (cmd.has_ret())
- ret = reinterpret_cast<int *>(msg.ret());
- break;
- case glesv2debugger::Message_Function_glGetFloatv:
- ret = GenerateCall_glGetFloatv(dbg, cmd, msg, prevRet);
- break;
- case glesv2debugger::Message_Function_glGetFramebufferAttachmentParameteriv:
- ret = GenerateCall_glGetFramebufferAttachmentParameteriv(dbg, cmd, msg, prevRet);
- break;
- case glesv2debugger::Message_Function_glGetIntegerv:
- ret = GenerateCall_glGetIntegerv(dbg, cmd, msg, prevRet);
- break;
- case glesv2debugger::Message_Function_glGetProgramiv:
- ret = GenerateCall_glGetProgramiv(dbg, cmd, msg, prevRet);
- break; // annotated output pointers
- case glesv2debugger::Message_Function_glGetProgramInfoLog:
- ret = GenerateCall_glGetProgramInfoLog(dbg, cmd, msg, prevRet);
- break;
- case glesv2debugger::Message_Function_glGetRenderbufferParameteriv:
- ret = GenerateCall_glGetRenderbufferParameteriv(dbg, cmd, msg, prevRet);
- break;
- case glesv2debugger::Message_Function_glGetShaderiv:
- ret = GenerateCall_glGetShaderiv(dbg, cmd, msg, prevRet);
- break; // annotated output pointers
- case glesv2debugger::Message_Function_glGetShaderInfoLog:
- ret = GenerateCall_glGetShaderInfoLog(dbg, cmd, msg, prevRet);
- break;
- case glesv2debugger::Message_Function_glGetShaderPrecisionFormat:
- ret = GenerateCall_glGetShaderPrecisionFormat(dbg, cmd, msg, prevRet);
- break;
- case glesv2debugger::Message_Function_glGetShaderSource:
- ret = GenerateCall_glGetShaderSource(dbg, cmd, msg, prevRet);
- break;
- case glesv2debugger::Message_Function_glGetString:
- ret = GenerateCall_glGetString(dbg, cmd, msg, prevRet);
- break;
- case glesv2debugger::Message_Function_glGetTexParameterfv:
- ret = GenerateCall_glGetTexParameterfv(dbg, cmd, msg, prevRet);
- break;
- case glesv2debugger::Message_Function_glGetTexParameteriv:
- ret = GenerateCall_glGetTexParameteriv(dbg, cmd, msg, prevRet);
- break;
- case glesv2debugger::Message_Function_glGetUniformfv:
- ret = GenerateCall_glGetUniformfv(dbg, cmd, msg, prevRet);
- break;
- case glesv2debugger::Message_Function_glGetUniformiv:
- ret = GenerateCall_glGetUniformiv(dbg, cmd, msg, prevRet);
- break;
- case glesv2debugger::Message_Function_glGetUniformLocation:
- msg.set_ret(static_cast<int>(dbg->hooks->gl.glGetUniformLocation(
- static_cast<GLuint>(cmd.arg0()), reinterpret_cast<GLchar*>(const_cast<char *>(cmd.data().data()))
- )));
- if (cmd.has_ret())
- ret = reinterpret_cast<int *>(msg.ret());
- break;
- case glesv2debugger::Message_Function_glGetVertexAttribfv:
- ret = GenerateCall_glGetVertexAttribfv(dbg, cmd, msg, prevRet);
- break;
- case glesv2debugger::Message_Function_glGetVertexAttribiv:
- ret = GenerateCall_glGetVertexAttribiv(dbg, cmd, msg, prevRet);
- break;
- case glesv2debugger::Message_Function_glGetVertexAttribPointerv:
- ret = GenerateCall_glGetVertexAttribPointerv(dbg, cmd, msg, prevRet);
- break;
- case glesv2debugger::Message_Function_glHint:
- dbg->hooks->gl.glHint(
- static_cast<GLenum>(cmd.arg0()), static_cast<GLenum>(cmd.arg1())
- );
- break;
- case glesv2debugger::Message_Function_glIsBuffer:
- msg.set_ret(static_cast<int>(dbg->hooks->gl.glIsBuffer(
- static_cast<GLuint>(cmd.arg0()))));
- if (cmd.has_ret())
- ret = reinterpret_cast<int *>(msg.ret());
- break;
- case glesv2debugger::Message_Function_glIsEnabled:
- msg.set_ret(static_cast<int>(dbg->hooks->gl.glIsEnabled(
- static_cast<GLenum>(cmd.arg0()))));
- if (cmd.has_ret())
- ret = reinterpret_cast<int *>(msg.ret());
- break;
- case glesv2debugger::Message_Function_glIsFramebuffer:
- msg.set_ret(static_cast<int>(dbg->hooks->gl.glIsFramebuffer(
- static_cast<GLuint>(cmd.arg0()))));
- if (cmd.has_ret())
- ret = reinterpret_cast<int *>(msg.ret());
- break;
- case glesv2debugger::Message_Function_glIsProgram:
- msg.set_ret(static_cast<int>(dbg->hooks->gl.glIsProgram(
- static_cast<GLuint>(cmd.arg0()))));
- if (cmd.has_ret())
- ret = reinterpret_cast<int *>(msg.ret());
- break;
- case glesv2debugger::Message_Function_glIsRenderbuffer:
- msg.set_ret(static_cast<int>(dbg->hooks->gl.glIsRenderbuffer(
- static_cast<GLuint>(cmd.arg0()))));
- if (cmd.has_ret())
- ret = reinterpret_cast<int *>(msg.ret());
- break;
- case glesv2debugger::Message_Function_glIsShader:
- msg.set_ret(static_cast<int>(dbg->hooks->gl.glIsShader(
- static_cast<GLuint>(cmd.arg0()))));
- if (cmd.has_ret())
- ret = reinterpret_cast<int *>(msg.ret());
- break;
- case glesv2debugger::Message_Function_glIsTexture:
- msg.set_ret(static_cast<int>(dbg->hooks->gl.glIsTexture(
- static_cast<GLuint>(cmd.arg0()))));
- if (cmd.has_ret())
- ret = reinterpret_cast<int *>(msg.ret());
- break;
- case glesv2debugger::Message_Function_glLineWidth:
- dbg->hooks->gl.glLineWidth(
- static_cast<GLfloat>(cmd.arg0()));
- break;
- case glesv2debugger::Message_Function_glLinkProgram:
- dbg->hooks->gl.glLinkProgram(
- static_cast<GLuint>(cmd.arg0()));
- break;
- case glesv2debugger::Message_Function_glPixelStorei:
- dbg->hooks->gl.glPixelStorei(
- static_cast<GLenum>(cmd.arg0()), static_cast<GLint>(cmd.arg1())
- );
- break;
- case glesv2debugger::Message_Function_glPolygonOffset:
- dbg->hooks->gl.glPolygonOffset(
- static_cast<GLfloat>(cmd.arg0()), static_cast<GLfloat>(cmd.arg1())
- );
- break;
- case glesv2debugger::Message_Function_glReadPixels:
- ret = GenerateCall_glReadPixels(dbg, cmd, msg, prevRet);
- break;
- case glesv2debugger::Message_Function_glReleaseShaderCompiler:
- dbg->hooks->gl.glReleaseShaderCompiler(
- );
- break;
- case glesv2debugger::Message_Function_glRenderbufferStorage:
- dbg->hooks->gl.glRenderbufferStorage(
- static_cast<GLenum>(cmd.arg0()), static_cast<GLenum>(cmd.arg1()),
- static_cast<GLsizei>(cmd.arg2()), static_cast<GLsizei>(cmd.arg3())
- );
- break;
- case glesv2debugger::Message_Function_glSampleCoverage:
- dbg->hooks->gl.glSampleCoverage(
- static_cast<GLclampf>(cmd.arg0()), GLboolean(cmd.arg1()));
- break;
- case glesv2debugger::Message_Function_glScissor:
- dbg->hooks->gl.glScissor(
- static_cast<GLint>(cmd.arg0()), static_cast<GLint>(cmd.arg1()),
- static_cast<GLsizei>(cmd.arg2()), static_cast<GLsizei>(cmd.arg3())
- );
- break;
- case glesv2debugger::Message_Function_glShaderBinary:
- ret = GenerateCall_glShaderBinary(dbg, cmd, msg, prevRet);
- break;
- case glesv2debugger::Message_Function_glShaderSource:
- ret = GenerateCall_glShaderSource(dbg, cmd, msg, prevRet);
- break;
- case glesv2debugger::Message_Function_glStencilFunc:
- dbg->hooks->gl.glStencilFunc(
- static_cast<GLenum>(cmd.arg0()), static_cast<GLint>(cmd.arg1()),
- static_cast<GLuint>(cmd.arg2()));
- break;
- case glesv2debugger::Message_Function_glStencilFuncSeparate:
- dbg->hooks->gl.glStencilFuncSeparate(
- static_cast<GLenum>(cmd.arg0()), static_cast<GLenum>(cmd.arg1()),
- static_cast<GLint>(cmd.arg2()), static_cast<GLuint>(cmd.arg3())
- );
- break;
- case glesv2debugger::Message_Function_glStencilMask:
- dbg->hooks->gl.glStencilMask(
- static_cast<GLuint>(cmd.arg0()));
- break;
- case glesv2debugger::Message_Function_glStencilMaskSeparate:
- dbg->hooks->gl.glStencilMaskSeparate(
- static_cast<GLenum>(cmd.arg0()), static_cast<GLuint>(cmd.arg1())
- );
- break;
- case glesv2debugger::Message_Function_glStencilOp:
- dbg->hooks->gl.glStencilOp(
- static_cast<GLenum>(cmd.arg0()), static_cast<GLenum>(cmd.arg1()),
- static_cast<GLenum>(cmd.arg2()));
- break;
- case glesv2debugger::Message_Function_glStencilOpSeparate:
- dbg->hooks->gl.glStencilOpSeparate(
- static_cast<GLenum>(cmd.arg0()), static_cast<GLenum>(cmd.arg1()),
- static_cast<GLenum>(cmd.arg2()), static_cast<GLenum>(cmd.arg3())
- );
- break;
- case glesv2debugger::Message_Function_glTexImage2D:
- ret = GenerateCall_glTexImage2D(dbg, cmd, msg, prevRet);
- break;
- case glesv2debugger::Message_Function_glTexParameterf:
- dbg->hooks->gl.glTexParameterf(
- static_cast<GLenum>(cmd.arg0()), static_cast<GLenum>(cmd.arg1()),
- static_cast<GLfloat>(cmd.arg2()));
- break;
- case glesv2debugger::Message_Function_glTexParameterfv:
- ret = GenerateCall_glTexParameterfv(dbg, cmd, msg, prevRet);
- break;
- case glesv2debugger::Message_Function_glTexParameteri:
- dbg->hooks->gl.glTexParameteri(
- static_cast<GLenum>(cmd.arg0()), static_cast<GLenum>(cmd.arg1()),
- static_cast<GLint>(cmd.arg2()));
- break;
- case glesv2debugger::Message_Function_glTexParameteriv:
- ret = GenerateCall_glTexParameteriv(dbg, cmd, msg, prevRet);
- break;
- case glesv2debugger::Message_Function_glTexSubImage2D:
- ret = GenerateCall_glTexSubImage2D(dbg, cmd, msg, prevRet);
- break;
- case glesv2debugger::Message_Function_glUniform1f:
- dbg->hooks->gl.glUniform1f(
- static_cast<GLint>(cmd.arg0()), static_cast<GLfloat>(cmd.arg1())
- );
- break;
- case glesv2debugger::Message_Function_glUniform1fv:
- dbg->hooks->gl.glUniform1fv(
- static_cast<GLint>(cmd.arg0()), static_cast<GLsizei>(cmd.arg1()),
- reinterpret_cast<GLfloat*>(const_cast<char *>(cmd.data().data()))
- );
- break;
- case glesv2debugger::Message_Function_glUniform1i:
- dbg->hooks->gl.glUniform1i(
- static_cast<GLint>(cmd.arg0()), static_cast<GLint>(cmd.arg1())
- );
- break;
- case glesv2debugger::Message_Function_glUniform1iv:
- dbg->hooks->gl.glUniform1iv(
- static_cast<GLint>(cmd.arg0()), static_cast<GLsizei>(cmd.arg1()),
- reinterpret_cast<GLint*>(const_cast<char *>(cmd.data().data()))
- );
- break;
- case glesv2debugger::Message_Function_glUniform2f:
- dbg->hooks->gl.glUniform2f(
- static_cast<GLint>(cmd.arg0()), static_cast<GLfloat>(cmd.arg1()),
- static_cast<GLfloat>(cmd.arg2()));
- break;
- case glesv2debugger::Message_Function_glUniform2fv:
- dbg->hooks->gl.glUniform2fv(
- static_cast<GLint>(cmd.arg0()), static_cast<GLsizei>(cmd.arg1()),
- reinterpret_cast<GLfloat*>(const_cast<char *>(cmd.data().data()))
- );
- break;
- case glesv2debugger::Message_Function_glUniform2i:
- dbg->hooks->gl.glUniform2i(
- static_cast<GLint>(cmd.arg0()), static_cast<GLint>(cmd.arg1()),
- static_cast<GLint>(cmd.arg2()));
- break;
- case glesv2debugger::Message_Function_glUniform2iv:
- dbg->hooks->gl.glUniform2iv(
- static_cast<GLint>(cmd.arg0()), static_cast<GLsizei>(cmd.arg1()),
- reinterpret_cast<GLint*>(const_cast<char *>(cmd.data().data()))
- );
- break;
- case glesv2debugger::Message_Function_glUniform3f:
- dbg->hooks->gl.glUniform3f(
- static_cast<GLint>(cmd.arg0()), static_cast<GLfloat>(cmd.arg1()),
- static_cast<GLfloat>(cmd.arg2()), static_cast<GLfloat>(cmd.arg3())
- );
- break;
- case glesv2debugger::Message_Function_glUniform3fv:
- dbg->hooks->gl.glUniform3fv(
- static_cast<GLint>(cmd.arg0()), static_cast<GLsizei>(cmd.arg1()),
- reinterpret_cast<GLfloat*>(const_cast<char *>(cmd.data().data()))
- );
- break;
- case glesv2debugger::Message_Function_glUniform3i:
- dbg->hooks->gl.glUniform3i(
- static_cast<GLint>(cmd.arg0()), static_cast<GLint>(cmd.arg1()),
- static_cast<GLint>(cmd.arg2()), static_cast<GLint>(cmd.arg3())
- );
- break;
- case glesv2debugger::Message_Function_glUniform3iv:
- dbg->hooks->gl.glUniform3iv(
- static_cast<GLint>(cmd.arg0()), static_cast<GLsizei>(cmd.arg1()),
- reinterpret_cast<GLint*>(const_cast<char *>(cmd.data().data()))
- );
- break;
- case glesv2debugger::Message_Function_glUniform4f:
- dbg->hooks->gl.glUniform4f(
- static_cast<GLint>(cmd.arg0()), static_cast<GLfloat>(cmd.arg1()),
- static_cast<GLfloat>(cmd.arg2()), static_cast<GLfloat>(cmd.arg3()),
- static_cast<GLfloat>(cmd.arg4()));
- break;
- case glesv2debugger::Message_Function_glUniform4fv:
- dbg->hooks->gl.glUniform4fv(
- static_cast<GLint>(cmd.arg0()), static_cast<GLsizei>(cmd.arg1()),
- reinterpret_cast<GLfloat*>(const_cast<char *>(cmd.data().data()))
- );
- break;
- case glesv2debugger::Message_Function_glUniform4i:
- dbg->hooks->gl.glUniform4i(
- static_cast<GLint>(cmd.arg0()), static_cast<GLint>(cmd.arg1()),
- static_cast<GLint>(cmd.arg2()), static_cast<GLint>(cmd.arg3()),
- static_cast<GLint>(cmd.arg4()));
- break;
- case glesv2debugger::Message_Function_glUniform4iv:
- dbg->hooks->gl.glUniform4iv(
- static_cast<GLint>(cmd.arg0()), static_cast<GLsizei>(cmd.arg1()),
- reinterpret_cast<GLint*>(const_cast<char *>(cmd.data().data()))
- );
- break;
- case glesv2debugger::Message_Function_glUniformMatrix2fv:
- dbg->hooks->gl.glUniformMatrix2fv(
- static_cast<GLint>(cmd.arg0()), static_cast<GLsizei>(cmd.arg1()),
- GLboolean(cmd.arg2()), reinterpret_cast<GLfloat*>(const_cast<char *>(cmd.data().data()))
- );
- break;
- case glesv2debugger::Message_Function_glUniformMatrix3fv:
- dbg->hooks->gl.glUniformMatrix3fv(
- static_cast<GLint>(cmd.arg0()), static_cast<GLsizei>(cmd.arg1()),
- GLboolean(cmd.arg2()), reinterpret_cast<GLfloat*>(const_cast<char *>(cmd.data().data()))
- );
- break;
- case glesv2debugger::Message_Function_glUniformMatrix4fv:
- dbg->hooks->gl.glUniformMatrix4fv(
- static_cast<GLint>(cmd.arg0()), static_cast<GLsizei>(cmd.arg1()),
- GLboolean(cmd.arg2()), reinterpret_cast<GLfloat*>(const_cast<char *>(cmd.data().data()))
- );
- break;
- case glesv2debugger::Message_Function_glUseProgram:
- dbg->hooks->gl.glUseProgram(
- static_cast<GLuint>(cmd.arg0()));
- break;
- case glesv2debugger::Message_Function_glValidateProgram:
- dbg->hooks->gl.glValidateProgram(
- static_cast<GLuint>(cmd.arg0()));
- break;
- case glesv2debugger::Message_Function_glVertexAttrib1f:
- dbg->hooks->gl.glVertexAttrib1f(
- static_cast<GLuint>(cmd.arg0()), static_cast<GLfloat>(cmd.arg1())
- );
- break;
- case glesv2debugger::Message_Function_glVertexAttrib1fv:
- dbg->hooks->gl.glVertexAttrib1fv(
- static_cast<GLuint>(cmd.arg0()), reinterpret_cast<GLfloat*>(const_cast<char *>(cmd.data().data()))
- );
- break;
- case glesv2debugger::Message_Function_glVertexAttrib2f:
- dbg->hooks->gl.glVertexAttrib2f(
- static_cast<GLuint>(cmd.arg0()), static_cast<GLfloat>(cmd.arg1()),
- static_cast<GLfloat>(cmd.arg2()));
- break;
- case glesv2debugger::Message_Function_glVertexAttrib2fv:
- dbg->hooks->gl.glVertexAttrib2fv(
- static_cast<GLuint>(cmd.arg0()), reinterpret_cast<GLfloat*>(const_cast<char *>(cmd.data().data()))
- );
- break;
- case glesv2debugger::Message_Function_glVertexAttrib3f:
- dbg->hooks->gl.glVertexAttrib3f(
- static_cast<GLuint>(cmd.arg0()), static_cast<GLfloat>(cmd.arg1()),
- static_cast<GLfloat>(cmd.arg2()), static_cast<GLfloat>(cmd.arg3())
- );
- break;
- case glesv2debugger::Message_Function_glVertexAttrib3fv:
- dbg->hooks->gl.glVertexAttrib3fv(
- static_cast<GLuint>(cmd.arg0()), reinterpret_cast<GLfloat*>(const_cast<char *>(cmd.data().data()))
- );
- break;
- case glesv2debugger::Message_Function_glVertexAttrib4f:
- dbg->hooks->gl.glVertexAttrib4f(
- static_cast<GLuint>(cmd.arg0()), static_cast<GLfloat>(cmd.arg1()),
- static_cast<GLfloat>(cmd.arg2()), static_cast<GLfloat>(cmd.arg3()),
- static_cast<GLfloat>(cmd.arg4()));
- break;
- case glesv2debugger::Message_Function_glVertexAttrib4fv:
- dbg->hooks->gl.glVertexAttrib4fv(
- static_cast<GLuint>(cmd.arg0()), reinterpret_cast<GLfloat*>(const_cast<char *>(cmd.data().data()))
- );
- break;
- case glesv2debugger::Message_Function_glVertexAttribPointer:
- ret = GenerateCall_glVertexAttribPointer(dbg, cmd, msg, prevRet);
- break;
- case glesv2debugger::Message_Function_glViewport:
- dbg->hooks->gl.glViewport(
- static_cast<GLint>(cmd.arg0()), static_cast<GLint>(cmd.arg1()),
- static_cast<GLsizei>(cmd.arg2()), static_cast<GLsizei>(cmd.arg3())
- );
- break;
- default:
- assert(0);
- }
- msg.set_time((systemTime(timeMode) - c0) * 1e-6f);
- msg.set_context_id(reinterpret_cast<int>(dbg));
- msg.set_function(cmd.function());
- msg.set_type(glesv2debugger::Message_Type_AfterGeneratedCall);
- return ret;
-}
-
-}; // name space android {
diff --git a/opengl/libs/GLES2_dbg/src/caller.h b/opengl/libs/GLES2_dbg/src/caller.h
deleted file mode 100644
index e8111b3..0000000
--- a/opengl/libs/GLES2_dbg/src/caller.h
+++ /dev/null
@@ -1,330 +0,0 @@
-/*
- ** Copyright 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.
- ** 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.
- */
-
-static const int * GenerateCall_glCompressedTexImage2D(DbgContext * const dbg,
- const glesv2debugger::Message & cmd,
- glesv2debugger::Message & msg, const int * const prevRet)
-{
- assert(0);
- return prevRet;
-}
-
-static const int * GenerateCall_glCompressedTexSubImage2D(DbgContext * const dbg,
- const glesv2debugger::Message & cmd,
- glesv2debugger::Message & msg, const int * const prevRet)
-{
- assert(0);
- return prevRet;
-}
-
-static const int * GenerateCall_glDrawElements(DbgContext * const dbg,
- const glesv2debugger::Message & cmd,
- glesv2debugger::Message & msg, const int * const prevRet)
-{
- assert(0);
- return prevRet;
-}
-
-static const int * GenerateCall_glGenBuffers(DbgContext * const dbg,
- const glesv2debugger::Message & cmd,
- glesv2debugger::Message & msg, const int * const prevRet)
-{
- assert(0);
- return prevRet;
-}
-
-static const int * GenerateCall_glGenFramebuffers(DbgContext * const dbg,
- const glesv2debugger::Message & cmd,
- glesv2debugger::Message & msg, const int * const prevRet)
-{
- assert(0);
- return prevRet;
-}
-
-static const int * GenerateCall_glGenRenderbuffers(DbgContext * const dbg,
- const glesv2debugger::Message & cmd,
- glesv2debugger::Message & msg, const int * const prevRet)
-{
- assert(0);
- return prevRet;
-}
-
-static const int * GenerateCall_glGenTextures(DbgContext * const dbg,
- const glesv2debugger::Message & cmd,
- glesv2debugger::Message & msg, const int * const prevRet)
-{
- assert(0);
- return prevRet;
-}
-
-static const int * GenerateCall_glGetActiveAttrib(DbgContext * const dbg,
- const glesv2debugger::Message & cmd,
- glesv2debugger::Message & msg, const int * const prevRet)
-{
- assert(0);
- return prevRet;
-}
-
-static const int * GenerateCall_glGetActiveUniform(DbgContext * const dbg,
- const glesv2debugger::Message & cmd,
- glesv2debugger::Message & msg, const int * const prevRet)
-{
- assert(0);
- return prevRet;
-}
-
-static const int * GenerateCall_glGetAttachedShaders(DbgContext * const dbg,
- const glesv2debugger::Message & cmd,
- glesv2debugger::Message & msg, const int * const prevRet)
-{
- assert(0);
- return prevRet;
-}
-
-static const int * GenerateCall_glGetBooleanv(DbgContext * const dbg,
- const glesv2debugger::Message & cmd,
- glesv2debugger::Message & msg, const int * const prevRet)
-{
- assert(0);
- return prevRet;
-}
-
-static const int * GenerateCall_glGetBufferParameteriv(DbgContext * const dbg,
- const glesv2debugger::Message & cmd,
- glesv2debugger::Message & msg, const int * const prevRet)
-{
- assert(0);
- return prevRet;
-}
-
-static const int * GenerateCall_glGetFloatv(DbgContext * const dbg,
- const glesv2debugger::Message & cmd,
- glesv2debugger::Message & msg, const int * const prevRet)
-{
- assert(0);
- return prevRet;
-}
-
-static const int * GenerateCall_glGetFramebufferAttachmentParameteriv(DbgContext * const dbg,
- const glesv2debugger::Message & cmd,
- glesv2debugger::Message & msg, const int * const prevRet)
-{
- assert(0);
- return prevRet;
-}
-
-static const int * GenerateCall_glGetIntegerv(DbgContext * const dbg,
- const glesv2debugger::Message & cmd,
- glesv2debugger::Message & msg, const int * const prevRet)
-{
- assert(0);
- return prevRet;
-}
-
-static const int * GenerateCall_glGetProgramiv(DbgContext * const dbg,
- const glesv2debugger::Message & cmd,
- glesv2debugger::Message & msg, const int * const prevRet)
-{
- GLint params = -1;
- dbg->hooks->gl.glGetProgramiv(cmd.arg0(), cmd.arg1(), ¶ms);
- msg.mutable_data()->append(reinterpret_cast<char *>(¶ms), sizeof(params));
- return prevRet;
-}
-
-static const int * GenerateCall_glGetProgramInfoLog(DbgContext * const dbg,
- const glesv2debugger::Message & cmd,
- glesv2debugger::Message & msg, const int * const prevRet)
-{
- const GLsizei bufSize = static_cast<GLsizei>(dbg->GetBufferSize());
- GLsizei length = -1;
- dbg->hooks->gl.glGetProgramInfoLog(cmd.arg0(), bufSize, &length, dbg->GetBuffer());
- msg.mutable_data()->append(dbg->GetBuffer(), length);
- return prevRet;
-}
-
-static const int * GenerateCall_glGetRenderbufferParameteriv(DbgContext * const dbg,
- const glesv2debugger::Message & cmd,
- glesv2debugger::Message & msg, const int * const prevRet)
-{
- assert(0);
- return prevRet;
-}
-
-static const int * GenerateCall_glGetShaderiv(DbgContext * const dbg,
- const glesv2debugger::Message & cmd,
- glesv2debugger::Message & msg, const int * const prevRet)
-{
- GLint params = -1;
- dbg->hooks->gl.glGetShaderiv(cmd.arg0(), cmd.arg1(), ¶ms);
- msg.mutable_data()->append(reinterpret_cast<char *>(¶ms), sizeof(params));
- return prevRet;
-}
-
-static const int * GenerateCall_glGetShaderInfoLog(DbgContext * const dbg,
- const glesv2debugger::Message & cmd,
- glesv2debugger::Message & msg, const int * const prevRet)
-{
- const GLsizei bufSize = static_cast<GLsizei>(dbg->GetBufferSize());
- GLsizei length = -1;
- dbg->hooks->gl.glGetShaderInfoLog(cmd.arg0(), bufSize, &length, dbg->GetBuffer());
- msg.mutable_data()->append(dbg->GetBuffer(), length);
- return prevRet;
-}
-
-static const int * GenerateCall_glGetShaderPrecisionFormat(DbgContext * const dbg,
- const glesv2debugger::Message & cmd,
- glesv2debugger::Message & msg, const int * const prevRet)
-{
- assert(0);
- return prevRet;
-}
-
-static const int * GenerateCall_glGetShaderSource(DbgContext * const dbg,
- const glesv2debugger::Message & cmd,
- glesv2debugger::Message & msg, const int * const prevRet)
-{
- assert(0);
- return prevRet;
-}
-
-static const int * GenerateCall_glGetString(DbgContext * const dbg,
- const glesv2debugger::Message & cmd,
- glesv2debugger::Message & msg, const int * const prevRet)
-{
- assert(0);
- return prevRet;
-}
-
-static const int * GenerateCall_glGetTexParameterfv(DbgContext * const dbg,
- const glesv2debugger::Message & cmd,
- glesv2debugger::Message & msg, const int * const prevRet)
-{
- assert(0);
- return prevRet;
-}
-
-static const int * GenerateCall_glGetTexParameteriv(DbgContext * const dbg,
- const glesv2debugger::Message & cmd,
- glesv2debugger::Message & msg, const int * const prevRet)
-{
- assert(0);
- return prevRet;
-}
-
-static const int * GenerateCall_glGetUniformfv(DbgContext * const dbg,
- const glesv2debugger::Message & cmd,
- glesv2debugger::Message & msg, const int * const prevRet)
-{
- assert(0);
- return prevRet;
-}
-
-static const int * GenerateCall_glGetUniformiv(DbgContext * const dbg,
- const glesv2debugger::Message & cmd,
- glesv2debugger::Message & msg, const int * const prevRet)
-{
- assert(0);
- return prevRet;
-}
-
-static const int * GenerateCall_glGetVertexAttribfv(DbgContext * const dbg,
- const glesv2debugger::Message & cmd,
- glesv2debugger::Message & msg, const int * const prevRet)
-{
- assert(0);
- return prevRet;
-}
-
-static const int * GenerateCall_glGetVertexAttribiv(DbgContext * const dbg,
- const glesv2debugger::Message & cmd,
- glesv2debugger::Message & msg, const int * const prevRet)
-{
- assert(0);
- return prevRet;
-}
-
-static const int * GenerateCall_glGetVertexAttribPointerv(DbgContext * const dbg,
- const glesv2debugger::Message & cmd,
- glesv2debugger::Message & msg, const int * const prevRet)
-{
- assert(0);
- return prevRet;
-}
-
-static const int * GenerateCall_glReadPixels(DbgContext * const dbg,
- const glesv2debugger::Message & cmd,
- glesv2debugger::Message & msg, const int * const prevRet)
-{
- assert(0);
- return prevRet;
-}
-
-static const int * GenerateCall_glShaderBinary(DbgContext * const dbg,
- const glesv2debugger::Message & cmd,
- glesv2debugger::Message & msg, const int * const prevRet)
-{
- assert(0);
- return prevRet;
-}
-
-static const int * GenerateCall_glShaderSource(DbgContext * const dbg,
- const glesv2debugger::Message & cmd,
- glesv2debugger::Message & msg, const int * const prevRet)
-{
- const char * string = cmd.data().data();
- dbg->hooks->gl.glShaderSource(cmd.arg0(), 1, &string, NULL);
- return prevRet;
-}
-
-static const int * GenerateCall_glTexImage2D(DbgContext * const dbg,
- const glesv2debugger::Message & cmd,
- glesv2debugger::Message & msg, const int * const prevRet)
-{
- assert(0);
- return prevRet;
-}
-
-static const int * GenerateCall_glTexParameterfv(DbgContext * const dbg,
- const glesv2debugger::Message & cmd,
- glesv2debugger::Message & msg, const int * const prevRet)
-{
- assert(0);
- return prevRet;
-}
-
-static const int * GenerateCall_glTexParameteriv(DbgContext * const dbg,
- const glesv2debugger::Message & cmd,
- glesv2debugger::Message & msg, const int * const prevRet)
-{
- assert(0);
- return prevRet;
-}
-
-static const int * GenerateCall_glTexSubImage2D(DbgContext * const dbg,
- const glesv2debugger::Message & cmd,
- glesv2debugger::Message & msg, const int * const prevRet)
-{
- assert(0);
- return prevRet;
-}
-
-static const int * GenerateCall_glVertexAttribPointer(DbgContext * const dbg,
- const glesv2debugger::Message & cmd,
- glesv2debugger::Message & msg, const int * const prevRet)
-{
- assert(0);
- return prevRet;
-}
diff --git a/opengl/libs/GLES2_dbg/src/dbgcontext.cpp b/opengl/libs/GLES2_dbg/src/dbgcontext.cpp
deleted file mode 100644
index 7bbaa18..0000000
--- a/opengl/libs/GLES2_dbg/src/dbgcontext.cpp
+++ /dev/null
@@ -1,427 +0,0 @@
-/*
- ** Copyright 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.
- ** 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.
- */
-
-#include "header.h"
-
-extern "C" {
-#include "liblzf/lzf.h"
-}
-
-namespace android {
-
-static pthread_key_t dbgEGLThreadLocalStorageKey = -1;
-static pthread_mutex_t gThreadLocalStorageKeyMutex = PTHREAD_MUTEX_INITIALIZER;
-
-DbgContext * getDbgContextThreadSpecific() {
- return (DbgContext*)pthread_getspecific(dbgEGLThreadLocalStorageKey);
-}
-
-DbgContext::DbgContext(const unsigned version, const gl_hooks_t * const hooks,
- const unsigned MAX_VERTEX_ATTRIBS)
- : lzf_buf(NULL), lzf_readIndex(0), lzf_refSize(0), lzf_refBufSize(0)
- , version(version), hooks(hooks)
- , MAX_VERTEX_ATTRIBS(MAX_VERTEX_ATTRIBS)
- , readBytesPerPixel(4)
- , captureSwap(0), captureDraw(0)
- , vertexAttribs(new VertexAttrib[MAX_VERTEX_ATTRIBS])
- , hasNonVBOAttribs(false), indexBuffers(NULL), indexBuffer(NULL)
- , program(0), maxAttrib(0)
-{
- lzf_ref[0] = lzf_ref[1] = NULL;
- for (unsigned i = 0; i < MAX_VERTEX_ATTRIBS; i++)
- vertexAttribs[i] = VertexAttrib();
- memset(&expectResponse, 0, sizeof(expectResponse));
-}
-
-DbgContext::~DbgContext()
-{
- delete vertexAttribs;
- free(lzf_buf);
- free(lzf_ref[0]);
- free(lzf_ref[1]);
-}
-
-DbgContext* CreateDbgContext(const unsigned version, const gl_hooks_t * const hooks)
-{
- pthread_mutex_lock(&gThreadLocalStorageKeyMutex);
- if (dbgEGLThreadLocalStorageKey == -1)
- pthread_key_create(&dbgEGLThreadLocalStorageKey, NULL);
- pthread_mutex_unlock(&gThreadLocalStorageKeyMutex);
-
- assert(version < 2);
- assert(GL_NO_ERROR == hooks->gl.glGetError());
- GLint MAX_VERTEX_ATTRIBS = 0;
- hooks->gl.glGetIntegerv(GL_MAX_VERTEX_ATTRIBS, &MAX_VERTEX_ATTRIBS);
- DbgContext* dbg = new DbgContext(version, hooks, MAX_VERTEX_ATTRIBS);
- glesv2debugger::Message msg, cmd;
- msg.set_context_id(reinterpret_cast<int>(dbg));
- msg.set_expect_response(false);
- msg.set_type(msg.Response);
- msg.set_function(msg.SETPROP);
- msg.set_prop(msg.GLConstant);
- msg.set_arg0(GL_MAX_VERTEX_ATTRIBS);
- msg.set_arg1(MAX_VERTEX_ATTRIBS);
- Send(msg, cmd);
-
- GLint MAX_COMBINED_TEXTURE_IMAGE_UNITS = 0;
- hooks->gl.glGetIntegerv(GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS, &MAX_COMBINED_TEXTURE_IMAGE_UNITS);
- msg.set_arg0(GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS);
- msg.set_arg1(MAX_COMBINED_TEXTURE_IMAGE_UNITS);
- Send(msg, cmd);
-
- pthread_setspecific(dbgEGLThreadLocalStorageKey, dbg);
- return dbg;
-}
-
-void dbgReleaseThread() {
- delete getDbgContextThreadSpecific();
-}
-
-unsigned GetBytesPerPixel(const GLenum format, const GLenum type)
-{
- switch (type) {
- case GL_UNSIGNED_SHORT_5_6_5:
- case GL_UNSIGNED_SHORT_4_4_4_4:
- case GL_UNSIGNED_SHORT_5_5_5_1:
- return 2;
- case GL_UNSIGNED_BYTE:
- break;
- default:
- ALOGE("GetBytesPerPixel: unknown type %x", type);
- }
-
- switch (format) {
- case GL_ALPHA:
- case GL_LUMINANCE:
- return 1;
- case GL_LUMINANCE_ALPHA:
- return 2;
- case GL_RGB:
- return 3;
- case GL_RGBA:
- case 0x80E1: // GL_BGRA_EXT
- return 4;
- default:
- ALOGE("GetBytesPerPixel: unknown format %x", format);
- }
-
- return 1; // in doubt...
-}
-
-void DbgContext::Fetch(const unsigned index, std::string * const data) const
-{
- // VBO data is already on client, just send user pointer data
- for (unsigned i = 0; i < maxAttrib; i++) {
- if (!vertexAttribs[i].enabled)
- continue;
- if (vertexAttribs[i].buffer > 0)
- continue;
- const char * ptr = (const char *)vertexAttribs[i].ptr;
- ptr += index * vertexAttribs[i].stride;
- data->append(ptr, vertexAttribs[i].elemSize);
- }
-}
-
-void DbgContext::Compress(const void * in_data, unsigned int in_len,
- std::string * const outStr)
-{
- if (!lzf_buf)
- lzf_buf = (char *)malloc(LZF_CHUNK_SIZE);
- assert(lzf_buf);
- const uint32_t totalDecompSize = in_len;
- outStr->append((const char *)&totalDecompSize, sizeof(totalDecompSize));
- for (unsigned int i = 0; i < in_len; i += LZF_CHUNK_SIZE) {
- uint32_t chunkSize = LZF_CHUNK_SIZE;
- if (i + LZF_CHUNK_SIZE > in_len)
- chunkSize = in_len - i;
- const uint32_t compSize = lzf_compress((const char *)in_data + i, chunkSize,
- lzf_buf, LZF_CHUNK_SIZE);
- outStr->append((const char *)&chunkSize, sizeof(chunkSize));
- outStr->append((const char *)&compSize, sizeof(compSize));
- if (compSize > 0)
- outStr->append(lzf_buf, compSize);
- else // compressed chunk bigger than LZF_CHUNK_SIZE (and uncompressed)
- outStr->append((const char *)in_data + i, chunkSize);
- }
-}
-
-unsigned char * DbgContext::Decompress(const void * in, const unsigned int inLen,
- unsigned int * const outLen)
-{
- assert(inLen > 4 * 3);
- if (inLen < 4 * 3)
- return NULL;
- *outLen = *(uint32_t *)in;
- unsigned char * const out = (unsigned char *)malloc(*outLen);
- unsigned int outPos = 0;
- const unsigned char * const end = (const unsigned char *)in + inLen;
- for (const unsigned char * inData = (const unsigned char *)in + 4; inData < end; ) {
- const uint32_t chunkOut = *(uint32_t *)inData;
- inData += 4;
- const uint32_t chunkIn = *(uint32_t *)inData;
- inData += 4;
- if (chunkIn > 0) {
- assert(inData + chunkIn <= end);
- assert(outPos + chunkOut <= *outLen);
- outPos += lzf_decompress(inData, chunkIn, out + outPos, chunkOut);
- inData += chunkIn;
- } else {
- assert(inData + chunkOut <= end);
- assert(outPos + chunkOut <= *outLen);
- memcpy(out + outPos, inData, chunkOut);
- inData += chunkOut;
- outPos += chunkOut;
- }
- }
- return out;
-}
-
-void * DbgContext::GetReadPixelsBuffer(const unsigned size)
-{
- if (lzf_refBufSize < size + 8) {
- lzf_refBufSize = size + 8;
- lzf_ref[0] = (unsigned *)realloc(lzf_ref[0], lzf_refBufSize);
- assert(lzf_ref[0]);
- memset(lzf_ref[0], 0, lzf_refBufSize);
- lzf_ref[1] = (unsigned *)realloc(lzf_ref[1], lzf_refBufSize);
- assert(lzf_ref[1]);
- memset(lzf_ref[1], 0, lzf_refBufSize);
- }
- if (lzf_refSize != size) // need to clear unused ref to maintain consistency
- { // since ref and src are swapped each time
- memset((char *)lzf_ref[0] + lzf_refSize, 0, lzf_refBufSize - lzf_refSize);
- memset((char *)lzf_ref[1] + lzf_refSize, 0, lzf_refBufSize - lzf_refSize);
- }
- lzf_refSize = size;
- lzf_readIndex ^= 1;
- return lzf_ref[lzf_readIndex];
-}
-
-void DbgContext::CompressReadPixelBuffer(std::string * const outStr)
-{
- assert(lzf_ref[0] && lzf_ref[1]);
- unsigned * const ref = lzf_ref[lzf_readIndex ^ 1];
- unsigned * const src = lzf_ref[lzf_readIndex];
- for (unsigned i = 0; i < lzf_refSize / sizeof(*ref) + 1; i++)
- ref[i] ^= src[i];
- Compress(ref, lzf_refSize, outStr);
-}
-
-char * DbgContext::GetBuffer()
-{
- if (!lzf_buf)
- lzf_buf = (char *)malloc(LZF_CHUNK_SIZE);
- assert(lzf_buf);
- return lzf_buf;
-}
-
-unsigned int DbgContext::GetBufferSize()
-{
- if (!lzf_buf)
- lzf_buf = (char *)malloc(LZF_CHUNK_SIZE);
- assert(lzf_buf);
- if (lzf_buf)
- return LZF_CHUNK_SIZE;
- else
- return 0;
-}
-
-void DbgContext::glUseProgram(GLuint program)
-{
- while (GLenum error = hooks->gl.glGetError())
- ALOGD("DbgContext::glUseProgram(%u): before glGetError() = 0x%.4X",
- program, error);
- this->program = program;
- maxAttrib = 0;
- if (program == 0)
- return;
- GLint activeAttributes = 0;
- hooks->gl.glGetProgramiv(program, GL_ACTIVE_ATTRIBUTES, &activeAttributes);
- maxAttrib = 0;
- GLint maxNameLen = -1;
- hooks->gl.glGetProgramiv(program, GL_ACTIVE_ATTRIBUTE_MAX_LENGTH, &maxNameLen);
- char * name = new char [maxNameLen + 1];
- name[maxNameLen] = 0;
- // find total number of attribute slots used
- for (unsigned i = 0; i < activeAttributes; i++) {
- GLint size = -1;
- GLenum type = -1;
- hooks->gl.glGetActiveAttrib(program, i, maxNameLen + 1, NULL, &size, &type, name);
- GLint slot = hooks->gl.glGetAttribLocation(program, name);
- assert(slot >= 0);
- switch (type) {
- case GL_FLOAT:
- case GL_FLOAT_VEC2:
- case GL_FLOAT_VEC3:
- case GL_FLOAT_VEC4:
- slot += size;
- break;
- case GL_FLOAT_MAT2:
- slot += size * 2;
- break;
- case GL_FLOAT_MAT3:
- slot += size * 3;
- break;
- case GL_FLOAT_MAT4:
- slot += size * 4;
- break;
- default:
- assert(0);
- }
- if (slot > maxAttrib)
- maxAttrib = slot;
- }
- delete name;
- while (GLenum error = hooks->gl.glGetError())
- ALOGD("DbgContext::glUseProgram(%u): after glGetError() = 0x%.4X",
- program, error);
-}
-
-static bool HasNonVBOAttribs(const DbgContext * const ctx)
-{
- bool need = false;
- for (unsigned i = 0; !need && i < ctx->maxAttrib; i++)
- if (ctx->vertexAttribs[i].enabled && ctx->vertexAttribs[i].buffer == 0)
- need = true;
- return need;
-}
-
-void DbgContext::glVertexAttribPointer(GLuint indx, GLint size, GLenum type,
- GLboolean normalized, GLsizei stride, const GLvoid* ptr)
-{
- assert(GL_NO_ERROR == hooks->gl.glGetError());
- assert(indx < MAX_VERTEX_ATTRIBS);
- vertexAttribs[indx].size = size;
- vertexAttribs[indx].type = type;
- vertexAttribs[indx].normalized = normalized;
- switch (type) {
- case GL_FLOAT:
- vertexAttribs[indx].elemSize = sizeof(GLfloat) * size;
- break;
- case GL_INT:
- case GL_UNSIGNED_INT:
- vertexAttribs[indx].elemSize = sizeof(GLint) * size;
- break;
- case GL_SHORT:
- case GL_UNSIGNED_SHORT:
- vertexAttribs[indx].elemSize = sizeof(GLshort) * size;
- break;
- case GL_BYTE:
- case GL_UNSIGNED_BYTE:
- vertexAttribs[indx].elemSize = sizeof(GLbyte) * size;
- break;
- default:
- assert(0);
- }
- if (0 == stride)
- stride = vertexAttribs[indx].elemSize;
- vertexAttribs[indx].stride = stride;
- vertexAttribs[indx].ptr = ptr;
- hooks->gl.glGetVertexAttribiv(indx, GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING,
- (GLint *)&vertexAttribs[indx].buffer);
- hasNonVBOAttribs = HasNonVBOAttribs(this);
-}
-
-void DbgContext::glEnableVertexAttribArray(GLuint index)
-{
- if (index >= MAX_VERTEX_ATTRIBS)
- return;
- vertexAttribs[index].enabled = true;
- hasNonVBOAttribs = HasNonVBOAttribs(this);
-}
-
-void DbgContext::glDisableVertexAttribArray(GLuint index)
-{
- if (index >= MAX_VERTEX_ATTRIBS)
- return;
- vertexAttribs[index].enabled = false;
- hasNonVBOAttribs = HasNonVBOAttribs(this);
-}
-
-void DbgContext::glBindBuffer(GLenum target, GLuint buffer)
-{
- if (GL_ELEMENT_ARRAY_BUFFER != target)
- return;
- if (0 == buffer) {
- indexBuffer = NULL;
- return;
- }
- VBO * b = indexBuffers;
- indexBuffer = NULL;
- while (b) {
- if (b->name == buffer) {
- assert(GL_ELEMENT_ARRAY_BUFFER == b->target);
- indexBuffer = b;
- break;
- }
- b = b->next;
- }
- if (!indexBuffer)
- indexBuffer = indexBuffers = new VBO(buffer, target, indexBuffers);
-}
-
-void DbgContext::glBufferData(GLenum target, GLsizeiptr size, const GLvoid* data, GLenum usage)
-{
- if (GL_ELEMENT_ARRAY_BUFFER != target)
- return;
- assert(indexBuffer);
- assert(size >= 0);
- indexBuffer->size = size;
- indexBuffer->data = realloc(indexBuffer->data, size);
- memcpy(indexBuffer->data, data, size);
-}
-
-void DbgContext::glBufferSubData(GLenum target, GLintptr offset, GLsizeiptr size, const GLvoid* data)
-{
- if (GL_ELEMENT_ARRAY_BUFFER != target)
- return;
- assert(indexBuffer);
- assert(size >= 0);
- assert(offset >= 0);
- assert(offset + size <= indexBuffer->size);
- memcpy((char *)indexBuffer->data + offset, data, size);
-}
-
-void DbgContext::glDeleteBuffers(GLsizei n, const GLuint *buffers)
-{
- for (unsigned i = 0; i < n; i++) {
- for (unsigned j = 0; j < MAX_VERTEX_ATTRIBS; j++)
- if (buffers[i] == vertexAttribs[j].buffer) {
- vertexAttribs[j].buffer = 0;
- vertexAttribs[j].enabled = false;
- }
- VBO * b = indexBuffers, * previous = NULL;
- while (b) {
- if (b->name == buffers[i]) {
- assert(GL_ELEMENT_ARRAY_BUFFER == b->target);
- if (indexBuffer == b)
- indexBuffer = NULL;
- if (previous)
- previous->next = b->next;
- else
- indexBuffers = b->next;
- free(b->data);
- delete b;
- break;
- }
- previous = b;
- b = b->next;
- }
- }
- hasNonVBOAttribs = HasNonVBOAttribs(this);
-}
-
-}; // namespace android
diff --git a/opengl/libs/GLES2_dbg/src/debugger_message.pb.cpp b/opengl/libs/GLES2_dbg/src/debugger_message.pb.cpp
deleted file mode 100644
index 50f70f7..0000000
--- a/opengl/libs/GLES2_dbg/src/debugger_message.pb.cpp
+++ /dev/null
@@ -1,1455 +0,0 @@
-// Generated by the protocol buffer compiler. DO NOT EDIT!
-
-#define INTERNAL_SUPPRESS_PROTOBUF_FIELD_DEPRECATION
-#include "debugger_message.pb.h"
-#include <google/protobuf/stubs/once.h>
-#include <google/protobuf/io/coded_stream.h>
-#include <google/protobuf/wire_format_lite_inl.h>
-// @@protoc_insertion_point(includes)
-
-namespace com {
-namespace android {
-namespace glesv2debugger {
-
-void protobuf_ShutdownFile_debugger_5fmessage_2eproto() {
- delete Message::default_instance_;
-}
-
-void protobuf_AddDesc_debugger_5fmessage_2eproto() {
- static bool already_here = false;
- if (already_here) return;
- already_here = true;
- GOOGLE_PROTOBUF_VERIFY_VERSION;
-
- Message::default_instance_ = new Message();
- Message::default_instance_->InitAsDefaultInstance();
- ::google::protobuf::internal::OnShutdown(&protobuf_ShutdownFile_debugger_5fmessage_2eproto);
-}
-
-// Force AddDescriptors() to be called at static initialization time.
-struct StaticDescriptorInitializer_debugger_5fmessage_2eproto {
- StaticDescriptorInitializer_debugger_5fmessage_2eproto() {
- protobuf_AddDesc_debugger_5fmessage_2eproto();
- }
-} static_descriptor_initializer_debugger_5fmessage_2eproto_;
-
-
-// ===================================================================
-
-bool Message_Function_IsValid(int value) {
- switch(value) {
- case 0:
- case 1:
- case 2:
- case 3:
- case 4:
- case 5:
- case 6:
- case 7:
- case 8:
- case 9:
- case 10:
- case 11:
- case 12:
- case 13:
- case 14:
- case 15:
- case 16:
- case 17:
- case 18:
- case 19:
- case 20:
- case 21:
- case 22:
- case 23:
- case 24:
- case 25:
- case 26:
- case 27:
- case 28:
- case 29:
- case 30:
- case 31:
- case 32:
- case 33:
- case 34:
- case 35:
- case 36:
- case 37:
- case 38:
- case 39:
- case 40:
- case 41:
- case 42:
- case 43:
- case 44:
- case 45:
- case 46:
- case 47:
- case 48:
- case 49:
- case 50:
- case 51:
- case 52:
- case 53:
- case 54:
- case 55:
- case 56:
- case 57:
- case 58:
- case 59:
- case 60:
- case 61:
- case 62:
- case 63:
- case 64:
- case 65:
- case 66:
- case 67:
- case 68:
- case 69:
- case 70:
- case 71:
- case 72:
- case 73:
- case 74:
- case 75:
- case 76:
- case 77:
- case 78:
- case 79:
- case 80:
- case 81:
- case 82:
- case 83:
- case 84:
- case 85:
- case 86:
- case 87:
- case 88:
- case 89:
- case 90:
- case 91:
- case 92:
- case 93:
- case 94:
- case 95:
- case 96:
- case 97:
- case 98:
- case 99:
- case 100:
- case 101:
- case 102:
- case 103:
- case 104:
- case 105:
- case 106:
- case 107:
- case 108:
- case 109:
- case 110:
- case 111:
- case 112:
- case 113:
- case 114:
- case 115:
- case 116:
- case 117:
- case 118:
- case 119:
- case 120:
- case 121:
- case 122:
- case 123:
- case 124:
- case 125:
- case 126:
- case 127:
- case 128:
- case 129:
- case 130:
- case 131:
- case 132:
- case 133:
- case 134:
- case 135:
- case 136:
- case 137:
- case 138:
- case 139:
- case 140:
- case 141:
- case 142:
- case 143:
- case 144:
- case 145:
- case 146:
- case 147:
- case 148:
- case 149:
- case 150:
- case 151:
- case 152:
- case 153:
- case 154:
- case 155:
- case 156:
- case 157:
- case 158:
- case 159:
- case 160:
- case 161:
- case 162:
- case 163:
- case 164:
- case 165:
- case 166:
- case 167:
- case 168:
- case 169:
- case 170:
- case 171:
- case 172:
- case 173:
- case 174:
- case 175:
- case 176:
- case 177:
- case 178:
- case 179:
- case 180:
- case 181:
- case 182:
- case 183:
- case 184:
- case 185:
- case 186:
- case 187:
- case 188:
- case 189:
- case 190:
- return true;
- default:
- return false;
- }
-}
-
-#ifndef _MSC_VER
-const Message_Function Message::glActiveTexture;
-const Message_Function Message::glAttachShader;
-const Message_Function Message::glBindAttribLocation;
-const Message_Function Message::glBindBuffer;
-const Message_Function Message::glBindFramebuffer;
-const Message_Function Message::glBindRenderbuffer;
-const Message_Function Message::glBindTexture;
-const Message_Function Message::glBlendColor;
-const Message_Function Message::glBlendEquation;
-const Message_Function Message::glBlendEquationSeparate;
-const Message_Function Message::glBlendFunc;
-const Message_Function Message::glBlendFuncSeparate;
-const Message_Function Message::glBufferData;
-const Message_Function Message::glBufferSubData;
-const Message_Function Message::glCheckFramebufferStatus;
-const Message_Function Message::glClear;
-const Message_Function Message::glClearColor;
-const Message_Function Message::glClearDepthf;
-const Message_Function Message::glClearStencil;
-const Message_Function Message::glColorMask;
-const Message_Function Message::glCompileShader;
-const Message_Function Message::glCompressedTexImage2D;
-const Message_Function Message::glCompressedTexSubImage2D;
-const Message_Function Message::glCopyTexImage2D;
-const Message_Function Message::glCopyTexSubImage2D;
-const Message_Function Message::glCreateProgram;
-const Message_Function Message::glCreateShader;
-const Message_Function Message::glCullFace;
-const Message_Function Message::glDeleteBuffers;
-const Message_Function Message::glDeleteFramebuffers;
-const Message_Function Message::glDeleteProgram;
-const Message_Function Message::glDeleteRenderbuffers;
-const Message_Function Message::glDeleteShader;
-const Message_Function Message::glDeleteTextures;
-const Message_Function Message::glDepthFunc;
-const Message_Function Message::glDepthMask;
-const Message_Function Message::glDepthRangef;
-const Message_Function Message::glDetachShader;
-const Message_Function Message::glDisable;
-const Message_Function Message::glDisableVertexAttribArray;
-const Message_Function Message::glDrawArrays;
-const Message_Function Message::glDrawElements;
-const Message_Function Message::glEnable;
-const Message_Function Message::glEnableVertexAttribArray;
-const Message_Function Message::glFinish;
-const Message_Function Message::glFlush;
-const Message_Function Message::glFramebufferRenderbuffer;
-const Message_Function Message::glFramebufferTexture2D;
-const Message_Function Message::glFrontFace;
-const Message_Function Message::glGenBuffers;
-const Message_Function Message::glGenerateMipmap;
-const Message_Function Message::glGenFramebuffers;
-const Message_Function Message::glGenRenderbuffers;
-const Message_Function Message::glGenTextures;
-const Message_Function Message::glGetActiveAttrib;
-const Message_Function Message::glGetActiveUniform;
-const Message_Function Message::glGetAttachedShaders;
-const Message_Function Message::glGetAttribLocation;
-const Message_Function Message::glGetBooleanv;
-const Message_Function Message::glGetBufferParameteriv;
-const Message_Function Message::glGetError;
-const Message_Function Message::glGetFloatv;
-const Message_Function Message::glGetFramebufferAttachmentParameteriv;
-const Message_Function Message::glGetIntegerv;
-const Message_Function Message::glGetProgramiv;
-const Message_Function Message::glGetProgramInfoLog;
-const Message_Function Message::glGetRenderbufferParameteriv;
-const Message_Function Message::glGetShaderiv;
-const Message_Function Message::glGetShaderInfoLog;
-const Message_Function Message::glGetShaderPrecisionFormat;
-const Message_Function Message::glGetShaderSource;
-const Message_Function Message::glGetString;
-const Message_Function Message::glGetTexParameterfv;
-const Message_Function Message::glGetTexParameteriv;
-const Message_Function Message::glGetUniformfv;
-const Message_Function Message::glGetUniformiv;
-const Message_Function Message::glGetUniformLocation;
-const Message_Function Message::glGetVertexAttribfv;
-const Message_Function Message::glGetVertexAttribiv;
-const Message_Function Message::glGetVertexAttribPointerv;
-const Message_Function Message::glHint;
-const Message_Function Message::glIsBuffer;
-const Message_Function Message::glIsEnabled;
-const Message_Function Message::glIsFramebuffer;
-const Message_Function Message::glIsProgram;
-const Message_Function Message::glIsRenderbuffer;
-const Message_Function Message::glIsShader;
-const Message_Function Message::glIsTexture;
-const Message_Function Message::glLineWidth;
-const Message_Function Message::glLinkProgram;
-const Message_Function Message::glPixelStorei;
-const Message_Function Message::glPolygonOffset;
-const Message_Function Message::glReadPixels;
-const Message_Function Message::glReleaseShaderCompiler;
-const Message_Function Message::glRenderbufferStorage;
-const Message_Function Message::glSampleCoverage;
-const Message_Function Message::glScissor;
-const Message_Function Message::glShaderBinary;
-const Message_Function Message::glShaderSource;
-const Message_Function Message::glStencilFunc;
-const Message_Function Message::glStencilFuncSeparate;
-const Message_Function Message::glStencilMask;
-const Message_Function Message::glStencilMaskSeparate;
-const Message_Function Message::glStencilOp;
-const Message_Function Message::glStencilOpSeparate;
-const Message_Function Message::glTexImage2D;
-const Message_Function Message::glTexParameterf;
-const Message_Function Message::glTexParameterfv;
-const Message_Function Message::glTexParameteri;
-const Message_Function Message::glTexParameteriv;
-const Message_Function Message::glTexSubImage2D;
-const Message_Function Message::glUniform1f;
-const Message_Function Message::glUniform1fv;
-const Message_Function Message::glUniform1i;
-const Message_Function Message::glUniform1iv;
-const Message_Function Message::glUniform2f;
-const Message_Function Message::glUniform2fv;
-const Message_Function Message::glUniform2i;
-const Message_Function Message::glUniform2iv;
-const Message_Function Message::glUniform3f;
-const Message_Function Message::glUniform3fv;
-const Message_Function Message::glUniform3i;
-const Message_Function Message::glUniform3iv;
-const Message_Function Message::glUniform4f;
-const Message_Function Message::glUniform4fv;
-const Message_Function Message::glUniform4i;
-const Message_Function Message::glUniform4iv;
-const Message_Function Message::glUniformMatrix2fv;
-const Message_Function Message::glUniformMatrix3fv;
-const Message_Function Message::glUniformMatrix4fv;
-const Message_Function Message::glUseProgram;
-const Message_Function Message::glValidateProgram;
-const Message_Function Message::glVertexAttrib1f;
-const Message_Function Message::glVertexAttrib1fv;
-const Message_Function Message::glVertexAttrib2f;
-const Message_Function Message::glVertexAttrib2fv;
-const Message_Function Message::glVertexAttrib3f;
-const Message_Function Message::glVertexAttrib3fv;
-const Message_Function Message::glVertexAttrib4f;
-const Message_Function Message::glVertexAttrib4fv;
-const Message_Function Message::glVertexAttribPointer;
-const Message_Function Message::glViewport;
-const Message_Function Message::eglGetDisplay;
-const Message_Function Message::eglInitialize;
-const Message_Function Message::eglTerminate;
-const Message_Function Message::eglGetConfigs;
-const Message_Function Message::eglChooseConfig;
-const Message_Function Message::eglGetConfigAttrib;
-const Message_Function Message::eglCreateWindowSurface;
-const Message_Function Message::eglCreatePixmapSurface;
-const Message_Function Message::eglCreatePbufferSurface;
-const Message_Function Message::eglDestroySurface;
-const Message_Function Message::eglQuerySurface;
-const Message_Function Message::eglCreateContext;
-const Message_Function Message::eglDestroyContext;
-const Message_Function Message::eglMakeCurrent;
-const Message_Function Message::eglGetCurrentContext;
-const Message_Function Message::eglGetCurrentSurface;
-const Message_Function Message::eglGetCurrentDisplay;
-const Message_Function Message::eglQueryContext;
-const Message_Function Message::eglWaitGL;
-const Message_Function Message::eglWaitNative;
-const Message_Function Message::eglSwapBuffers;
-const Message_Function Message::eglCopyBuffers;
-const Message_Function Message::eglGetError;
-const Message_Function Message::eglQueryString;
-const Message_Function Message::eglGetProcAddress;
-const Message_Function Message::eglSurfaceAttrib;
-const Message_Function Message::eglBindTexImage;
-const Message_Function Message::eglReleaseTexImage;
-const Message_Function Message::eglSwapInterval;
-const Message_Function Message::eglBindAPI;
-const Message_Function Message::eglQueryAPI;
-const Message_Function Message::eglWaitClient;
-const Message_Function Message::eglReleaseThread;
-const Message_Function Message::eglCreatePbufferFromClientBuffer;
-const Message_Function Message::eglLockSurfaceKHR;
-const Message_Function Message::eglUnlockSurfaceKHR;
-const Message_Function Message::eglCreateImageKHR;
-const Message_Function Message::eglDestroyImageKHR;
-const Message_Function Message::eglCreateSyncKHR;
-const Message_Function Message::eglDestroySyncKHR;
-const Message_Function Message::eglClientWaitSyncKHR;
-const Message_Function Message::eglGetSyncAttribKHR;
-const Message_Function Message::eglSetSwapRectangleANDROID;
-const Message_Function Message::eglGetRenderBufferANDROID;
-const Message_Function Message::ACK;
-const Message_Function Message::NEG;
-const Message_Function Message::CONTINUE;
-const Message_Function Message::SKIP;
-const Message_Function Message::SETPROP;
-const Message_Function Message::Function_MIN;
-const Message_Function Message::Function_MAX;
-const int Message::Function_ARRAYSIZE;
-#endif // _MSC_VER
-bool Message_Type_IsValid(int value) {
- switch(value) {
- case 0:
- case 1:
- case 2:
- case 3:
- case 4:
- return true;
- default:
- return false;
- }
-}
-
-#ifndef _MSC_VER
-const Message_Type Message::BeforeCall;
-const Message_Type Message::AfterCall;
-const Message_Type Message::AfterGeneratedCall;
-const Message_Type Message::Response;
-const Message_Type Message::CompleteCall;
-const Message_Type Message::Type_MIN;
-const Message_Type Message::Type_MAX;
-const int Message::Type_ARRAYSIZE;
-#endif // _MSC_VER
-bool Message_DataType_IsValid(int value) {
- switch(value) {
- case 0:
- case 1:
- return true;
- default:
- return false;
- }
-}
-
-#ifndef _MSC_VER
-const Message_DataType Message::ReferencedImage;
-const Message_DataType Message::NonreferencedImage;
-const Message_DataType Message::DataType_MIN;
-const Message_DataType Message::DataType_MAX;
-const int Message::DataType_ARRAYSIZE;
-#endif // _MSC_VER
-bool Message_Prop_IsValid(int value) {
- switch(value) {
- case 0:
- case 1:
- case 2:
- case 3:
- case 4:
- return true;
- default:
- return false;
- }
-}
-
-#ifndef _MSC_VER
-const Message_Prop Message::CaptureDraw;
-const Message_Prop Message::TimeMode;
-const Message_Prop Message::ExpectResponse;
-const Message_Prop Message::CaptureSwap;
-const Message_Prop Message::GLConstant;
-const Message_Prop Message::Prop_MIN;
-const Message_Prop Message::Prop_MAX;
-const int Message::Prop_ARRAYSIZE;
-#endif // _MSC_VER
-const ::std::string Message::_default_data_;
-#ifndef _MSC_VER
-const int Message::kContextIdFieldNumber;
-const int Message::kFunctionFieldNumber;
-const int Message::kTypeFieldNumber;
-const int Message::kExpectResponseFieldNumber;
-const int Message::kRetFieldNumber;
-const int Message::kArg0FieldNumber;
-const int Message::kArg1FieldNumber;
-const int Message::kArg2FieldNumber;
-const int Message::kArg3FieldNumber;
-const int Message::kArg4FieldNumber;
-const int Message::kArg5FieldNumber;
-const int Message::kArg6FieldNumber;
-const int Message::kArg7FieldNumber;
-const int Message::kArg8FieldNumber;
-const int Message::kDataFieldNumber;
-const int Message::kDataTypeFieldNumber;
-const int Message::kPixelFormatFieldNumber;
-const int Message::kPixelTypeFieldNumber;
-const int Message::kImageWidthFieldNumber;
-const int Message::kImageHeightFieldNumber;
-const int Message::kTimeFieldNumber;
-const int Message::kPropFieldNumber;
-const int Message::kClockFieldNumber;
-#endif // !_MSC_VER
-
-Message::Message()
- : ::google::protobuf::MessageLite() {
- SharedCtor();
-}
-
-void Message::InitAsDefaultInstance() {
-}
-
-Message::Message(const Message& from)
- : ::google::protobuf::MessageLite() {
- SharedCtor();
- MergeFrom(from);
-}
-
-void Message::SharedCtor() {
- _cached_size_ = 0;
- context_id_ = 0;
- function_ = 187;
- type_ = 0;
- expect_response_ = false;
- ret_ = 0;
- arg0_ = 0;
- arg1_ = 0;
- arg2_ = 0;
- arg3_ = 0;
- arg4_ = 0;
- arg5_ = 0;
- arg6_ = 0;
- arg7_ = 0;
- arg8_ = 0;
- data_ = const_cast< ::std::string*>(&_default_data_);
- data_type_ = 0;
- pixel_format_ = 0;
- pixel_type_ = 0;
- image_width_ = 0;
- image_height_ = 0;
- time_ = 0;
- prop_ = 0;
- clock_ = 0;
- ::memset(_has_bits_, 0, sizeof(_has_bits_));
-}
-
-Message::~Message() {
- SharedDtor();
-}
-
-void Message::SharedDtor() {
- if (data_ != &_default_data_) {
- delete data_;
- }
- if (this != default_instance_) {
- }
-}
-
-void Message::SetCachedSize(int size) const {
- GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
- _cached_size_ = size;
- GOOGLE_SAFE_CONCURRENT_WRITES_END();
-}
-const Message& Message::default_instance() {
- if (default_instance_ == NULL) protobuf_AddDesc_debugger_5fmessage_2eproto(); return *default_instance_;
-}
-
-Message* Message::default_instance_ = NULL;
-
-Message* Message::New() const {
- return new Message;
-}
-
-void Message::Clear() {
- if (_has_bits_[0 / 32] & (0xffu << (0 % 32))) {
- context_id_ = 0;
- function_ = 187;
- type_ = 0;
- expect_response_ = false;
- ret_ = 0;
- arg0_ = 0;
- arg1_ = 0;
- arg2_ = 0;
- }
- if (_has_bits_[8 / 32] & (0xffu << (8 % 32))) {
- arg3_ = 0;
- arg4_ = 0;
- arg5_ = 0;
- arg6_ = 0;
- arg7_ = 0;
- arg8_ = 0;
- if (_has_bit(14)) {
- if (data_ != &_default_data_) {
- data_->clear();
- }
- }
- data_type_ = 0;
- }
- if (_has_bits_[16 / 32] & (0xffu << (16 % 32))) {
- pixel_format_ = 0;
- pixel_type_ = 0;
- image_width_ = 0;
- image_height_ = 0;
- time_ = 0;
- prop_ = 0;
- clock_ = 0;
- }
- ::memset(_has_bits_, 0, sizeof(_has_bits_));
-}
-
-bool Message::MergePartialFromCodedStream(
- ::google::protobuf::io::CodedInputStream* input) {
-#define DO_(EXPRESSION) if (!(EXPRESSION)) return false
- ::google::protobuf::uint32 tag;
- while ((tag = input->ReadTag()) != 0) {
- switch (::google::protobuf::internal::WireFormatLite::GetTagFieldNumber(tag)) {
- // required int32 context_id = 1;
- case 1: {
- if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
- ::google::protobuf::internal::WireFormatLite::WIRETYPE_VARINT) {
- DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
- ::google::protobuf::int32, ::google::protobuf::internal::WireFormatLite::TYPE_INT32>(
- input, &context_id_)));
- _set_bit(0);
- } else {
- goto handle_uninterpreted;
- }
- if (input->ExpectTag(16)) goto parse_function;
- break;
- }
-
- // required .com.android.glesv2debugger.Message.Function function = 2 [default = NEG];
- case 2: {
- if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
- ::google::protobuf::internal::WireFormatLite::WIRETYPE_VARINT) {
- parse_function:
- int value;
- DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
- int, ::google::protobuf::internal::WireFormatLite::TYPE_ENUM>(
- input, &value)));
- if (::com::android::glesv2debugger::Message_Function_IsValid(value)) {
- set_function(static_cast< ::com::android::glesv2debugger::Message_Function >(value));
- }
- } else {
- goto handle_uninterpreted;
- }
- if (input->ExpectTag(24)) goto parse_type;
- break;
- }
-
- // required .com.android.glesv2debugger.Message.Type type = 3;
- case 3: {
- if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
- ::google::protobuf::internal::WireFormatLite::WIRETYPE_VARINT) {
- parse_type:
- int value;
- DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
- int, ::google::protobuf::internal::WireFormatLite::TYPE_ENUM>(
- input, &value)));
- if (::com::android::glesv2debugger::Message_Type_IsValid(value)) {
- set_type(static_cast< ::com::android::glesv2debugger::Message_Type >(value));
- }
- } else {
- goto handle_uninterpreted;
- }
- if (input->ExpectTag(32)) goto parse_expect_response;
- break;
- }
-
- // required bool expect_response = 4;
- case 4: {
- if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
- ::google::protobuf::internal::WireFormatLite::WIRETYPE_VARINT) {
- parse_expect_response:
- DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
- bool, ::google::protobuf::internal::WireFormatLite::TYPE_BOOL>(
- input, &expect_response_)));
- _set_bit(3);
- } else {
- goto handle_uninterpreted;
- }
- if (input->ExpectTag(40)) goto parse_ret;
- break;
- }
-
- // optional int32 ret = 5;
- case 5: {
- if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
- ::google::protobuf::internal::WireFormatLite::WIRETYPE_VARINT) {
- parse_ret:
- DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
- ::google::protobuf::int32, ::google::protobuf::internal::WireFormatLite::TYPE_INT32>(
- input, &ret_)));
- _set_bit(4);
- } else {
- goto handle_uninterpreted;
- }
- if (input->ExpectTag(48)) goto parse_arg0;
- break;
- }
-
- // optional int32 arg0 = 6;
- case 6: {
- if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
- ::google::protobuf::internal::WireFormatLite::WIRETYPE_VARINT) {
- parse_arg0:
- DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
- ::google::protobuf::int32, ::google::protobuf::internal::WireFormatLite::TYPE_INT32>(
- input, &arg0_)));
- _set_bit(5);
- } else {
- goto handle_uninterpreted;
- }
- if (input->ExpectTag(56)) goto parse_arg1;
- break;
- }
-
- // optional int32 arg1 = 7;
- case 7: {
- if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
- ::google::protobuf::internal::WireFormatLite::WIRETYPE_VARINT) {
- parse_arg1:
- DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
- ::google::protobuf::int32, ::google::protobuf::internal::WireFormatLite::TYPE_INT32>(
- input, &arg1_)));
- _set_bit(6);
- } else {
- goto handle_uninterpreted;
- }
- if (input->ExpectTag(64)) goto parse_arg2;
- break;
- }
-
- // optional int32 arg2 = 8;
- case 8: {
- if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
- ::google::protobuf::internal::WireFormatLite::WIRETYPE_VARINT) {
- parse_arg2:
- DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
- ::google::protobuf::int32, ::google::protobuf::internal::WireFormatLite::TYPE_INT32>(
- input, &arg2_)));
- _set_bit(7);
- } else {
- goto handle_uninterpreted;
- }
- if (input->ExpectTag(72)) goto parse_arg3;
- break;
- }
-
- // optional int32 arg3 = 9;
- case 9: {
- if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
- ::google::protobuf::internal::WireFormatLite::WIRETYPE_VARINT) {
- parse_arg3:
- DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
- ::google::protobuf::int32, ::google::protobuf::internal::WireFormatLite::TYPE_INT32>(
- input, &arg3_)));
- _set_bit(8);
- } else {
- goto handle_uninterpreted;
- }
- if (input->ExpectTag(82)) goto parse_data;
- break;
- }
-
- // optional bytes data = 10;
- case 10: {
- if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
- ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED) {
- parse_data:
- DO_(::google::protobuf::internal::WireFormatLite::ReadBytes(
- input, this->mutable_data()));
- } else {
- goto handle_uninterpreted;
- }
- if (input->ExpectTag(93)) goto parse_time;
- break;
- }
-
- // optional float time = 11;
- case 11: {
- if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
- ::google::protobuf::internal::WireFormatLite::WIRETYPE_FIXED32) {
- parse_time:
- DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
- float, ::google::protobuf::internal::WireFormatLite::TYPE_FLOAT>(
- input, &time_)));
- _set_bit(20);
- } else {
- goto handle_uninterpreted;
- }
- if (input->ExpectTag(128)) goto parse_arg4;
- break;
- }
-
- // optional int32 arg4 = 16;
- case 16: {
- if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
- ::google::protobuf::internal::WireFormatLite::WIRETYPE_VARINT) {
- parse_arg4:
- DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
- ::google::protobuf::int32, ::google::protobuf::internal::WireFormatLite::TYPE_INT32>(
- input, &arg4_)));
- _set_bit(9);
- } else {
- goto handle_uninterpreted;
- }
- if (input->ExpectTag(136)) goto parse_arg5;
- break;
- }
-
- // optional int32 arg5 = 17;
- case 17: {
- if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
- ::google::protobuf::internal::WireFormatLite::WIRETYPE_VARINT) {
- parse_arg5:
- DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
- ::google::protobuf::int32, ::google::protobuf::internal::WireFormatLite::TYPE_INT32>(
- input, &arg5_)));
- _set_bit(10);
- } else {
- goto handle_uninterpreted;
- }
- if (input->ExpectTag(144)) goto parse_arg6;
- break;
- }
-
- // optional int32 arg6 = 18;
- case 18: {
- if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
- ::google::protobuf::internal::WireFormatLite::WIRETYPE_VARINT) {
- parse_arg6:
- DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
- ::google::protobuf::int32, ::google::protobuf::internal::WireFormatLite::TYPE_INT32>(
- input, &arg6_)));
- _set_bit(11);
- } else {
- goto handle_uninterpreted;
- }
- if (input->ExpectTag(152)) goto parse_arg7;
- break;
- }
-
- // optional int32 arg7 = 19;
- case 19: {
- if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
- ::google::protobuf::internal::WireFormatLite::WIRETYPE_VARINT) {
- parse_arg7:
- DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
- ::google::protobuf::int32, ::google::protobuf::internal::WireFormatLite::TYPE_INT32>(
- input, &arg7_)));
- _set_bit(12);
- } else {
- goto handle_uninterpreted;
- }
- if (input->ExpectTag(160)) goto parse_arg8;
- break;
- }
-
- // optional int32 arg8 = 20;
- case 20: {
- if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
- ::google::protobuf::internal::WireFormatLite::WIRETYPE_VARINT) {
- parse_arg8:
- DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
- ::google::protobuf::int32, ::google::protobuf::internal::WireFormatLite::TYPE_INT32>(
- input, &arg8_)));
- _set_bit(13);
- } else {
- goto handle_uninterpreted;
- }
- if (input->ExpectTag(168)) goto parse_prop;
- break;
- }
-
- // optional .com.android.glesv2debugger.Message.Prop prop = 21;
- case 21: {
- if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
- ::google::protobuf::internal::WireFormatLite::WIRETYPE_VARINT) {
- parse_prop:
- int value;
- DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
- int, ::google::protobuf::internal::WireFormatLite::TYPE_ENUM>(
- input, &value)));
- if (::com::android::glesv2debugger::Message_Prop_IsValid(value)) {
- set_prop(static_cast< ::com::android::glesv2debugger::Message_Prop >(value));
- }
- } else {
- goto handle_uninterpreted;
- }
- if (input->ExpectTag(181)) goto parse_clock;
- break;
- }
-
- // optional float clock = 22;
- case 22: {
- if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
- ::google::protobuf::internal::WireFormatLite::WIRETYPE_FIXED32) {
- parse_clock:
- DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
- float, ::google::protobuf::internal::WireFormatLite::TYPE_FLOAT>(
- input, &clock_)));
- _set_bit(22);
- } else {
- goto handle_uninterpreted;
- }
- if (input->ExpectTag(184)) goto parse_data_type;
- break;
- }
-
- // optional .com.android.glesv2debugger.Message.DataType data_type = 23;
- case 23: {
- if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
- ::google::protobuf::internal::WireFormatLite::WIRETYPE_VARINT) {
- parse_data_type:
- int value;
- DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
- int, ::google::protobuf::internal::WireFormatLite::TYPE_ENUM>(
- input, &value)));
- if (::com::android::glesv2debugger::Message_DataType_IsValid(value)) {
- set_data_type(static_cast< ::com::android::glesv2debugger::Message_DataType >(value));
- }
- } else {
- goto handle_uninterpreted;
- }
- if (input->ExpectTag(192)) goto parse_pixel_format;
- break;
- }
-
- // optional int32 pixel_format = 24;
- case 24: {
- if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
- ::google::protobuf::internal::WireFormatLite::WIRETYPE_VARINT) {
- parse_pixel_format:
- DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
- ::google::protobuf::int32, ::google::protobuf::internal::WireFormatLite::TYPE_INT32>(
- input, &pixel_format_)));
- _set_bit(16);
- } else {
- goto handle_uninterpreted;
- }
- if (input->ExpectTag(200)) goto parse_pixel_type;
- break;
- }
-
- // optional int32 pixel_type = 25;
- case 25: {
- if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
- ::google::protobuf::internal::WireFormatLite::WIRETYPE_VARINT) {
- parse_pixel_type:
- DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
- ::google::protobuf::int32, ::google::protobuf::internal::WireFormatLite::TYPE_INT32>(
- input, &pixel_type_)));
- _set_bit(17);
- } else {
- goto handle_uninterpreted;
- }
- if (input->ExpectTag(208)) goto parse_image_width;
- break;
- }
-
- // optional int32 image_width = 26;
- case 26: {
- if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
- ::google::protobuf::internal::WireFormatLite::WIRETYPE_VARINT) {
- parse_image_width:
- DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
- ::google::protobuf::int32, ::google::protobuf::internal::WireFormatLite::TYPE_INT32>(
- input, &image_width_)));
- _set_bit(18);
- } else {
- goto handle_uninterpreted;
- }
- if (input->ExpectTag(216)) goto parse_image_height;
- break;
- }
-
- // optional int32 image_height = 27;
- case 27: {
- if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
- ::google::protobuf::internal::WireFormatLite::WIRETYPE_VARINT) {
- parse_image_height:
- DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
- ::google::protobuf::int32, ::google::protobuf::internal::WireFormatLite::TYPE_INT32>(
- input, &image_height_)));
- _set_bit(19);
- } else {
- goto handle_uninterpreted;
- }
- if (input->ExpectAtEnd()) return true;
- break;
- }
-
- default: {
- handle_uninterpreted:
- if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
- ::google::protobuf::internal::WireFormatLite::WIRETYPE_END_GROUP) {
- return true;
- }
- DO_(::google::protobuf::internal::WireFormatLite::SkipField(input, tag));
- break;
- }
- }
- }
- return true;
-#undef DO_
-}
-
-void Message::SerializeWithCachedSizes(
- ::google::protobuf::io::CodedOutputStream* output) const {
- // required int32 context_id = 1;
- if (_has_bit(0)) {
- ::google::protobuf::internal::WireFormatLite::WriteInt32(1, this->context_id(), output);
- }
-
- // required .com.android.glesv2debugger.Message.Function function = 2 [default = NEG];
- if (_has_bit(1)) {
- ::google::protobuf::internal::WireFormatLite::WriteEnum(
- 2, this->function(), output);
- }
-
- // required .com.android.glesv2debugger.Message.Type type = 3;
- if (_has_bit(2)) {
- ::google::protobuf::internal::WireFormatLite::WriteEnum(
- 3, this->type(), output);
- }
-
- // required bool expect_response = 4;
- if (_has_bit(3)) {
- ::google::protobuf::internal::WireFormatLite::WriteBool(4, this->expect_response(), output);
- }
-
- // optional int32 ret = 5;
- if (_has_bit(4)) {
- ::google::protobuf::internal::WireFormatLite::WriteInt32(5, this->ret(), output);
- }
-
- // optional int32 arg0 = 6;
- if (_has_bit(5)) {
- ::google::protobuf::internal::WireFormatLite::WriteInt32(6, this->arg0(), output);
- }
-
- // optional int32 arg1 = 7;
- if (_has_bit(6)) {
- ::google::protobuf::internal::WireFormatLite::WriteInt32(7, this->arg1(), output);
- }
-
- // optional int32 arg2 = 8;
- if (_has_bit(7)) {
- ::google::protobuf::internal::WireFormatLite::WriteInt32(8, this->arg2(), output);
- }
-
- // optional int32 arg3 = 9;
- if (_has_bit(8)) {
- ::google::protobuf::internal::WireFormatLite::WriteInt32(9, this->arg3(), output);
- }
-
- // optional bytes data = 10;
- if (_has_bit(14)) {
- ::google::protobuf::internal::WireFormatLite::WriteBytes(
- 10, this->data(), output);
- }
-
- // optional float time = 11;
- if (_has_bit(20)) {
- ::google::protobuf::internal::WireFormatLite::WriteFloat(11, this->time(), output);
- }
-
- // optional int32 arg4 = 16;
- if (_has_bit(9)) {
- ::google::protobuf::internal::WireFormatLite::WriteInt32(16, this->arg4(), output);
- }
-
- // optional int32 arg5 = 17;
- if (_has_bit(10)) {
- ::google::protobuf::internal::WireFormatLite::WriteInt32(17, this->arg5(), output);
- }
-
- // optional int32 arg6 = 18;
- if (_has_bit(11)) {
- ::google::protobuf::internal::WireFormatLite::WriteInt32(18, this->arg6(), output);
- }
-
- // optional int32 arg7 = 19;
- if (_has_bit(12)) {
- ::google::protobuf::internal::WireFormatLite::WriteInt32(19, this->arg7(), output);
- }
-
- // optional int32 arg8 = 20;
- if (_has_bit(13)) {
- ::google::protobuf::internal::WireFormatLite::WriteInt32(20, this->arg8(), output);
- }
-
- // optional .com.android.glesv2debugger.Message.Prop prop = 21;
- if (_has_bit(21)) {
- ::google::protobuf::internal::WireFormatLite::WriteEnum(
- 21, this->prop(), output);
- }
-
- // optional float clock = 22;
- if (_has_bit(22)) {
- ::google::protobuf::internal::WireFormatLite::WriteFloat(22, this->clock(), output);
- }
-
- // optional .com.android.glesv2debugger.Message.DataType data_type = 23;
- if (_has_bit(15)) {
- ::google::protobuf::internal::WireFormatLite::WriteEnum(
- 23, this->data_type(), output);
- }
-
- // optional int32 pixel_format = 24;
- if (_has_bit(16)) {
- ::google::protobuf::internal::WireFormatLite::WriteInt32(24, this->pixel_format(), output);
- }
-
- // optional int32 pixel_type = 25;
- if (_has_bit(17)) {
- ::google::protobuf::internal::WireFormatLite::WriteInt32(25, this->pixel_type(), output);
- }
-
- // optional int32 image_width = 26;
- if (_has_bit(18)) {
- ::google::protobuf::internal::WireFormatLite::WriteInt32(26, this->image_width(), output);
- }
-
- // optional int32 image_height = 27;
- if (_has_bit(19)) {
- ::google::protobuf::internal::WireFormatLite::WriteInt32(27, this->image_height(), output);
- }
-
-}
-
-int Message::ByteSize() const {
- int total_size = 0;
-
- if (_has_bits_[0 / 32] & (0xffu << (0 % 32))) {
- // required int32 context_id = 1;
- if (has_context_id()) {
- total_size += 1 +
- ::google::protobuf::internal::WireFormatLite::Int32Size(
- this->context_id());
- }
-
- // required .com.android.glesv2debugger.Message.Function function = 2 [default = NEG];
- if (has_function()) {
- total_size += 1 +
- ::google::protobuf::internal::WireFormatLite::EnumSize(this->function());
- }
-
- // required .com.android.glesv2debugger.Message.Type type = 3;
- if (has_type()) {
- total_size += 1 +
- ::google::protobuf::internal::WireFormatLite::EnumSize(this->type());
- }
-
- // required bool expect_response = 4;
- if (has_expect_response()) {
- total_size += 1 + 1;
- }
-
- // optional int32 ret = 5;
- if (has_ret()) {
- total_size += 1 +
- ::google::protobuf::internal::WireFormatLite::Int32Size(
- this->ret());
- }
-
- // optional int32 arg0 = 6;
- if (has_arg0()) {
- total_size += 1 +
- ::google::protobuf::internal::WireFormatLite::Int32Size(
- this->arg0());
- }
-
- // optional int32 arg1 = 7;
- if (has_arg1()) {
- total_size += 1 +
- ::google::protobuf::internal::WireFormatLite::Int32Size(
- this->arg1());
- }
-
- // optional int32 arg2 = 8;
- if (has_arg2()) {
- total_size += 1 +
- ::google::protobuf::internal::WireFormatLite::Int32Size(
- this->arg2());
- }
-
- }
- if (_has_bits_[8 / 32] & (0xffu << (8 % 32))) {
- // optional int32 arg3 = 9;
- if (has_arg3()) {
- total_size += 1 +
- ::google::protobuf::internal::WireFormatLite::Int32Size(
- this->arg3());
- }
-
- // optional int32 arg4 = 16;
- if (has_arg4()) {
- total_size += 2 +
- ::google::protobuf::internal::WireFormatLite::Int32Size(
- this->arg4());
- }
-
- // optional int32 arg5 = 17;
- if (has_arg5()) {
- total_size += 2 +
- ::google::protobuf::internal::WireFormatLite::Int32Size(
- this->arg5());
- }
-
- // optional int32 arg6 = 18;
- if (has_arg6()) {
- total_size += 2 +
- ::google::protobuf::internal::WireFormatLite::Int32Size(
- this->arg6());
- }
-
- // optional int32 arg7 = 19;
- if (has_arg7()) {
- total_size += 2 +
- ::google::protobuf::internal::WireFormatLite::Int32Size(
- this->arg7());
- }
-
- // optional int32 arg8 = 20;
- if (has_arg8()) {
- total_size += 2 +
- ::google::protobuf::internal::WireFormatLite::Int32Size(
- this->arg8());
- }
-
- // optional bytes data = 10;
- if (has_data()) {
- total_size += 1 +
- ::google::protobuf::internal::WireFormatLite::BytesSize(
- this->data());
- }
-
- // optional .com.android.glesv2debugger.Message.DataType data_type = 23;
- if (has_data_type()) {
- total_size += 2 +
- ::google::protobuf::internal::WireFormatLite::EnumSize(this->data_type());
- }
-
- }
- if (_has_bits_[16 / 32] & (0xffu << (16 % 32))) {
- // optional int32 pixel_format = 24;
- if (has_pixel_format()) {
- total_size += 2 +
- ::google::protobuf::internal::WireFormatLite::Int32Size(
- this->pixel_format());
- }
-
- // optional int32 pixel_type = 25;
- if (has_pixel_type()) {
- total_size += 2 +
- ::google::protobuf::internal::WireFormatLite::Int32Size(
- this->pixel_type());
- }
-
- // optional int32 image_width = 26;
- if (has_image_width()) {
- total_size += 2 +
- ::google::protobuf::internal::WireFormatLite::Int32Size(
- this->image_width());
- }
-
- // optional int32 image_height = 27;
- if (has_image_height()) {
- total_size += 2 +
- ::google::protobuf::internal::WireFormatLite::Int32Size(
- this->image_height());
- }
-
- // optional float time = 11;
- if (has_time()) {
- total_size += 1 + 4;
- }
-
- // optional .com.android.glesv2debugger.Message.Prop prop = 21;
- if (has_prop()) {
- total_size += 2 +
- ::google::protobuf::internal::WireFormatLite::EnumSize(this->prop());
- }
-
- // optional float clock = 22;
- if (has_clock()) {
- total_size += 2 + 4;
- }
-
- }
- GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
- _cached_size_ = total_size;
- GOOGLE_SAFE_CONCURRENT_WRITES_END();
- return total_size;
-}
-
-void Message::CheckTypeAndMergeFrom(
- const ::google::protobuf::MessageLite& from) {
- MergeFrom(*::google::protobuf::down_cast<const Message*>(&from));
-}
-
-void Message::MergeFrom(const Message& from) {
- GOOGLE_CHECK_NE(&from, this);
- if (from._has_bits_[0 / 32] & (0xffu << (0 % 32))) {
- if (from._has_bit(0)) {
- set_context_id(from.context_id());
- }
- if (from._has_bit(1)) {
- set_function(from.function());
- }
- if (from._has_bit(2)) {
- set_type(from.type());
- }
- if (from._has_bit(3)) {
- set_expect_response(from.expect_response());
- }
- if (from._has_bit(4)) {
- set_ret(from.ret());
- }
- if (from._has_bit(5)) {
- set_arg0(from.arg0());
- }
- if (from._has_bit(6)) {
- set_arg1(from.arg1());
- }
- if (from._has_bit(7)) {
- set_arg2(from.arg2());
- }
- }
- if (from._has_bits_[8 / 32] & (0xffu << (8 % 32))) {
- if (from._has_bit(8)) {
- set_arg3(from.arg3());
- }
- if (from._has_bit(9)) {
- set_arg4(from.arg4());
- }
- if (from._has_bit(10)) {
- set_arg5(from.arg5());
- }
- if (from._has_bit(11)) {
- set_arg6(from.arg6());
- }
- if (from._has_bit(12)) {
- set_arg7(from.arg7());
- }
- if (from._has_bit(13)) {
- set_arg8(from.arg8());
- }
- if (from._has_bit(14)) {
- set_data(from.data());
- }
- if (from._has_bit(15)) {
- set_data_type(from.data_type());
- }
- }
- if (from._has_bits_[16 / 32] & (0xffu << (16 % 32))) {
- if (from._has_bit(16)) {
- set_pixel_format(from.pixel_format());
- }
- if (from._has_bit(17)) {
- set_pixel_type(from.pixel_type());
- }
- if (from._has_bit(18)) {
- set_image_width(from.image_width());
- }
- if (from._has_bit(19)) {
- set_image_height(from.image_height());
- }
- if (from._has_bit(20)) {
- set_time(from.time());
- }
- if (from._has_bit(21)) {
- set_prop(from.prop());
- }
- if (from._has_bit(22)) {
- set_clock(from.clock());
- }
- }
-}
-
-void Message::CopyFrom(const Message& from) {
- if (&from == this) return;
- Clear();
- MergeFrom(from);
-}
-
-bool Message::IsInitialized() const {
- if ((_has_bits_[0] & 0x0000000f) != 0x0000000f) return false;
-
- return true;
-}
-
-void Message::Swap(Message* other) {
- if (other != this) {
- std::swap(context_id_, other->context_id_);
- std::swap(function_, other->function_);
- std::swap(type_, other->type_);
- std::swap(expect_response_, other->expect_response_);
- std::swap(ret_, other->ret_);
- std::swap(arg0_, other->arg0_);
- std::swap(arg1_, other->arg1_);
- std::swap(arg2_, other->arg2_);
- std::swap(arg3_, other->arg3_);
- std::swap(arg4_, other->arg4_);
- std::swap(arg5_, other->arg5_);
- std::swap(arg6_, other->arg6_);
- std::swap(arg7_, other->arg7_);
- std::swap(arg8_, other->arg8_);
- std::swap(data_, other->data_);
- std::swap(data_type_, other->data_type_);
- std::swap(pixel_format_, other->pixel_format_);
- std::swap(pixel_type_, other->pixel_type_);
- std::swap(image_width_, other->image_width_);
- std::swap(image_height_, other->image_height_);
- std::swap(time_, other->time_);
- std::swap(prop_, other->prop_);
- std::swap(clock_, other->clock_);
- std::swap(_has_bits_[0], other->_has_bits_[0]);
- std::swap(_cached_size_, other->_cached_size_);
- }
-}
-
-::std::string Message::GetTypeName() const {
- return "com.android.glesv2debugger.Message";
-}
-
-
-// @@protoc_insertion_point(namespace_scope)
-
-} // namespace glesv2debugger
-} // namespace android
-} // namespace com
-
-// @@protoc_insertion_point(global_scope)
diff --git a/opengl/libs/GLES2_dbg/src/debugger_message.pb.h b/opengl/libs/GLES2_dbg/src/debugger_message.pb.h
deleted file mode 100644
index 5c94664..0000000
--- a/opengl/libs/GLES2_dbg/src/debugger_message.pb.h
+++ /dev/null
@@ -1,1187 +0,0 @@
-// Generated by the protocol buffer compiler. DO NOT EDIT!
-// source: debugger_message.proto
-
-#ifndef PROTOBUF_debugger_5fmessage_2eproto__INCLUDED
-#define PROTOBUF_debugger_5fmessage_2eproto__INCLUDED
-
-#include <string>
-
-#include <google/protobuf/stubs/common.h>
-
-#if GOOGLE_PROTOBUF_VERSION < 2003000
-#error This file was generated by a newer version of protoc which is
-#error incompatible with your Protocol Buffer headers. Please update
-#error your headers.
-#endif
-#if 2003000 < GOOGLE_PROTOBUF_MIN_PROTOC_VERSION
-#error This file was generated by an older version of protoc which is
-#error incompatible with your Protocol Buffer headers. Please
-#error regenerate this file with a newer version of protoc.
-#endif
-
-#include <google/protobuf/generated_message_util.h>
-#include <google/protobuf/repeated_field.h>
-#include <google/protobuf/extension_set.h>
-// @@protoc_insertion_point(includes)
-
-namespace com {
-namespace android {
-namespace glesv2debugger {
-
-// Internal implementation detail -- do not call these.
-void protobuf_AddDesc_debugger_5fmessage_2eproto();
-void protobuf_AssignDesc_debugger_5fmessage_2eproto();
-void protobuf_ShutdownFile_debugger_5fmessage_2eproto();
-
-class Message;
-
-enum Message_Function {
- Message_Function_glActiveTexture = 0,
- Message_Function_glAttachShader = 1,
- Message_Function_glBindAttribLocation = 2,
- Message_Function_glBindBuffer = 3,
- Message_Function_glBindFramebuffer = 4,
- Message_Function_glBindRenderbuffer = 5,
- Message_Function_glBindTexture = 6,
- Message_Function_glBlendColor = 7,
- Message_Function_glBlendEquation = 8,
- Message_Function_glBlendEquationSeparate = 9,
- Message_Function_glBlendFunc = 10,
- Message_Function_glBlendFuncSeparate = 11,
- Message_Function_glBufferData = 12,
- Message_Function_glBufferSubData = 13,
- Message_Function_glCheckFramebufferStatus = 14,
- Message_Function_glClear = 15,
- Message_Function_glClearColor = 16,
- Message_Function_glClearDepthf = 17,
- Message_Function_glClearStencil = 18,
- Message_Function_glColorMask = 19,
- Message_Function_glCompileShader = 20,
- Message_Function_glCompressedTexImage2D = 21,
- Message_Function_glCompressedTexSubImage2D = 22,
- Message_Function_glCopyTexImage2D = 23,
- Message_Function_glCopyTexSubImage2D = 24,
- Message_Function_glCreateProgram = 25,
- Message_Function_glCreateShader = 26,
- Message_Function_glCullFace = 27,
- Message_Function_glDeleteBuffers = 28,
- Message_Function_glDeleteFramebuffers = 29,
- Message_Function_glDeleteProgram = 30,
- Message_Function_glDeleteRenderbuffers = 31,
- Message_Function_glDeleteShader = 32,
- Message_Function_glDeleteTextures = 33,
- Message_Function_glDepthFunc = 34,
- Message_Function_glDepthMask = 35,
- Message_Function_glDepthRangef = 36,
- Message_Function_glDetachShader = 37,
- Message_Function_glDisable = 38,
- Message_Function_glDisableVertexAttribArray = 39,
- Message_Function_glDrawArrays = 40,
- Message_Function_glDrawElements = 41,
- Message_Function_glEnable = 42,
- Message_Function_glEnableVertexAttribArray = 43,
- Message_Function_glFinish = 44,
- Message_Function_glFlush = 45,
- Message_Function_glFramebufferRenderbuffer = 46,
- Message_Function_glFramebufferTexture2D = 47,
- Message_Function_glFrontFace = 48,
- Message_Function_glGenBuffers = 49,
- Message_Function_glGenerateMipmap = 50,
- Message_Function_glGenFramebuffers = 51,
- Message_Function_glGenRenderbuffers = 52,
- Message_Function_glGenTextures = 53,
- Message_Function_glGetActiveAttrib = 54,
- Message_Function_glGetActiveUniform = 55,
- Message_Function_glGetAttachedShaders = 56,
- Message_Function_glGetAttribLocation = 57,
- Message_Function_glGetBooleanv = 58,
- Message_Function_glGetBufferParameteriv = 59,
- Message_Function_glGetError = 60,
- Message_Function_glGetFloatv = 61,
- Message_Function_glGetFramebufferAttachmentParameteriv = 62,
- Message_Function_glGetIntegerv = 63,
- Message_Function_glGetProgramiv = 64,
- Message_Function_glGetProgramInfoLog = 65,
- Message_Function_glGetRenderbufferParameteriv = 66,
- Message_Function_glGetShaderiv = 67,
- Message_Function_glGetShaderInfoLog = 68,
- Message_Function_glGetShaderPrecisionFormat = 69,
- Message_Function_glGetShaderSource = 70,
- Message_Function_glGetString = 71,
- Message_Function_glGetTexParameterfv = 72,
- Message_Function_glGetTexParameteriv = 73,
- Message_Function_glGetUniformfv = 74,
- Message_Function_glGetUniformiv = 75,
- Message_Function_glGetUniformLocation = 76,
- Message_Function_glGetVertexAttribfv = 77,
- Message_Function_glGetVertexAttribiv = 78,
- Message_Function_glGetVertexAttribPointerv = 79,
- Message_Function_glHint = 80,
- Message_Function_glIsBuffer = 81,
- Message_Function_glIsEnabled = 82,
- Message_Function_glIsFramebuffer = 83,
- Message_Function_glIsProgram = 84,
- Message_Function_glIsRenderbuffer = 85,
- Message_Function_glIsShader = 86,
- Message_Function_glIsTexture = 87,
- Message_Function_glLineWidth = 88,
- Message_Function_glLinkProgram = 89,
- Message_Function_glPixelStorei = 90,
- Message_Function_glPolygonOffset = 91,
- Message_Function_glReadPixels = 92,
- Message_Function_glReleaseShaderCompiler = 93,
- Message_Function_glRenderbufferStorage = 94,
- Message_Function_glSampleCoverage = 95,
- Message_Function_glScissor = 96,
- Message_Function_glShaderBinary = 97,
- Message_Function_glShaderSource = 98,
- Message_Function_glStencilFunc = 99,
- Message_Function_glStencilFuncSeparate = 100,
- Message_Function_glStencilMask = 101,
- Message_Function_glStencilMaskSeparate = 102,
- Message_Function_glStencilOp = 103,
- Message_Function_glStencilOpSeparate = 104,
- Message_Function_glTexImage2D = 105,
- Message_Function_glTexParameterf = 106,
- Message_Function_glTexParameterfv = 107,
- Message_Function_glTexParameteri = 108,
- Message_Function_glTexParameteriv = 109,
- Message_Function_glTexSubImage2D = 110,
- Message_Function_glUniform1f = 111,
- Message_Function_glUniform1fv = 112,
- Message_Function_glUniform1i = 113,
- Message_Function_glUniform1iv = 114,
- Message_Function_glUniform2f = 115,
- Message_Function_glUniform2fv = 116,
- Message_Function_glUniform2i = 117,
- Message_Function_glUniform2iv = 118,
- Message_Function_glUniform3f = 119,
- Message_Function_glUniform3fv = 120,
- Message_Function_glUniform3i = 121,
- Message_Function_glUniform3iv = 122,
- Message_Function_glUniform4f = 123,
- Message_Function_glUniform4fv = 124,
- Message_Function_glUniform4i = 125,
- Message_Function_glUniform4iv = 126,
- Message_Function_glUniformMatrix2fv = 127,
- Message_Function_glUniformMatrix3fv = 128,
- Message_Function_glUniformMatrix4fv = 129,
- Message_Function_glUseProgram = 130,
- Message_Function_glValidateProgram = 131,
- Message_Function_glVertexAttrib1f = 132,
- Message_Function_glVertexAttrib1fv = 133,
- Message_Function_glVertexAttrib2f = 134,
- Message_Function_glVertexAttrib2fv = 135,
- Message_Function_glVertexAttrib3f = 136,
- Message_Function_glVertexAttrib3fv = 137,
- Message_Function_glVertexAttrib4f = 138,
- Message_Function_glVertexAttrib4fv = 139,
- Message_Function_glVertexAttribPointer = 140,
- Message_Function_glViewport = 141,
- Message_Function_eglGetDisplay = 142,
- Message_Function_eglInitialize = 143,
- Message_Function_eglTerminate = 144,
- Message_Function_eglGetConfigs = 145,
- Message_Function_eglChooseConfig = 146,
- Message_Function_eglGetConfigAttrib = 147,
- Message_Function_eglCreateWindowSurface = 148,
- Message_Function_eglCreatePixmapSurface = 149,
- Message_Function_eglCreatePbufferSurface = 150,
- Message_Function_eglDestroySurface = 151,
- Message_Function_eglQuerySurface = 152,
- Message_Function_eglCreateContext = 153,
- Message_Function_eglDestroyContext = 154,
- Message_Function_eglMakeCurrent = 155,
- Message_Function_eglGetCurrentContext = 156,
- Message_Function_eglGetCurrentSurface = 157,
- Message_Function_eglGetCurrentDisplay = 158,
- Message_Function_eglQueryContext = 159,
- Message_Function_eglWaitGL = 160,
- Message_Function_eglWaitNative = 161,
- Message_Function_eglSwapBuffers = 162,
- Message_Function_eglCopyBuffers = 163,
- Message_Function_eglGetError = 164,
- Message_Function_eglQueryString = 165,
- Message_Function_eglGetProcAddress = 166,
- Message_Function_eglSurfaceAttrib = 167,
- Message_Function_eglBindTexImage = 168,
- Message_Function_eglReleaseTexImage = 169,
- Message_Function_eglSwapInterval = 170,
- Message_Function_eglBindAPI = 171,
- Message_Function_eglQueryAPI = 172,
- Message_Function_eglWaitClient = 173,
- Message_Function_eglReleaseThread = 174,
- Message_Function_eglCreatePbufferFromClientBuffer = 175,
- Message_Function_eglLockSurfaceKHR = 176,
- Message_Function_eglUnlockSurfaceKHR = 177,
- Message_Function_eglCreateImageKHR = 178,
- Message_Function_eglDestroyImageKHR = 179,
- Message_Function_eglCreateSyncKHR = 180,
- Message_Function_eglDestroySyncKHR = 181,
- Message_Function_eglClientWaitSyncKHR = 182,
- Message_Function_eglGetSyncAttribKHR = 183,
- Message_Function_eglSetSwapRectangleANDROID = 184,
- Message_Function_eglGetRenderBufferANDROID = 185,
- Message_Function_ACK = 186,
- Message_Function_NEG = 187,
- Message_Function_CONTINUE = 188,
- Message_Function_SKIP = 189,
- Message_Function_SETPROP = 190
-};
-bool Message_Function_IsValid(int value);
-const Message_Function Message_Function_Function_MIN = Message_Function_glActiveTexture;
-const Message_Function Message_Function_Function_MAX = Message_Function_SETPROP;
-const int Message_Function_Function_ARRAYSIZE = Message_Function_Function_MAX + 1;
-
-enum Message_Type {
- Message_Type_BeforeCall = 0,
- Message_Type_AfterCall = 1,
- Message_Type_AfterGeneratedCall = 2,
- Message_Type_Response = 3,
- Message_Type_CompleteCall = 4
-};
-bool Message_Type_IsValid(int value);
-const Message_Type Message_Type_Type_MIN = Message_Type_BeforeCall;
-const Message_Type Message_Type_Type_MAX = Message_Type_CompleteCall;
-const int Message_Type_Type_ARRAYSIZE = Message_Type_Type_MAX + 1;
-
-enum Message_DataType {
- Message_DataType_ReferencedImage = 0,
- Message_DataType_NonreferencedImage = 1
-};
-bool Message_DataType_IsValid(int value);
-const Message_DataType Message_DataType_DataType_MIN = Message_DataType_ReferencedImage;
-const Message_DataType Message_DataType_DataType_MAX = Message_DataType_NonreferencedImage;
-const int Message_DataType_DataType_ARRAYSIZE = Message_DataType_DataType_MAX + 1;
-
-enum Message_Prop {
- Message_Prop_CaptureDraw = 0,
- Message_Prop_TimeMode = 1,
- Message_Prop_ExpectResponse = 2,
- Message_Prop_CaptureSwap = 3,
- Message_Prop_GLConstant = 4
-};
-bool Message_Prop_IsValid(int value);
-const Message_Prop Message_Prop_Prop_MIN = Message_Prop_CaptureDraw;
-const Message_Prop Message_Prop_Prop_MAX = Message_Prop_GLConstant;
-const int Message_Prop_Prop_ARRAYSIZE = Message_Prop_Prop_MAX + 1;
-
-// ===================================================================
-
-class Message : public ::google::protobuf::MessageLite {
- public:
- Message();
- virtual ~Message();
-
- Message(const Message& from);
-
- inline Message& operator=(const Message& from) {
- CopyFrom(from);
- return *this;
- }
-
- static const Message& default_instance();
-
- void Swap(Message* other);
-
- // implements Message ----------------------------------------------
-
- Message* New() const;
- void CheckTypeAndMergeFrom(const ::google::protobuf::MessageLite& from);
- void CopyFrom(const Message& from);
- void MergeFrom(const Message& from);
- void Clear();
- bool IsInitialized() const;
-
- int ByteSize() const;
- bool MergePartialFromCodedStream(
- ::google::protobuf::io::CodedInputStream* input);
- void SerializeWithCachedSizes(
- ::google::protobuf::io::CodedOutputStream* output) const;
- int GetCachedSize() const { return _cached_size_; }
- private:
- void SharedCtor();
- void SharedDtor();
- void SetCachedSize(int size) const;
- public:
-
- ::std::string GetTypeName() const;
-
- // nested types ----------------------------------------------------
-
- typedef Message_Function Function;
- static const Function glActiveTexture = Message_Function_glActiveTexture;
- static const Function glAttachShader = Message_Function_glAttachShader;
- static const Function glBindAttribLocation = Message_Function_glBindAttribLocation;
- static const Function glBindBuffer = Message_Function_glBindBuffer;
- static const Function glBindFramebuffer = Message_Function_glBindFramebuffer;
- static const Function glBindRenderbuffer = Message_Function_glBindRenderbuffer;
- static const Function glBindTexture = Message_Function_glBindTexture;
- static const Function glBlendColor = Message_Function_glBlendColor;
- static const Function glBlendEquation = Message_Function_glBlendEquation;
- static const Function glBlendEquationSeparate = Message_Function_glBlendEquationSeparate;
- static const Function glBlendFunc = Message_Function_glBlendFunc;
- static const Function glBlendFuncSeparate = Message_Function_glBlendFuncSeparate;
- static const Function glBufferData = Message_Function_glBufferData;
- static const Function glBufferSubData = Message_Function_glBufferSubData;
- static const Function glCheckFramebufferStatus = Message_Function_glCheckFramebufferStatus;
- static const Function glClear = Message_Function_glClear;
- static const Function glClearColor = Message_Function_glClearColor;
- static const Function glClearDepthf = Message_Function_glClearDepthf;
- static const Function glClearStencil = Message_Function_glClearStencil;
- static const Function glColorMask = Message_Function_glColorMask;
- static const Function glCompileShader = Message_Function_glCompileShader;
- static const Function glCompressedTexImage2D = Message_Function_glCompressedTexImage2D;
- static const Function glCompressedTexSubImage2D = Message_Function_glCompressedTexSubImage2D;
- static const Function glCopyTexImage2D = Message_Function_glCopyTexImage2D;
- static const Function glCopyTexSubImage2D = Message_Function_glCopyTexSubImage2D;
- static const Function glCreateProgram = Message_Function_glCreateProgram;
- static const Function glCreateShader = Message_Function_glCreateShader;
- static const Function glCullFace = Message_Function_glCullFace;
- static const Function glDeleteBuffers = Message_Function_glDeleteBuffers;
- static const Function glDeleteFramebuffers = Message_Function_glDeleteFramebuffers;
- static const Function glDeleteProgram = Message_Function_glDeleteProgram;
- static const Function glDeleteRenderbuffers = Message_Function_glDeleteRenderbuffers;
- static const Function glDeleteShader = Message_Function_glDeleteShader;
- static const Function glDeleteTextures = Message_Function_glDeleteTextures;
- static const Function glDepthFunc = Message_Function_glDepthFunc;
- static const Function glDepthMask = Message_Function_glDepthMask;
- static const Function glDepthRangef = Message_Function_glDepthRangef;
- static const Function glDetachShader = Message_Function_glDetachShader;
- static const Function glDisable = Message_Function_glDisable;
- static const Function glDisableVertexAttribArray = Message_Function_glDisableVertexAttribArray;
- static const Function glDrawArrays = Message_Function_glDrawArrays;
- static const Function glDrawElements = Message_Function_glDrawElements;
- static const Function glEnable = Message_Function_glEnable;
- static const Function glEnableVertexAttribArray = Message_Function_glEnableVertexAttribArray;
- static const Function glFinish = Message_Function_glFinish;
- static const Function glFlush = Message_Function_glFlush;
- static const Function glFramebufferRenderbuffer = Message_Function_glFramebufferRenderbuffer;
- static const Function glFramebufferTexture2D = Message_Function_glFramebufferTexture2D;
- static const Function glFrontFace = Message_Function_glFrontFace;
- static const Function glGenBuffers = Message_Function_glGenBuffers;
- static const Function glGenerateMipmap = Message_Function_glGenerateMipmap;
- static const Function glGenFramebuffers = Message_Function_glGenFramebuffers;
- static const Function glGenRenderbuffers = Message_Function_glGenRenderbuffers;
- static const Function glGenTextures = Message_Function_glGenTextures;
- static const Function glGetActiveAttrib = Message_Function_glGetActiveAttrib;
- static const Function glGetActiveUniform = Message_Function_glGetActiveUniform;
- static const Function glGetAttachedShaders = Message_Function_glGetAttachedShaders;
- static const Function glGetAttribLocation = Message_Function_glGetAttribLocation;
- static const Function glGetBooleanv = Message_Function_glGetBooleanv;
- static const Function glGetBufferParameteriv = Message_Function_glGetBufferParameteriv;
- static const Function glGetError = Message_Function_glGetError;
- static const Function glGetFloatv = Message_Function_glGetFloatv;
- static const Function glGetFramebufferAttachmentParameteriv = Message_Function_glGetFramebufferAttachmentParameteriv;
- static const Function glGetIntegerv = Message_Function_glGetIntegerv;
- static const Function glGetProgramiv = Message_Function_glGetProgramiv;
- static const Function glGetProgramInfoLog = Message_Function_glGetProgramInfoLog;
- static const Function glGetRenderbufferParameteriv = Message_Function_glGetRenderbufferParameteriv;
- static const Function glGetShaderiv = Message_Function_glGetShaderiv;
- static const Function glGetShaderInfoLog = Message_Function_glGetShaderInfoLog;
- static const Function glGetShaderPrecisionFormat = Message_Function_glGetShaderPrecisionFormat;
- static const Function glGetShaderSource = Message_Function_glGetShaderSource;
- static const Function glGetString = Message_Function_glGetString;
- static const Function glGetTexParameterfv = Message_Function_glGetTexParameterfv;
- static const Function glGetTexParameteriv = Message_Function_glGetTexParameteriv;
- static const Function glGetUniformfv = Message_Function_glGetUniformfv;
- static const Function glGetUniformiv = Message_Function_glGetUniformiv;
- static const Function glGetUniformLocation = Message_Function_glGetUniformLocation;
- static const Function glGetVertexAttribfv = Message_Function_glGetVertexAttribfv;
- static const Function glGetVertexAttribiv = Message_Function_glGetVertexAttribiv;
- static const Function glGetVertexAttribPointerv = Message_Function_glGetVertexAttribPointerv;
- static const Function glHint = Message_Function_glHint;
- static const Function glIsBuffer = Message_Function_glIsBuffer;
- static const Function glIsEnabled = Message_Function_glIsEnabled;
- static const Function glIsFramebuffer = Message_Function_glIsFramebuffer;
- static const Function glIsProgram = Message_Function_glIsProgram;
- static const Function glIsRenderbuffer = Message_Function_glIsRenderbuffer;
- static const Function glIsShader = Message_Function_glIsShader;
- static const Function glIsTexture = Message_Function_glIsTexture;
- static const Function glLineWidth = Message_Function_glLineWidth;
- static const Function glLinkProgram = Message_Function_glLinkProgram;
- static const Function glPixelStorei = Message_Function_glPixelStorei;
- static const Function glPolygonOffset = Message_Function_glPolygonOffset;
- static const Function glReadPixels = Message_Function_glReadPixels;
- static const Function glReleaseShaderCompiler = Message_Function_glReleaseShaderCompiler;
- static const Function glRenderbufferStorage = Message_Function_glRenderbufferStorage;
- static const Function glSampleCoverage = Message_Function_glSampleCoverage;
- static const Function glScissor = Message_Function_glScissor;
- static const Function glShaderBinary = Message_Function_glShaderBinary;
- static const Function glShaderSource = Message_Function_glShaderSource;
- static const Function glStencilFunc = Message_Function_glStencilFunc;
- static const Function glStencilFuncSeparate = Message_Function_glStencilFuncSeparate;
- static const Function glStencilMask = Message_Function_glStencilMask;
- static const Function glStencilMaskSeparate = Message_Function_glStencilMaskSeparate;
- static const Function glStencilOp = Message_Function_glStencilOp;
- static const Function glStencilOpSeparate = Message_Function_glStencilOpSeparate;
- static const Function glTexImage2D = Message_Function_glTexImage2D;
- static const Function glTexParameterf = Message_Function_glTexParameterf;
- static const Function glTexParameterfv = Message_Function_glTexParameterfv;
- static const Function glTexParameteri = Message_Function_glTexParameteri;
- static const Function glTexParameteriv = Message_Function_glTexParameteriv;
- static const Function glTexSubImage2D = Message_Function_glTexSubImage2D;
- static const Function glUniform1f = Message_Function_glUniform1f;
- static const Function glUniform1fv = Message_Function_glUniform1fv;
- static const Function glUniform1i = Message_Function_glUniform1i;
- static const Function glUniform1iv = Message_Function_glUniform1iv;
- static const Function glUniform2f = Message_Function_glUniform2f;
- static const Function glUniform2fv = Message_Function_glUniform2fv;
- static const Function glUniform2i = Message_Function_glUniform2i;
- static const Function glUniform2iv = Message_Function_glUniform2iv;
- static const Function glUniform3f = Message_Function_glUniform3f;
- static const Function glUniform3fv = Message_Function_glUniform3fv;
- static const Function glUniform3i = Message_Function_glUniform3i;
- static const Function glUniform3iv = Message_Function_glUniform3iv;
- static const Function glUniform4f = Message_Function_glUniform4f;
- static const Function glUniform4fv = Message_Function_glUniform4fv;
- static const Function glUniform4i = Message_Function_glUniform4i;
- static const Function glUniform4iv = Message_Function_glUniform4iv;
- static const Function glUniformMatrix2fv = Message_Function_glUniformMatrix2fv;
- static const Function glUniformMatrix3fv = Message_Function_glUniformMatrix3fv;
- static const Function glUniformMatrix4fv = Message_Function_glUniformMatrix4fv;
- static const Function glUseProgram = Message_Function_glUseProgram;
- static const Function glValidateProgram = Message_Function_glValidateProgram;
- static const Function glVertexAttrib1f = Message_Function_glVertexAttrib1f;
- static const Function glVertexAttrib1fv = Message_Function_glVertexAttrib1fv;
- static const Function glVertexAttrib2f = Message_Function_glVertexAttrib2f;
- static const Function glVertexAttrib2fv = Message_Function_glVertexAttrib2fv;
- static const Function glVertexAttrib3f = Message_Function_glVertexAttrib3f;
- static const Function glVertexAttrib3fv = Message_Function_glVertexAttrib3fv;
- static const Function glVertexAttrib4f = Message_Function_glVertexAttrib4f;
- static const Function glVertexAttrib4fv = Message_Function_glVertexAttrib4fv;
- static const Function glVertexAttribPointer = Message_Function_glVertexAttribPointer;
- static const Function glViewport = Message_Function_glViewport;
- static const Function eglGetDisplay = Message_Function_eglGetDisplay;
- static const Function eglInitialize = Message_Function_eglInitialize;
- static const Function eglTerminate = Message_Function_eglTerminate;
- static const Function eglGetConfigs = Message_Function_eglGetConfigs;
- static const Function eglChooseConfig = Message_Function_eglChooseConfig;
- static const Function eglGetConfigAttrib = Message_Function_eglGetConfigAttrib;
- static const Function eglCreateWindowSurface = Message_Function_eglCreateWindowSurface;
- static const Function eglCreatePixmapSurface = Message_Function_eglCreatePixmapSurface;
- static const Function eglCreatePbufferSurface = Message_Function_eglCreatePbufferSurface;
- static const Function eglDestroySurface = Message_Function_eglDestroySurface;
- static const Function eglQuerySurface = Message_Function_eglQuerySurface;
- static const Function eglCreateContext = Message_Function_eglCreateContext;
- static const Function eglDestroyContext = Message_Function_eglDestroyContext;
- static const Function eglMakeCurrent = Message_Function_eglMakeCurrent;
- static const Function eglGetCurrentContext = Message_Function_eglGetCurrentContext;
- static const Function eglGetCurrentSurface = Message_Function_eglGetCurrentSurface;
- static const Function eglGetCurrentDisplay = Message_Function_eglGetCurrentDisplay;
- static const Function eglQueryContext = Message_Function_eglQueryContext;
- static const Function eglWaitGL = Message_Function_eglWaitGL;
- static const Function eglWaitNative = Message_Function_eglWaitNative;
- static const Function eglSwapBuffers = Message_Function_eglSwapBuffers;
- static const Function eglCopyBuffers = Message_Function_eglCopyBuffers;
- static const Function eglGetError = Message_Function_eglGetError;
- static const Function eglQueryString = Message_Function_eglQueryString;
- static const Function eglGetProcAddress = Message_Function_eglGetProcAddress;
- static const Function eglSurfaceAttrib = Message_Function_eglSurfaceAttrib;
- static const Function eglBindTexImage = Message_Function_eglBindTexImage;
- static const Function eglReleaseTexImage = Message_Function_eglReleaseTexImage;
- static const Function eglSwapInterval = Message_Function_eglSwapInterval;
- static const Function eglBindAPI = Message_Function_eglBindAPI;
- static const Function eglQueryAPI = Message_Function_eglQueryAPI;
- static const Function eglWaitClient = Message_Function_eglWaitClient;
- static const Function eglReleaseThread = Message_Function_eglReleaseThread;
- static const Function eglCreatePbufferFromClientBuffer = Message_Function_eglCreatePbufferFromClientBuffer;
- static const Function eglLockSurfaceKHR = Message_Function_eglLockSurfaceKHR;
- static const Function eglUnlockSurfaceKHR = Message_Function_eglUnlockSurfaceKHR;
- static const Function eglCreateImageKHR = Message_Function_eglCreateImageKHR;
- static const Function eglDestroyImageKHR = Message_Function_eglDestroyImageKHR;
- static const Function eglCreateSyncKHR = Message_Function_eglCreateSyncKHR;
- static const Function eglDestroySyncKHR = Message_Function_eglDestroySyncKHR;
- static const Function eglClientWaitSyncKHR = Message_Function_eglClientWaitSyncKHR;
- static const Function eglGetSyncAttribKHR = Message_Function_eglGetSyncAttribKHR;
- static const Function eglSetSwapRectangleANDROID = Message_Function_eglSetSwapRectangleANDROID;
- static const Function eglGetRenderBufferANDROID = Message_Function_eglGetRenderBufferANDROID;
- static const Function ACK = Message_Function_ACK;
- static const Function NEG = Message_Function_NEG;
- static const Function CONTINUE = Message_Function_CONTINUE;
- static const Function SKIP = Message_Function_SKIP;
- static const Function SETPROP = Message_Function_SETPROP;
- static inline bool Function_IsValid(int value) {
- return Message_Function_IsValid(value);
- }
- static const Function Function_MIN =
- Message_Function_Function_MIN;
- static const Function Function_MAX =
- Message_Function_Function_MAX;
- static const int Function_ARRAYSIZE =
- Message_Function_Function_ARRAYSIZE;
-
- typedef Message_Type Type;
- static const Type BeforeCall = Message_Type_BeforeCall;
- static const Type AfterCall = Message_Type_AfterCall;
- static const Type AfterGeneratedCall = Message_Type_AfterGeneratedCall;
- static const Type Response = Message_Type_Response;
- static const Type CompleteCall = Message_Type_CompleteCall;
- static inline bool Type_IsValid(int value) {
- return Message_Type_IsValid(value);
- }
- static const Type Type_MIN =
- Message_Type_Type_MIN;
- static const Type Type_MAX =
- Message_Type_Type_MAX;
- static const int Type_ARRAYSIZE =
- Message_Type_Type_ARRAYSIZE;
-
- typedef Message_DataType DataType;
- static const DataType ReferencedImage = Message_DataType_ReferencedImage;
- static const DataType NonreferencedImage = Message_DataType_NonreferencedImage;
- static inline bool DataType_IsValid(int value) {
- return Message_DataType_IsValid(value);
- }
- static const DataType DataType_MIN =
- Message_DataType_DataType_MIN;
- static const DataType DataType_MAX =
- Message_DataType_DataType_MAX;
- static const int DataType_ARRAYSIZE =
- Message_DataType_DataType_ARRAYSIZE;
-
- typedef Message_Prop Prop;
- static const Prop CaptureDraw = Message_Prop_CaptureDraw;
- static const Prop TimeMode = Message_Prop_TimeMode;
- static const Prop ExpectResponse = Message_Prop_ExpectResponse;
- static const Prop CaptureSwap = Message_Prop_CaptureSwap;
- static const Prop GLConstant = Message_Prop_GLConstant;
- static inline bool Prop_IsValid(int value) {
- return Message_Prop_IsValid(value);
- }
- static const Prop Prop_MIN =
- Message_Prop_Prop_MIN;
- static const Prop Prop_MAX =
- Message_Prop_Prop_MAX;
- static const int Prop_ARRAYSIZE =
- Message_Prop_Prop_ARRAYSIZE;
-
- // accessors -------------------------------------------------------
-
- // required int32 context_id = 1;
- inline bool has_context_id() const;
- inline void clear_context_id();
- static const int kContextIdFieldNumber = 1;
- inline ::google::protobuf::int32 context_id() const;
- inline void set_context_id(::google::protobuf::int32 value);
-
- // required .com.android.glesv2debugger.Message.Function function = 2 [default = NEG];
- inline bool has_function() const;
- inline void clear_function();
- static const int kFunctionFieldNumber = 2;
- inline ::com::android::glesv2debugger::Message_Function function() const;
- inline void set_function(::com::android::glesv2debugger::Message_Function value);
-
- // required .com.android.glesv2debugger.Message.Type type = 3;
- inline bool has_type() const;
- inline void clear_type();
- static const int kTypeFieldNumber = 3;
- inline ::com::android::glesv2debugger::Message_Type type() const;
- inline void set_type(::com::android::glesv2debugger::Message_Type value);
-
- // required bool expect_response = 4;
- inline bool has_expect_response() const;
- inline void clear_expect_response();
- static const int kExpectResponseFieldNumber = 4;
- inline bool expect_response() const;
- inline void set_expect_response(bool value);
-
- // optional int32 ret = 5;
- inline bool has_ret() const;
- inline void clear_ret();
- static const int kRetFieldNumber = 5;
- inline ::google::protobuf::int32 ret() const;
- inline void set_ret(::google::protobuf::int32 value);
-
- // optional int32 arg0 = 6;
- inline bool has_arg0() const;
- inline void clear_arg0();
- static const int kArg0FieldNumber = 6;
- inline ::google::protobuf::int32 arg0() const;
- inline void set_arg0(::google::protobuf::int32 value);
-
- // optional int32 arg1 = 7;
- inline bool has_arg1() const;
- inline void clear_arg1();
- static const int kArg1FieldNumber = 7;
- inline ::google::protobuf::int32 arg1() const;
- inline void set_arg1(::google::protobuf::int32 value);
-
- // optional int32 arg2 = 8;
- inline bool has_arg2() const;
- inline void clear_arg2();
- static const int kArg2FieldNumber = 8;
- inline ::google::protobuf::int32 arg2() const;
- inline void set_arg2(::google::protobuf::int32 value);
-
- // optional int32 arg3 = 9;
- inline bool has_arg3() const;
- inline void clear_arg3();
- static const int kArg3FieldNumber = 9;
- inline ::google::protobuf::int32 arg3() const;
- inline void set_arg3(::google::protobuf::int32 value);
-
- // optional int32 arg4 = 16;
- inline bool has_arg4() const;
- inline void clear_arg4();
- static const int kArg4FieldNumber = 16;
- inline ::google::protobuf::int32 arg4() const;
- inline void set_arg4(::google::protobuf::int32 value);
-
- // optional int32 arg5 = 17;
- inline bool has_arg5() const;
- inline void clear_arg5();
- static const int kArg5FieldNumber = 17;
- inline ::google::protobuf::int32 arg5() const;
- inline void set_arg5(::google::protobuf::int32 value);
-
- // optional int32 arg6 = 18;
- inline bool has_arg6() const;
- inline void clear_arg6();
- static const int kArg6FieldNumber = 18;
- inline ::google::protobuf::int32 arg6() const;
- inline void set_arg6(::google::protobuf::int32 value);
-
- // optional int32 arg7 = 19;
- inline bool has_arg7() const;
- inline void clear_arg7();
- static const int kArg7FieldNumber = 19;
- inline ::google::protobuf::int32 arg7() const;
- inline void set_arg7(::google::protobuf::int32 value);
-
- // optional int32 arg8 = 20;
- inline bool has_arg8() const;
- inline void clear_arg8();
- static const int kArg8FieldNumber = 20;
- inline ::google::protobuf::int32 arg8() const;
- inline void set_arg8(::google::protobuf::int32 value);
-
- // optional bytes data = 10;
- inline bool has_data() const;
- inline void clear_data();
- static const int kDataFieldNumber = 10;
- inline const ::std::string& data() const;
- inline void set_data(const ::std::string& value);
- inline void set_data(const char* value);
- inline void set_data(const void* value, size_t size);
- inline ::std::string* mutable_data();
-
- // optional .com.android.glesv2debugger.Message.DataType data_type = 23;
- inline bool has_data_type() const;
- inline void clear_data_type();
- static const int kDataTypeFieldNumber = 23;
- inline ::com::android::glesv2debugger::Message_DataType data_type() const;
- inline void set_data_type(::com::android::glesv2debugger::Message_DataType value);
-
- // optional int32 pixel_format = 24;
- inline bool has_pixel_format() const;
- inline void clear_pixel_format();
- static const int kPixelFormatFieldNumber = 24;
- inline ::google::protobuf::int32 pixel_format() const;
- inline void set_pixel_format(::google::protobuf::int32 value);
-
- // optional int32 pixel_type = 25;
- inline bool has_pixel_type() const;
- inline void clear_pixel_type();
- static const int kPixelTypeFieldNumber = 25;
- inline ::google::protobuf::int32 pixel_type() const;
- inline void set_pixel_type(::google::protobuf::int32 value);
-
- // optional int32 image_width = 26;
- inline bool has_image_width() const;
- inline void clear_image_width();
- static const int kImageWidthFieldNumber = 26;
- inline ::google::protobuf::int32 image_width() const;
- inline void set_image_width(::google::protobuf::int32 value);
-
- // optional int32 image_height = 27;
- inline bool has_image_height() const;
- inline void clear_image_height();
- static const int kImageHeightFieldNumber = 27;
- inline ::google::protobuf::int32 image_height() const;
- inline void set_image_height(::google::protobuf::int32 value);
-
- // optional float time = 11;
- inline bool has_time() const;
- inline void clear_time();
- static const int kTimeFieldNumber = 11;
- inline float time() const;
- inline void set_time(float value);
-
- // optional .com.android.glesv2debugger.Message.Prop prop = 21;
- inline bool has_prop() const;
- inline void clear_prop();
- static const int kPropFieldNumber = 21;
- inline ::com::android::glesv2debugger::Message_Prop prop() const;
- inline void set_prop(::com::android::glesv2debugger::Message_Prop value);
-
- // optional float clock = 22;
- inline bool has_clock() const;
- inline void clear_clock();
- static const int kClockFieldNumber = 22;
- inline float clock() const;
- inline void set_clock(float value);
-
- // @@protoc_insertion_point(class_scope:com.android.glesv2debugger.Message)
- private:
- mutable int _cached_size_;
-
- ::google::protobuf::int32 context_id_;
- int function_;
- int type_;
- bool expect_response_;
- ::google::protobuf::int32 ret_;
- ::google::protobuf::int32 arg0_;
- ::google::protobuf::int32 arg1_;
- ::google::protobuf::int32 arg2_;
- ::google::protobuf::int32 arg3_;
- ::google::protobuf::int32 arg4_;
- ::google::protobuf::int32 arg5_;
- ::google::protobuf::int32 arg6_;
- ::google::protobuf::int32 arg7_;
- ::google::protobuf::int32 arg8_;
- ::std::string* data_;
- static const ::std::string _default_data_;
- int data_type_;
- ::google::protobuf::int32 pixel_format_;
- ::google::protobuf::int32 pixel_type_;
- ::google::protobuf::int32 image_width_;
- ::google::protobuf::int32 image_height_;
- float time_;
- int prop_;
- float clock_;
- friend void protobuf_AddDesc_debugger_5fmessage_2eproto();
- friend void protobuf_AssignDesc_debugger_5fmessage_2eproto();
- friend void protobuf_ShutdownFile_debugger_5fmessage_2eproto();
-
- ::google::protobuf::uint32 _has_bits_[(23 + 31) / 32];
-
- // WHY DOES & HAVE LOWER PRECEDENCE THAN != !?
- inline bool _has_bit(int index) const {
- return (_has_bits_[index / 32] & (1u << (index % 32))) != 0;
- }
- inline void _set_bit(int index) {
- _has_bits_[index / 32] |= (1u << (index % 32));
- }
- inline void _clear_bit(int index) {
- _has_bits_[index / 32] &= ~(1u << (index % 32));
- }
-
- void InitAsDefaultInstance();
- static Message* default_instance_;
-};
-// ===================================================================
-
-
-// ===================================================================
-
-// Message
-
-// required int32 context_id = 1;
-inline bool Message::has_context_id() const {
- return _has_bit(0);
-}
-inline void Message::clear_context_id() {
- context_id_ = 0;
- _clear_bit(0);
-}
-inline ::google::protobuf::int32 Message::context_id() const {
- return context_id_;
-}
-inline void Message::set_context_id(::google::protobuf::int32 value) {
- _set_bit(0);
- context_id_ = value;
-}
-
-// required .com.android.glesv2debugger.Message.Function function = 2 [default = NEG];
-inline bool Message::has_function() const {
- return _has_bit(1);
-}
-inline void Message::clear_function() {
- function_ = 187;
- _clear_bit(1);
-}
-inline ::com::android::glesv2debugger::Message_Function Message::function() const {
- return static_cast< ::com::android::glesv2debugger::Message_Function >(function_);
-}
-inline void Message::set_function(::com::android::glesv2debugger::Message_Function value) {
- GOOGLE_DCHECK(::com::android::glesv2debugger::Message_Function_IsValid(value));
- _set_bit(1);
- function_ = value;
-}
-
-// required .com.android.glesv2debugger.Message.Type type = 3;
-inline bool Message::has_type() const {
- return _has_bit(2);
-}
-inline void Message::clear_type() {
- type_ = 0;
- _clear_bit(2);
-}
-inline ::com::android::glesv2debugger::Message_Type Message::type() const {
- return static_cast< ::com::android::glesv2debugger::Message_Type >(type_);
-}
-inline void Message::set_type(::com::android::glesv2debugger::Message_Type value) {
- GOOGLE_DCHECK(::com::android::glesv2debugger::Message_Type_IsValid(value));
- _set_bit(2);
- type_ = value;
-}
-
-// required bool expect_response = 4;
-inline bool Message::has_expect_response() const {
- return _has_bit(3);
-}
-inline void Message::clear_expect_response() {
- expect_response_ = false;
- _clear_bit(3);
-}
-inline bool Message::expect_response() const {
- return expect_response_;
-}
-inline void Message::set_expect_response(bool value) {
- _set_bit(3);
- expect_response_ = value;
-}
-
-// optional int32 ret = 5;
-inline bool Message::has_ret() const {
- return _has_bit(4);
-}
-inline void Message::clear_ret() {
- ret_ = 0;
- _clear_bit(4);
-}
-inline ::google::protobuf::int32 Message::ret() const {
- return ret_;
-}
-inline void Message::set_ret(::google::protobuf::int32 value) {
- _set_bit(4);
- ret_ = value;
-}
-
-// optional int32 arg0 = 6;
-inline bool Message::has_arg0() const {
- return _has_bit(5);
-}
-inline void Message::clear_arg0() {
- arg0_ = 0;
- _clear_bit(5);
-}
-inline ::google::protobuf::int32 Message::arg0() const {
- return arg0_;
-}
-inline void Message::set_arg0(::google::protobuf::int32 value) {
- _set_bit(5);
- arg0_ = value;
-}
-
-// optional int32 arg1 = 7;
-inline bool Message::has_arg1() const {
- return _has_bit(6);
-}
-inline void Message::clear_arg1() {
- arg1_ = 0;
- _clear_bit(6);
-}
-inline ::google::protobuf::int32 Message::arg1() const {
- return arg1_;
-}
-inline void Message::set_arg1(::google::protobuf::int32 value) {
- _set_bit(6);
- arg1_ = value;
-}
-
-// optional int32 arg2 = 8;
-inline bool Message::has_arg2() const {
- return _has_bit(7);
-}
-inline void Message::clear_arg2() {
- arg2_ = 0;
- _clear_bit(7);
-}
-inline ::google::protobuf::int32 Message::arg2() const {
- return arg2_;
-}
-inline void Message::set_arg2(::google::protobuf::int32 value) {
- _set_bit(7);
- arg2_ = value;
-}
-
-// optional int32 arg3 = 9;
-inline bool Message::has_arg3() const {
- return _has_bit(8);
-}
-inline void Message::clear_arg3() {
- arg3_ = 0;
- _clear_bit(8);
-}
-inline ::google::protobuf::int32 Message::arg3() const {
- return arg3_;
-}
-inline void Message::set_arg3(::google::protobuf::int32 value) {
- _set_bit(8);
- arg3_ = value;
-}
-
-// optional int32 arg4 = 16;
-inline bool Message::has_arg4() const {
- return _has_bit(9);
-}
-inline void Message::clear_arg4() {
- arg4_ = 0;
- _clear_bit(9);
-}
-inline ::google::protobuf::int32 Message::arg4() const {
- return arg4_;
-}
-inline void Message::set_arg4(::google::protobuf::int32 value) {
- _set_bit(9);
- arg4_ = value;
-}
-
-// optional int32 arg5 = 17;
-inline bool Message::has_arg5() const {
- return _has_bit(10);
-}
-inline void Message::clear_arg5() {
- arg5_ = 0;
- _clear_bit(10);
-}
-inline ::google::protobuf::int32 Message::arg5() const {
- return arg5_;
-}
-inline void Message::set_arg5(::google::protobuf::int32 value) {
- _set_bit(10);
- arg5_ = value;
-}
-
-// optional int32 arg6 = 18;
-inline bool Message::has_arg6() const {
- return _has_bit(11);
-}
-inline void Message::clear_arg6() {
- arg6_ = 0;
- _clear_bit(11);
-}
-inline ::google::protobuf::int32 Message::arg6() const {
- return arg6_;
-}
-inline void Message::set_arg6(::google::protobuf::int32 value) {
- _set_bit(11);
- arg6_ = value;
-}
-
-// optional int32 arg7 = 19;
-inline bool Message::has_arg7() const {
- return _has_bit(12);
-}
-inline void Message::clear_arg7() {
- arg7_ = 0;
- _clear_bit(12);
-}
-inline ::google::protobuf::int32 Message::arg7() const {
- return arg7_;
-}
-inline void Message::set_arg7(::google::protobuf::int32 value) {
- _set_bit(12);
- arg7_ = value;
-}
-
-// optional int32 arg8 = 20;
-inline bool Message::has_arg8() const {
- return _has_bit(13);
-}
-inline void Message::clear_arg8() {
- arg8_ = 0;
- _clear_bit(13);
-}
-inline ::google::protobuf::int32 Message::arg8() const {
- return arg8_;
-}
-inline void Message::set_arg8(::google::protobuf::int32 value) {
- _set_bit(13);
- arg8_ = value;
-}
-
-// optional bytes data = 10;
-inline bool Message::has_data() const {
- return _has_bit(14);
-}
-inline void Message::clear_data() {
- if (data_ != &_default_data_) {
- data_->clear();
- }
- _clear_bit(14);
-}
-inline const ::std::string& Message::data() const {
- return *data_;
-}
-inline void Message::set_data(const ::std::string& value) {
- _set_bit(14);
- if (data_ == &_default_data_) {
- data_ = new ::std::string;
- }
- data_->assign(value);
-}
-inline void Message::set_data(const char* value) {
- _set_bit(14);
- if (data_ == &_default_data_) {
- data_ = new ::std::string;
- }
- data_->assign(value);
-}
-inline void Message::set_data(const void* value, size_t size) {
- _set_bit(14);
- if (data_ == &_default_data_) {
- data_ = new ::std::string;
- }
- data_->assign(reinterpret_cast<const char*>(value), size);
-}
-inline ::std::string* Message::mutable_data() {
- _set_bit(14);
- if (data_ == &_default_data_) {
- data_ = new ::std::string;
- }
- return data_;
-}
-
-// optional .com.android.glesv2debugger.Message.DataType data_type = 23;
-inline bool Message::has_data_type() const {
- return _has_bit(15);
-}
-inline void Message::clear_data_type() {
- data_type_ = 0;
- _clear_bit(15);
-}
-inline ::com::android::glesv2debugger::Message_DataType Message::data_type() const {
- return static_cast< ::com::android::glesv2debugger::Message_DataType >(data_type_);
-}
-inline void Message::set_data_type(::com::android::glesv2debugger::Message_DataType value) {
- GOOGLE_DCHECK(::com::android::glesv2debugger::Message_DataType_IsValid(value));
- _set_bit(15);
- data_type_ = value;
-}
-
-// optional int32 pixel_format = 24;
-inline bool Message::has_pixel_format() const {
- return _has_bit(16);
-}
-inline void Message::clear_pixel_format() {
- pixel_format_ = 0;
- _clear_bit(16);
-}
-inline ::google::protobuf::int32 Message::pixel_format() const {
- return pixel_format_;
-}
-inline void Message::set_pixel_format(::google::protobuf::int32 value) {
- _set_bit(16);
- pixel_format_ = value;
-}
-
-// optional int32 pixel_type = 25;
-inline bool Message::has_pixel_type() const {
- return _has_bit(17);
-}
-inline void Message::clear_pixel_type() {
- pixel_type_ = 0;
- _clear_bit(17);
-}
-inline ::google::protobuf::int32 Message::pixel_type() const {
- return pixel_type_;
-}
-inline void Message::set_pixel_type(::google::protobuf::int32 value) {
- _set_bit(17);
- pixel_type_ = value;
-}
-
-// optional int32 image_width = 26;
-inline bool Message::has_image_width() const {
- return _has_bit(18);
-}
-inline void Message::clear_image_width() {
- image_width_ = 0;
- _clear_bit(18);
-}
-inline ::google::protobuf::int32 Message::image_width() const {
- return image_width_;
-}
-inline void Message::set_image_width(::google::protobuf::int32 value) {
- _set_bit(18);
- image_width_ = value;
-}
-
-// optional int32 image_height = 27;
-inline bool Message::has_image_height() const {
- return _has_bit(19);
-}
-inline void Message::clear_image_height() {
- image_height_ = 0;
- _clear_bit(19);
-}
-inline ::google::protobuf::int32 Message::image_height() const {
- return image_height_;
-}
-inline void Message::set_image_height(::google::protobuf::int32 value) {
- _set_bit(19);
- image_height_ = value;
-}
-
-// optional float time = 11;
-inline bool Message::has_time() const {
- return _has_bit(20);
-}
-inline void Message::clear_time() {
- time_ = 0;
- _clear_bit(20);
-}
-inline float Message::time() const {
- return time_;
-}
-inline void Message::set_time(float value) {
- _set_bit(20);
- time_ = value;
-}
-
-// optional .com.android.glesv2debugger.Message.Prop prop = 21;
-inline bool Message::has_prop() const {
- return _has_bit(21);
-}
-inline void Message::clear_prop() {
- prop_ = 0;
- _clear_bit(21);
-}
-inline ::com::android::glesv2debugger::Message_Prop Message::prop() const {
- return static_cast< ::com::android::glesv2debugger::Message_Prop >(prop_);
-}
-inline void Message::set_prop(::com::android::glesv2debugger::Message_Prop value) {
- GOOGLE_DCHECK(::com::android::glesv2debugger::Message_Prop_IsValid(value));
- _set_bit(21);
- prop_ = value;
-}
-
-// optional float clock = 22;
-inline bool Message::has_clock() const {
- return _has_bit(22);
-}
-inline void Message::clear_clock() {
- clock_ = 0;
- _clear_bit(22);
-}
-inline float Message::clock() const {
- return clock_;
-}
-inline void Message::set_clock(float value) {
- _set_bit(22);
- clock_ = value;
-}
-
-
-// @@protoc_insertion_point(namespace_scope)
-
-} // namespace glesv2debugger
-} // namespace android
-} // namespace com
-
-// @@protoc_insertion_point(global_scope)
-
-#endif // PROTOBUF_debugger_5fmessage_2eproto__INCLUDED
diff --git a/opengl/libs/GLES2_dbg/src/egl.cpp b/opengl/libs/GLES2_dbg/src/egl.cpp
deleted file mode 100644
index bbea3bd..0000000
--- a/opengl/libs/GLES2_dbg/src/egl.cpp
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
- ** Copyright 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.
- ** 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.
- */
-
-#include "header.h"
-
-EGLBoolean Debug_eglSwapBuffers(EGLDisplay dpy, EGLSurface draw)
-{
- DbgContext * const dbg = getDbgContextThreadSpecific();
- glesv2debugger::Message msg;
- struct : public FunctionCall {
- EGLDisplay dpy;
- EGLSurface draw;
-
- const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
- msg.set_time(-1);
- return reinterpret_cast<const int *>(true);
- }
- } caller;
- caller.dpy = dpy;
- caller.draw = draw;
-
- msg.set_arg0(reinterpret_cast<int>(dpy));
- msg.set_arg1(reinterpret_cast<int>(draw));
- if (dbg->captureSwap > 0) {
- dbg->captureSwap--;
- int viewport[4] = {};
- dbg->hooks->gl.glGetIntegerv(GL_VIEWPORT, viewport);
- void * pixels = dbg->GetReadPixelsBuffer(viewport[2] * viewport[3] *
- dbg->readBytesPerPixel);
- dbg->hooks->gl.glReadPixels(viewport[0], viewport[1], viewport[2],
- viewport[3], GL_RGBA, GL_UNSIGNED_BYTE, pixels);
- dbg->CompressReadPixelBuffer(msg.mutable_data());
- msg.set_data_type(msg.ReferencedImage);
- msg.set_pixel_format(GL_RGBA);
- msg.set_pixel_type(GL_UNSIGNED_BYTE);
- msg.set_image_width(viewport[2]);
- msg.set_image_height(viewport[3]);
- }
- int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_eglSwapBuffers);
- return static_cast<EGLBoolean>(reinterpret_cast<int>(ret));
-}
diff --git a/opengl/libs/GLES2_dbg/src/header.h b/opengl/libs/GLES2_dbg/src/header.h
deleted file mode 100644
index 0ab4890..0000000
--- a/opengl/libs/GLES2_dbg/src/header.h
+++ /dev/null
@@ -1,178 +0,0 @@
-/*
- ** Copyright 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.
- ** You may obtain a copy of the License at
- **
- ** http://www.apache.org/licenses/LICENSE-2.0
- **
- ** Unless required by applicable law or agreed to in writing, software
- ** distributed under the License is distributed on an "AS IS" BASIS,
- ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ** See the License for the specific language governing permissions and
- ** limitations under the License.
- */
-
-#ifndef ANDROID_GLES2_DBG_HEADER_H
-#define ANDROID_GLES2_DBG_HEADER_H
-
-#include <stdlib.h>
-#include <ctype.h>
-#include <string.h>
-#include <errno.h>
-
-#include <GLES2/gl2.h>
-#include <GLES2/gl2ext.h>
-
-#include <cutils/log.h>
-#include <utils/Timers.h>
-
-#include "hooks.h"
-
-#include "glesv2dbg.h"
-
-#define GL_ENTRY(_r, _api, ...) _r Debug_##_api ( __VA_ARGS__ );
-#include "glesv2dbg_functions.h"
-
-#include "debugger_message.pb.h"
-
-using namespace android;
-using namespace com::android;
-
-#ifndef __location__
-#define __HIERALLOC_STRING_0__(s) #s
-#define __HIERALLOC_STRING_1__(s) __HIERALLOC_STRING_0__(s)
-#define __HIERALLOC_STRING_2__ __HIERALLOC_STRING_1__(__LINE__)
-#define __location__ __FILE__ ":" __HIERALLOC_STRING_2__
-#endif
-
-#undef assert
-#define assert(expr) if (!(expr)) { ALOGD("\n*\n*\n* assert: %s at %s \n*\n*", #expr, __location__); int * x = 0; *x = 5; }
-//#undef ALOGD
-//#define ALOGD(...)
-
-namespace android
-{
-
-struct GLFunctionBitfield {
- unsigned char field [24]; // 8 * 24 = 192
-
- void Bit(const glesv2debugger::Message_Function function, bool bit) {
- const unsigned byte = function / 8, mask = 1 << (function % 8);
- if (bit)
- field[byte] |= mask;
- else
- field[byte] &= ~mask;
- }
-
- bool Bit(const glesv2debugger::Message_Function function) const {
- const unsigned byte = function / 8, mask = 1 << (function % 8);
- return field[byte] & mask;
- }
-};
-
-struct DbgContext {
- static const unsigned int LZF_CHUNK_SIZE = 256 * 1024;
-
-private:
- char * lzf_buf; // malloc / free; for lzf chunk compression and other uses
-
- // used as buffer and reference frame for ReadPixels; malloc/free
- unsigned * lzf_ref [2];
- unsigned lzf_readIndex; // 0 or 1
- unsigned lzf_refSize, lzf_refBufSize; // bytes
-
-public:
- const unsigned int version; // 0 is GLES1, 1 is GLES2
- const gl_hooks_t * const hooks;
- const unsigned int MAX_VERTEX_ATTRIBS;
- const unsigned int readBytesPerPixel;
-
- unsigned int captureSwap; // number of eglSwapBuffers to glReadPixels
- unsigned int captureDraw; // number of glDrawArrays/Elements to glReadPixels
-
- GLFunctionBitfield expectResponse;
-
- struct VertexAttrib {
- GLenum type; // element data type
- unsigned size; // number of data per element
- unsigned stride; // calculated number of bytes between elements
- const void * ptr;
- unsigned elemSize; // calculated number of bytes per element
- GLuint buffer; // buffer name
- GLboolean normalized : 1;
- GLboolean enabled : 1;
- VertexAttrib() : type(0), size(0), stride(0), ptr(NULL), elemSize(0),
- buffer(0), normalized(0), enabled(0) {}
- } * vertexAttribs;
- bool hasNonVBOAttribs; // whether any enabled vertexAttrib is user pointer
-
- struct VBO {
- const GLuint name;
- const GLenum target;
- VBO * next;
- void * data; // malloc/free
- unsigned size; // in bytes
- VBO(const GLuint name, const GLenum target, VBO * head) : name(name),
- target(target), next(head), data(NULL), size(0) {}
- } * indexBuffers; // linked list of all index buffers
- VBO * indexBuffer; // currently bound index buffer
-
- GLuint program;
- unsigned maxAttrib; // number of slots used by program
-
- DbgContext(const unsigned version, const gl_hooks_t * const hooks,
- const unsigned MAX_VERTEX_ATTRIBS);
- ~DbgContext();
-
- void Fetch(const unsigned index, std::string * const data) const;
- void Compress(const void * in_data, unsigned in_len, std::string * const outStr);
- static unsigned char * Decompress(const void * in, const unsigned int inLen,
- unsigned int * const outLen); // malloc/free
- void * GetReadPixelsBuffer(const unsigned size);
- bool IsReadPixelBuffer(const void * const ptr) {
- return ptr == lzf_ref[lzf_readIndex];
- }
- void CompressReadPixelBuffer(std::string * const outStr);
- char * GetBuffer(); // allocates lzf_buf if NULL
- unsigned int GetBufferSize(); // allocates lzf_buf if NULL
-
- void glUseProgram(GLuint program);
- void glEnableVertexAttribArray(GLuint index);
- void glDisableVertexAttribArray(GLuint index);
- void glVertexAttribPointer(GLuint indx, GLint size, GLenum type,
- GLboolean normalized, GLsizei stride, const GLvoid* ptr);
- void glBindBuffer(GLenum target, GLuint buffer);
- void glBufferData(GLenum target, GLsizeiptr size, const GLvoid* data, GLenum usage);
- void glBufferSubData(GLenum target, GLintptr offset, GLsizeiptr size, const GLvoid* data);
- void glDeleteBuffers(GLsizei n, const GLuint *buffers);
-};
-
-DbgContext * getDbgContextThreadSpecific();
-
-struct FunctionCall {
- virtual const int * operator()(gl_hooks_t::gl_t const * const _c,
- glesv2debugger::Message & msg) = 0;
- virtual ~FunctionCall() {}
-};
-
-// move these into DbgContext as static
-extern int timeMode; // SYSTEM_TIME_
-
-extern int clientSock, serverSock;
-
-unsigned GetBytesPerPixel(const GLenum format, const GLenum type);
-
-// every Debug_gl* function calls this to send message to client and possibly receive commands
-int * MessageLoop(FunctionCall & functionCall, glesv2debugger::Message & msg,
- const glesv2debugger::Message_Function function);
-
-void Receive(glesv2debugger::Message & cmd);
-float Send(const glesv2debugger::Message & msg, glesv2debugger::Message & cmd);
-void SetProp(DbgContext * const dbg, const glesv2debugger::Message & cmd);
-const int * GenerateCall(DbgContext * const dbg, const glesv2debugger::Message & cmd,
- glesv2debugger::Message & msg, const int * const prevRet);
-}; // namespace android {
-
-#endif // #ifndef ANDROID_GLES2_DBG_HEADER_H
diff --git a/opengl/libs/GLES2_dbg/src/server.cpp b/opengl/libs/GLES2_dbg/src/server.cpp
deleted file mode 100644
index 3e93697..0000000
--- a/opengl/libs/GLES2_dbg/src/server.cpp
+++ /dev/null
@@ -1,312 +0,0 @@
-/*
- ** Copyright 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.
- ** 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.
- */
-
-#include <sys/ioctl.h>
-#include <unistd.h>
-#include <sys/socket.h>
-#include <fcntl.h>
-#include <netinet/in.h>
-#include <arpa/inet.h>
-#include <pthread.h>
-
-#include "header.h"
-
-namespace android
-{
-
-int serverSock = -1, clientSock = -1;
-FILE * file = NULL;
-unsigned int MAX_FILE_SIZE = 0;
-int timeMode = SYSTEM_TIME_THREAD;
-
-static void Die(const char * msg)
-{
- ALOGD("\n*\n*\n* GLESv2_dbg: Die: %s \n*\n*", msg);
- StopDebugServer();
- exit(1);
-}
-
-void StartDebugServer(const unsigned short port, const bool forceUseFile,
- const unsigned int maxFileSize, const char * const filePath)
-{
- MAX_FILE_SIZE = maxFileSize;
-
- ALOGD("GLESv2_dbg: StartDebugServer");
- if (serverSock >= 0 || file)
- return;
-
- ALOGD("GLESv2_dbg: StartDebugServer create socket");
- struct sockaddr_in server = {}, client = {};
-
- /* Create the TCP socket */
- if (forceUseFile || (serverSock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0) {
- file = fopen(filePath, "wb");
- if (!file)
- Die("Failed to create socket and file");
- else
- return;
- }
- /* Construct the server sockaddr_in structure */
- server.sin_family = AF_INET; /* Internet/IP */
- server.sin_addr.s_addr = htonl(INADDR_LOOPBACK); /* Incoming addr */
- server.sin_port = htons(port); /* server port */
-
- /* Bind the server socket */
- socklen_t sizeofSockaddr_in = sizeof(sockaddr_in);
- if (bind(serverSock, (struct sockaddr *) &server,
- sizeof(server)) < 0) {
- Die("Failed to bind the server socket");
- }
- /* Listen on the server socket */
- if (listen(serverSock, 1) < 0) {
- Die("Failed to listen on server socket");
- }
-
- ALOGD("server started on %d \n", server.sin_port);
-
-
- /* Wait for client connection */
- if ((clientSock =
- accept(serverSock, (struct sockaddr *) &client,
- &sizeofSockaddr_in)) < 0) {
- Die("Failed to accept client connection");
- }
-
- ALOGD("Client connected: %s\n", inet_ntoa(client.sin_addr));
-// fcntl(clientSock, F_SETFL, O_NONBLOCK);
-}
-
-void StopDebugServer()
-{
- ALOGD("GLESv2_dbg: StopDebugServer");
- if (clientSock > 0) {
- close(clientSock);
- clientSock = -1;
- }
- if (serverSock > 0) {
- close(serverSock);
- serverSock = -1;
- }
- if (file) {
- fclose(file);
- file = NULL;
- }
-}
-
-void Receive(glesv2debugger::Message & cmd)
-{
- if (clientSock < 0)
- return;
- unsigned len = 0;
- int received = recv(clientSock, &len, 4, MSG_WAITALL);
- if (received < 0)
- Die("Failed to receive response length");
- else if (4 != received) {
- ALOGD("received %dB: %.8X", received, len);
- Die("Received length mismatch, expected 4");
- }
- static void * buffer = NULL;
- static unsigned bufferSize = 0;
- if (bufferSize < len) {
- buffer = realloc(buffer, len);
- assert(buffer);
- bufferSize = len;
- }
- received = recv(clientSock, buffer, len, MSG_WAITALL);
- if (received < 0)
- Die("Failed to receive response");
- else if (len != received)
- Die("Received length mismatch");
- cmd.Clear();
- cmd.ParseFromArray(buffer, len);
-}
-
-bool TryReceive(glesv2debugger::Message & cmd)
-{
- if (clientSock < 0)
- return false;
- fd_set readSet;
- FD_ZERO(&readSet);
- FD_SET(clientSock, &readSet);
- timeval timeout;
- timeout.tv_sec = timeout.tv_usec = 0;
-
- int rc = select(clientSock + 1, &readSet, NULL, NULL, &timeout);
- if (rc < 0)
- Die("failed to select clientSock");
-
- bool received = false;
- if (FD_ISSET(clientSock, &readSet)) {
- ALOGD("TryReceive: avaiable for read");
- Receive(cmd);
- return true;
- }
- return false;
-}
-
-float Send(const glesv2debugger::Message & msg, glesv2debugger::Message & cmd)
-{
- // TODO: use per DbgContext send/receive buffer and async socket
- // instead of mutex and blocking io; watch out for large messages
- static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
- struct Autolock {
- Autolock() {
- pthread_mutex_lock(&mutex);
- }
- ~Autolock() {
- pthread_mutex_unlock(&mutex);
- }
- } autolock;
-
- if (msg.function() != glesv2debugger::Message_Function_ACK)
- assert(msg.has_context_id() && msg.context_id() != 0);
- static std::string str;
- msg.SerializeToString(&str);
- const uint32_t len = str.length();
- if (clientSock < 0) {
- if (file) {
- fwrite(&len, sizeof(len), 1, file);
- fwrite(str.data(), len, 1, file);
- if (ftell(file) >= MAX_FILE_SIZE) {
- fclose(file);
- Die("MAX_FILE_SIZE reached");
- }
- }
- return 0;
- }
- int sent = -1;
- sent = send(clientSock, &len, sizeof(len), 0);
- if (sent != sizeof(len)) {
- ALOGD("actual sent=%d expected=%d clientSock=%d", sent, sizeof(len), clientSock);
- Die("Failed to send message length");
- }
- nsecs_t c0 = systemTime(timeMode);
- sent = send(clientSock, str.data(), str.length(), 0);
- float t = (float)ns2ms(systemTime(timeMode) - c0);
- if (sent != str.length()) {
- ALOGD("actual sent=%d expected=%d clientSock=%d", sent, str.length(), clientSock);
- Die("Failed to send message");
- }
- // TODO: factor Receive & TryReceive out and into MessageLoop, or add control argument.
- // mean while, if server is sending a SETPROP then don't try to receive,
- // because server will not be processing received command
- if (msg.function() == msg.SETPROP)
- return t;
- // try to receive commands even though not expecting response,
- // since client can send SETPROP and other commands anytime
- if (!msg.expect_response()) {
- if (TryReceive(cmd)) {
- if (glesv2debugger::Message_Function_SETPROP == cmd.function())
- ALOGD("Send: TryReceived SETPROP");
- else
- ALOGD("Send: TryReceived %u", cmd.function());
- }
- } else
- Receive(cmd);
- return t;
-}
-
-void SetProp(DbgContext * const dbg, const glesv2debugger::Message & cmd)
-{
- switch (cmd.prop()) {
- case glesv2debugger::Message_Prop_CaptureDraw:
- ALOGD("SetProp Message_Prop_CaptureDraw %d", cmd.arg0());
- dbg->captureDraw = cmd.arg0();
- break;
- case glesv2debugger::Message_Prop_TimeMode:
- ALOGD("SetProp Message_Prop_TimeMode %d", cmd.arg0());
- timeMode = cmd.arg0();
- break;
- case glesv2debugger::Message_Prop_ExpectResponse:
- ALOGD("SetProp Message_Prop_ExpectResponse %d=%d", cmd.arg0(), cmd.arg1());
- dbg->expectResponse.Bit((glesv2debugger::Message_Function)cmd.arg0(), cmd.arg1());
- break;
- case glesv2debugger::Message_Prop_CaptureSwap:
- ALOGD("SetProp CaptureSwap %d", cmd.arg0());
- dbg->captureSwap = cmd.arg0();
- break;
- default:
- assert(0);
- }
-}
-
-int * MessageLoop(FunctionCall & functionCall, glesv2debugger::Message & msg,
- const glesv2debugger::Message_Function function)
-{
- DbgContext * const dbg = getDbgContextThreadSpecific();
- const int * ret = 0;
- glesv2debugger::Message cmd;
- msg.set_context_id(reinterpret_cast<int>(dbg));
- msg.set_type(glesv2debugger::Message_Type_BeforeCall);
- bool expectResponse = dbg->expectResponse.Bit(function);
- msg.set_expect_response(expectResponse);
- msg.set_function(function);
-
- // when not exectResponse, set cmd to CONTINUE then SKIP
- // cmd will be overwritten by received command
- cmd.set_function(glesv2debugger::Message_Function_CONTINUE);
- cmd.set_expect_response(expectResponse);
- glesv2debugger::Message_Function oldCmd = cmd.function();
- Send(msg, cmd);
- expectResponse = cmd.expect_response();
- while (true) {
- msg.Clear();
- nsecs_t c0 = systemTime(timeMode);
- switch (cmd.function()) {
- case glesv2debugger::Message_Function_CONTINUE:
- ret = functionCall(&dbg->hooks->gl, msg);
- while (GLenum error = dbg->hooks->gl.glGetError())
- ALOGD("Function=%u glGetError() = 0x%.4X", function, error);
- if (!msg.has_time()) // some has output data copy, so time inside call
- msg.set_time((systemTime(timeMode) - c0) * 1e-6f);
- msg.set_context_id(reinterpret_cast<int>(dbg));
- msg.set_function(function);
- msg.set_type(glesv2debugger::Message_Type_AfterCall);
- msg.set_expect_response(expectResponse);
- if (!expectResponse) {
- cmd.set_function(glesv2debugger::Message_Function_SKIP);
- cmd.set_expect_response(false);
- }
- oldCmd = cmd.function();
- Send(msg, cmd);
- expectResponse = cmd.expect_response();
- break;
- case glesv2debugger::Message_Function_SKIP:
- return const_cast<int *>(ret);
- case glesv2debugger::Message_Function_SETPROP:
- SetProp(dbg, cmd);
- expectResponse = cmd.expect_response();
- if (!expectResponse) // SETPROP is "out of band"
- cmd.set_function(oldCmd);
- else
- Receive(cmd);
- break;
- default:
- ret = GenerateCall(dbg, cmd, msg, ret);
- msg.set_expect_response(expectResponse);
- if (!expectResponse) {
- cmd.set_function(cmd.SKIP);
- cmd.set_expect_response(expectResponse);
- }
- oldCmd = cmd.function();
- Send(msg, cmd);
- expectResponse = cmd.expect_response();
- break;
- }
- }
- return 0;
-}
-}; // namespace android {
diff --git a/opengl/libs/GLES2_dbg/src/vertex.cpp b/opengl/libs/GLES2_dbg/src/vertex.cpp
deleted file mode 100644
index 70c3433..0000000
--- a/opengl/libs/GLES2_dbg/src/vertex.cpp
+++ /dev/null
@@ -1,214 +0,0 @@
-/*
- ** Copyright 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.
- ** 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.
- */
-
-#include "header.h"
-
-namespace android
-{
-bool capture; // capture after each glDraw*
-}
-
-void Debug_glDrawArrays(GLenum mode, GLint first, GLsizei count)
-{
- DbgContext * const dbg = getDbgContextThreadSpecific();
- glesv2debugger::Message msg, cmd;
- msg.set_context_id(reinterpret_cast<int>(dbg));
- msg.set_type(glesv2debugger::Message_Type_BeforeCall);
- bool expectResponse = dbg->expectResponse.Bit(glesv2debugger::Message_Function_glDrawArrays);
- msg.set_expect_response(expectResponse);
- msg.set_function(glesv2debugger::Message_Function_glDrawArrays);
- msg.set_arg0(mode);
- msg.set_arg1(first);
- msg.set_arg2(count);
-
- msg.set_arg7(dbg->maxAttrib); // indicate capturing vertex data
- if (dbg->hasNonVBOAttribs) {
- std::string * const data = msg.mutable_data();
- for (unsigned i = 0; i < count; i++)
- dbg->Fetch(i + first, data);
- }
-
- void * pixels = NULL;
- int viewport[4] = {};
- cmd.set_function(glesv2debugger::Message_Function_CONTINUE);
- cmd.set_expect_response(expectResponse);
- glesv2debugger::Message_Function oldCmd = cmd.function();
- Send(msg, cmd);
- expectResponse = cmd.expect_response();
- while (true) {
- msg.Clear();
- nsecs_t c0 = systemTime(timeMode);
- switch (cmd.function()) {
- case glesv2debugger::Message_Function_CONTINUE:
- dbg->hooks->gl.glDrawArrays(mode, first, count);
- msg.set_time((systemTime(timeMode) - c0) * 1e-6f);
- msg.set_context_id(reinterpret_cast<int>(dbg));
- msg.set_function(glesv2debugger::Message_Function_glDrawArrays);
- msg.set_type(glesv2debugger::Message_Type_AfterCall);
- msg.set_expect_response(expectResponse);
- if (!expectResponse) {
- cmd.set_function(glesv2debugger::Message_Function_SKIP);
- cmd.set_expect_response(false);
- }
- oldCmd = cmd.function();
- Send(msg, cmd);
- expectResponse = cmd.expect_response();
- // TODO: pack glReadPixels data with vertex data instead of
- // relying on sperate call for transport, this would allow
- // auto generated message loop using EXTEND_Debug macro
- if (dbg->captureDraw > 0) {
- dbg->captureDraw--;
- dbg->hooks->gl.glGetIntegerv(GL_VIEWPORT, viewport);
-// ALOGD("glDrawArrays CAPTURE: x=%d y=%d width=%d height=%d format=0x%.4X type=0x%.4X",
-// viewport[0], viewport[1], viewport[2], viewport[3], readFormat, readType);
- pixels = dbg->GetReadPixelsBuffer(viewport[2] * viewport[3] *
- dbg->readBytesPerPixel);
- Debug_glReadPixels(viewport[0], viewport[1], viewport[2], viewport[3],
- GL_RGBA, GL_UNSIGNED_BYTE, pixels);
- }
- break;
- case glesv2debugger::Message_Function_SKIP:
- return;
- case glesv2debugger::Message_Function_SETPROP:
- SetProp(dbg, cmd);
- expectResponse = cmd.expect_response();
- if (!expectResponse) // SETPROP is "out of band"
- cmd.set_function(oldCmd);
- else
- Receive(cmd);
- break;
- default:
- GenerateCall(dbg, cmd, msg, NULL);
- msg.set_expect_response(expectResponse);
- if (!expectResponse) {
- cmd.set_function(cmd.SKIP);
- cmd.set_expect_response(expectResponse);
- }
- oldCmd = cmd.function();
- Send(msg, cmd);
- expectResponse = cmd.expect_response();
- break;
- }
- }
-}
-
-template<typename T>
-static inline void FetchIndexed(const unsigned count, const T * indices,
- std::string * const data, const DbgContext * const ctx)
-{
- for (unsigned i = 0; i < count; i++) {
- if (!ctx->indexBuffer)
- data->append((const char *)(indices + i), sizeof(*indices));
- if (ctx->hasNonVBOAttribs)
- ctx->Fetch(indices[i], data);
- }
-}
-
-void Debug_glDrawElements(GLenum mode, GLsizei count, GLenum type, const GLvoid* indices)
-{
- DbgContext * const dbg = getDbgContextThreadSpecific();
- glesv2debugger::Message msg, cmd;
- msg.set_context_id(reinterpret_cast<int>(dbg));
- msg.set_type(glesv2debugger::Message_Type_BeforeCall);
- bool expectResponse = dbg->expectResponse.Bit(glesv2debugger::Message_Function_glDrawElements);
- msg.set_expect_response(expectResponse);
- msg.set_function(glesv2debugger::Message_Function_glDrawElements);
- msg.set_arg0(mode);
- msg.set_arg1(count);
- msg.set_arg2(type);
- msg.set_arg3(reinterpret_cast<int>(indices));
-
- msg.set_arg7(dbg->maxAttrib); // indicate capturing vertex data
- std::string * const data = msg.mutable_data();
- if (GL_UNSIGNED_BYTE == type) {
- if (dbg->indexBuffer) {
- FetchIndexed(count, (unsigned char *)dbg->indexBuffer->data +
- (unsigned long)indices, data, dbg);
- } else {
- FetchIndexed(count, (unsigned char *)indices, data, dbg);
- }
- } else if (GL_UNSIGNED_SHORT == type) {
- if (dbg->indexBuffer) {
- FetchIndexed(count, (unsigned short *)((char *)dbg->indexBuffer->data +
- (unsigned long)indices), data, dbg);
- } else {
- FetchIndexed(count, (unsigned short *)indices, data, dbg);
- }
- } else {
- assert(0);
- }
-
- void * pixels = NULL;
- int viewport[4] = {};
- cmd.set_function(glesv2debugger::Message_Function_CONTINUE);
- cmd.set_expect_response(expectResponse);
- glesv2debugger::Message_Function oldCmd = cmd.function();
- Send(msg, cmd);
- expectResponse = cmd.expect_response();
- while (true) {
- msg.Clear();
- nsecs_t c0 = systemTime(timeMode);
- switch (cmd.function()) {
- case glesv2debugger::Message_Function_CONTINUE:
- dbg->hooks->gl.glDrawElements(mode, count, type, indices);
- msg.set_time((systemTime(timeMode) - c0) * 1e-6f);
- msg.set_context_id(reinterpret_cast<int>(dbg));
- msg.set_function(glesv2debugger::Message_Function_glDrawElements);
- msg.set_type(glesv2debugger::Message_Type_AfterCall);
- msg.set_expect_response(expectResponse);
- if (!expectResponse) {
- cmd.set_function(glesv2debugger::Message_Function_SKIP);
- cmd.set_expect_response(false);
- }
- oldCmd = cmd.function();
- Send(msg, cmd);
- expectResponse = cmd.expect_response();
- // TODO: pack glReadPixels data with vertex data instead of
- // relying on separate call for transport, this would allow
- // auto generated message loop using EXTEND_Debug macro
- if (dbg->captureDraw > 0) {
- dbg->captureDraw--;
- dbg->hooks->gl.glGetIntegerv(GL_VIEWPORT, viewport);
- pixels = dbg->GetReadPixelsBuffer(viewport[2] * viewport[3] *
- dbg->readBytesPerPixel);
- Debug_glReadPixels(viewport[0], viewport[1], viewport[2], viewport[3],
- GL_RGBA, GL_UNSIGNED_BYTE, pixels);
- }
- break;
- case glesv2debugger::Message_Function_SKIP:
- return;
- case glesv2debugger::Message_Function_SETPROP:
- SetProp(dbg, cmd);
- expectResponse = cmd.expect_response();
- if (!expectResponse) // SETPROP is "out of band"
- cmd.set_function(oldCmd);
- else
- Receive(cmd);
- break;
- default:
- GenerateCall(dbg, cmd, msg, NULL);
- msg.set_expect_response(expectResponse);
- if (!expectResponse) {
- cmd.set_function(cmd.SKIP);
- cmd.set_expect_response(expectResponse);
- }
- oldCmd = cmd.function();
- Send(msg, cmd);
- expectResponse = cmd.expect_response();
- break;
- }
- }
-}
diff --git a/opengl/libs/GLES2_dbg/test/Android.mk b/opengl/libs/GLES2_dbg/test/Android.mk
deleted file mode 100644
index 8708d43..0000000
--- a/opengl/libs/GLES2_dbg/test/Android.mk
+++ /dev/null
@@ -1,37 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-
-include $(CLEAR_VARS)
-
-LOCAL_C_INCLUDES := \
- $(LOCAL_PATH) \
- $(LOCAL_PATH)/../src \
- $(LOCAL_PATH)/../../ \
- external/gtest/include \
- external/stlport/stlport \
- external/protobuf/src \
- bionic \
- external \
-#
-
-LOCAL_SRC_FILES:= \
- test_main.cpp \
- test_server.cpp \
- test_socket.cpp \
-#
-
-LOCAL_SHARED_LIBRARIES := libcutils libutils libGLESv2_dbg libstlport
-LOCAL_STATIC_LIBRARIES := libgtest libprotobuf-cpp-2.3.0-lite liblzf
-LOCAL_MODULE_TAGS := tests
-LOCAL_MODULE:= libGLESv2_dbg_test
-
-ifeq ($(ARCH_ARM_HAVE_TLS_REGISTER),true)
- LOCAL_CFLAGS += -DHAVE_ARM_TLS_REGISTER
-endif
-LOCAL_C_INCLUDES += bionic/libc/private
-
-LOCAL_CFLAGS += -DLOG_TAG=\"libEGL\"
-LOCAL_CFLAGS += -DGL_GLEXT_PROTOTYPES -DEGL_EGLEXT_PROTOTYPES
-LOCAL_CFLAGS += -fvisibility=hidden
-
-include $(BUILD_EXECUTABLE)
-
diff --git a/opengl/libs/GLES2_dbg/test/test_main.cpp b/opengl/libs/GLES2_dbg/test/test_main.cpp
deleted file mode 100644
index 183bf8e..0000000
--- a/opengl/libs/GLES2_dbg/test/test_main.cpp
+++ /dev/null
@@ -1,234 +0,0 @@
-/*
- ** Copyright 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.
- ** 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.
- */
-
-#include "header.h"
-#include "gtest/gtest.h"
-#include "hooks.h"
-
-namespace
-{
-
-// The fixture for testing class Foo.
-class DbgContextTest : public ::testing::Test
-{
-protected:
- android::DbgContext dbg;
- gl_hooks_t hooks;
-
- DbgContextTest()
- : dbg(1, &hooks, 32) {
- // You can do set-up work for each test here.
- hooks.gl.glGetError = GetError;
- }
-
- static GLenum GetError() {
- return GL_NO_ERROR;
- }
-
- virtual ~DbgContextTest() {
- // You can do clean-up work that doesn't throw exceptions here.
- }
-
- // If the constructor and destructor are not enough for setting up
- // and cleaning up each test, you can define the following methods:
-
- virtual void SetUp() {
- // Code here will be called immediately after the constructor (right
- // before each test).
- }
-
- virtual void TearDown() {
- // Code here will be called immediately after each test (right
- // before the destructor).
- }
-};
-
-TEST_F(DbgContextTest, GetReadPixelBuffer)
-{
- const unsigned int bufferSize = 512;
- // test that it's allocating two buffers and swapping them
- void * const buffer0 = dbg.GetReadPixelsBuffer(bufferSize);
- ASSERT_NE((void *)NULL, buffer0);
- for (unsigned int i = 0; i < bufferSize / sizeof(unsigned int); i++) {
- EXPECT_EQ(0, ((unsigned int *)buffer0)[i])
- << "GetReadPixelsBuffer should allocate and zero";
- ((unsigned int *)buffer0)[i] = i * 13;
- }
-
- void * const buffer1 = dbg.GetReadPixelsBuffer(bufferSize);
- ASSERT_NE((void *)NULL, buffer1);
- EXPECT_NE(buffer0, buffer1);
- for (unsigned int i = 0; i < bufferSize / sizeof(unsigned int); i++) {
- EXPECT_EQ(0, ((unsigned int *)buffer1)[i])
- << "GetReadPixelsBuffer should allocate and zero";
- ((unsigned int *)buffer1)[i] = i * 17;
- }
-
- void * const buffer2 = dbg.GetReadPixelsBuffer(bufferSize);
- EXPECT_EQ(buffer2, buffer0);
- for (unsigned int i = 0; i < bufferSize / sizeof(unsigned int); i++)
- EXPECT_EQ(i * 13, ((unsigned int *)buffer2)[i])
- << "GetReadPixelsBuffer should swap buffers";
-
- void * const buffer3 = dbg.GetReadPixelsBuffer(bufferSize);
- EXPECT_EQ(buffer3, buffer1);
- for (unsigned int i = 0; i < bufferSize / sizeof(unsigned int); i++)
- EXPECT_EQ(i * 17, ((unsigned int *)buffer3)[i])
- << "GetReadPixelsBuffer should swap buffers";
-
- void * const buffer4 = dbg.GetReadPixelsBuffer(bufferSize);
- EXPECT_NE(buffer3, buffer4);
- EXPECT_EQ(buffer0, buffer2);
- EXPECT_EQ(buffer1, buffer3);
- EXPECT_EQ(buffer2, buffer4);
-
- // it reallocs as necessary; 0 size may result in NULL
- for (unsigned int i = 0; i < 42; i++) {
- void * const buffer = dbg.GetReadPixelsBuffer(((i & 7)) << 20);
- EXPECT_NE((void *)NULL, buffer)
- << "should be able to get a variety of reasonable sizes";
- EXPECT_TRUE(dbg.IsReadPixelBuffer(buffer));
- }
-}
-
-TEST_F(DbgContextTest, CompressReadPixelBuffer)
-{
- const unsigned int bufferSize = dbg.LZF_CHUNK_SIZE * 4 + 33;
- std::string out;
- unsigned char * buffer = (unsigned char *)dbg.GetReadPixelsBuffer(bufferSize);
- for (unsigned int i = 0; i < bufferSize; i++)
- buffer[i] = i * 13;
- dbg.CompressReadPixelBuffer(&out);
- uint32_t decompSize = 0;
- ASSERT_LT(12, out.length()); // at least written chunk header
- ASSERT_EQ(bufferSize, *(uint32_t *)out.data())
- << "total decompressed size should be as requested in GetReadPixelsBuffer";
- for (unsigned int i = 4; i < out.length();) {
- const uint32_t outSize = *(uint32_t *)(out.data() + i);
- i += 4;
- const uint32_t inSize = *(uint32_t *)(out.data() + i);
- i += 4;
- if (inSize == 0)
- i += outSize; // chunk not compressed
- else
- i += inSize; // skip the actual compressed chunk
- decompSize += outSize;
- }
- ASSERT_EQ(bufferSize, decompSize);
- decompSize = 0;
-
- unsigned char * decomp = dbg.Decompress(out.data(), out.length(), &decompSize);
- ASSERT_EQ(decompSize, bufferSize);
- for (unsigned int i = 0; i < bufferSize; i++)
- EXPECT_EQ((unsigned char)(i * 13), decomp[i]) << "xor with 0 ref is identity";
- free(decomp);
-
- buffer = (unsigned char *)dbg.GetReadPixelsBuffer(bufferSize);
- for (unsigned int i = 0; i < bufferSize; i++)
- buffer[i] = i * 13;
- out.clear();
- dbg.CompressReadPixelBuffer(&out);
- decompSize = 0;
- decomp = dbg.Decompress(out.data(), out.length(), &decompSize);
- ASSERT_EQ(decompSize, bufferSize);
- for (unsigned int i = 0; i < bufferSize; i++)
- EXPECT_EQ(0, decomp[i]) << "xor with same ref is 0";
- free(decomp);
-
- buffer = (unsigned char *)dbg.GetReadPixelsBuffer(bufferSize);
- for (unsigned int i = 0; i < bufferSize; i++)
- buffer[i] = i * 19;
- out.clear();
- dbg.CompressReadPixelBuffer(&out);
- decompSize = 0;
- decomp = dbg.Decompress(out.data(), out.length(), &decompSize);
- ASSERT_EQ(decompSize, bufferSize);
- for (unsigned int i = 0; i < bufferSize; i++)
- EXPECT_EQ((unsigned char)(i * 13) ^ (unsigned char)(i * 19), decomp[i])
- << "xor ref";
- free(decomp);
-}
-
-TEST_F(DbgContextTest, UseProgram)
-{
- static const GLuint _program = 74568;
- static const struct Attribute {
- const char * name;
- GLint location;
- GLint size;
- GLenum type;
- } _attributes [] = {
- {"aaa", 2, 2, GL_FLOAT_VEC2},
- {"bb", 6, 2, GL_FLOAT_MAT2},
- {"c", 1, 1, GL_FLOAT},
- };
- static const unsigned int _attributeCount = sizeof(_attributes) / sizeof(*_attributes);
- struct GL {
- static void GetProgramiv(GLuint program, GLenum pname, GLint* params) {
- EXPECT_EQ(_program, program);
- ASSERT_NE((GLint *)NULL, params);
- switch (pname) {
- case GL_ACTIVE_ATTRIBUTES:
- *params = _attributeCount;
- return;
- case GL_ACTIVE_ATTRIBUTE_MAX_LENGTH:
- *params = 4; // includes NULL terminator
- return;
- default:
- ADD_FAILURE() << "not handled pname: " << pname;
- }
- }
-
- static GLint GetAttribLocation(GLuint program, const GLchar* name) {
- EXPECT_EQ(_program, program);
- for (unsigned int i = 0; i < _attributeCount; i++)
- if (!strcmp(name, _attributes[i].name))
- return _attributes[i].location;
- ADD_FAILURE() << "unknown attribute name: " << name;
- return -1;
- }
-
- static void GetActiveAttrib(GLuint program, GLuint index, GLsizei bufsize,
- GLsizei* length, GLint* size, GLenum* type, GLchar* name) {
- EXPECT_EQ(_program, program);
- ASSERT_LT(index, _attributeCount);
- const Attribute & att = _attributes[index];
- ASSERT_GE(bufsize, strlen(att.name) + 1);
- ASSERT_NE((GLint *)NULL, size);
- ASSERT_NE((GLenum *)NULL, type);
- ASSERT_NE((GLchar *)NULL, name);
- strcpy(name, att.name);
- if (length)
- *length = strlen(name) + 1;
- *size = att.size;
- *type = att.type;
- }
- };
- hooks.gl.glGetProgramiv = GL::GetProgramiv;
- hooks.gl.glGetAttribLocation = GL::GetAttribLocation;
- hooks.gl.glGetActiveAttrib = GL::GetActiveAttrib;
- dbg.glUseProgram(_program);
- EXPECT_EQ(10, dbg.maxAttrib);
- dbg.glUseProgram(0);
- EXPECT_EQ(0, dbg.maxAttrib);
-}
-} // namespace
-
-int main(int argc, char **argv)
-{
- ::testing::InitGoogleTest(&argc, argv);
- return RUN_ALL_TESTS();
-}
diff --git a/opengl/libs/GLES2_dbg/test/test_server.cpp b/opengl/libs/GLES2_dbg/test/test_server.cpp
deleted file mode 100644
index 0ab87b0..0000000
--- a/opengl/libs/GLES2_dbg/test/test_server.cpp
+++ /dev/null
@@ -1,245 +0,0 @@
-/*
- ** Copyright 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.
- ** 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.
- */
-
-#include "header.h"
-#include "gtest/gtest.h"
-#include "hooks.h"
-
-namespace android
-{
-extern FILE * file;
-extern unsigned int MAX_FILE_SIZE;
-};
-
-// tmpfile fails, so need to manually make a writable file first
-static const char * filePath = "/data/local/tmp/dump.gles2dbg";
-
-class ServerFileTest : public ::testing::Test
-{
-protected:
- ServerFileTest() { }
-
- virtual ~ServerFileTest() { }
-
- virtual void SetUp() {
- MAX_FILE_SIZE = 8 << 20;
- ASSERT_EQ((FILE *)NULL, file);
- file = fopen("/data/local/tmp/dump.gles2dbg", "wb+");
- ASSERT_NE((FILE *)NULL, file) << "make sure file is writable: "
- << filePath;
- }
-
- virtual void TearDown() {
- ASSERT_NE((FILE *)NULL, file);
- fclose(file);
- file = NULL;
- }
-
- void Read(glesv2debugger::Message & msg) const {
- msg.Clear();
- uint32_t len = 0;
- ASSERT_EQ(sizeof(len), fread(&len, 1, sizeof(len), file));
- ASSERT_GT(len, 0u);
- char * buffer = new char [len];
- ASSERT_EQ(len, fread(buffer, 1, len, file));
- msg.ParseFromArray(buffer, len);
- delete buffer;
- }
-
- void CheckNoAvailable() {
- const long pos = ftell(file);
- fseek(file, 0, SEEK_END);
- EXPECT_EQ(pos, ftell(file)) << "check no available";
- }
-};
-
-TEST_F(ServerFileTest, Send)
-{
- glesv2debugger::Message msg, cmd, read;
- msg.set_context_id(1);
- msg.set_function(msg.glFinish);
- msg.set_expect_response(false);
- msg.set_type(msg.BeforeCall);
- rewind(file);
- android::Send(msg, cmd);
- rewind(file);
- Read(read);
- EXPECT_EQ(msg.context_id(), read.context_id());
- EXPECT_EQ(msg.function(), read.function());
- EXPECT_EQ(msg.expect_response(), read.expect_response());
- EXPECT_EQ(msg.type(), read.type());
-}
-
-TEST_F(ServerFileTest, CreateDbgContext)
-{
- gl_hooks_t hooks;
- struct Constant {
- GLenum pname;
- GLint param;
- };
- static const Constant constants [] = {
- {GL_MAX_VERTEX_ATTRIBS, 16},
- {GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS, 32},
- {GL_IMPLEMENTATION_COLOR_READ_FORMAT, GL_RGBA},
- {GL_IMPLEMENTATION_COLOR_READ_TYPE, GL_UNSIGNED_BYTE},
- };
- struct HookMock {
- static void GetIntegerv(GLenum pname, GLint* params) {
- ASSERT_TRUE(params != NULL);
- for (unsigned int i = 0; i < sizeof(constants) / sizeof(*constants); i++)
- if (pname == constants[i].pname) {
- *params = constants[i].param;
- return;
- }
- FAIL() << "GetIntegerv unknown pname: " << pname;
- }
- static GLenum GetError() {
- return GL_NO_ERROR;
- }
- };
- hooks.gl.glGetError = HookMock::GetError;
- hooks.gl.glGetIntegerv = HookMock::GetIntegerv;
- DbgContext * const dbg = CreateDbgContext(1, &hooks);
- ASSERT_TRUE(dbg != NULL);
- EXPECT_TRUE(dbg->vertexAttribs != NULL);
-
- rewind(file);
- glesv2debugger::Message read;
- for (unsigned int i = 0; i < 2; i++) {
- Read(read);
- EXPECT_EQ(reinterpret_cast<int>(dbg), read.context_id());
- EXPECT_FALSE(read.expect_response());
- EXPECT_EQ(read.Response, read.type());
- EXPECT_EQ(read.SETPROP, read.function());
- EXPECT_EQ(read.GLConstant, read.prop());
- GLint expectedConstant = 0;
- HookMock::GetIntegerv(read.arg0(), &expectedConstant);
- EXPECT_EQ(expectedConstant, read.arg1());
- }
- CheckNoAvailable();
- dbgReleaseThread();
-}
-
-void * glNoop()
-{
- return 0;
-}
-
-class ServerFileContextTest : public ServerFileTest
-{
-protected:
- DbgContext* dbg;
- gl_hooks_t hooks;
-
- ServerFileContextTest() { }
-
- virtual ~ServerFileContextTest() { }
-
- virtual void SetUp() {
- ServerFileTest::SetUp();
-
- dbg = new DbgContext(1, &hooks, 32);
- ASSERT_NE((void *)NULL, dbg);
- for (unsigned int i = 0; i < sizeof(hooks) / sizeof(void *); i++)
- ((void **)&hooks)[i] = reinterpret_cast<void *>(glNoop);
- }
-
- virtual void TearDown() {
- ServerFileTest::TearDown();
- }
-};
-
-TEST_F(ServerFileContextTest, MessageLoop)
-{
- static const int arg0 = 45;
- static const float arg7 = -87.2331f;
- static const int arg8 = -3;
- static const int * ret = reinterpret_cast<int *>(870);
-
- struct Caller : public FunctionCall {
- const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
- msg.set_arg0(arg0);
- msg.set_arg7((int &)arg7);
- msg.set_arg8(arg8);
- return ret;
- }
- } caller;
- const int contextId = reinterpret_cast<int>(dbg);
- glesv2debugger::Message msg, read;
-
- EXPECT_EQ(ret, MessageLoop(caller, msg, msg.glFinish));
-
- rewind(file);
- Read(read);
- EXPECT_EQ(contextId, read.context_id());
- EXPECT_EQ(read.glFinish, read.function());
- EXPECT_EQ(false, read.expect_response());
- EXPECT_EQ(read.BeforeCall, read.type());
-
- Read(read);
- EXPECT_EQ(contextId, read.context_id());
- EXPECT_EQ(read.glFinish, read.function());
- EXPECT_EQ(false, read.expect_response());
- EXPECT_EQ(read.AfterCall, read.type());
- EXPECT_TRUE(read.has_time());
- EXPECT_EQ(arg0, read.arg0());
- const int readArg7 = read.arg7();
- EXPECT_EQ(arg7, (float &)readArg7);
- EXPECT_EQ(arg8, read.arg8());
-
- const long pos = ftell(file);
- fseek(file, 0, SEEK_END);
- EXPECT_EQ(pos, ftell(file))
- << "should only write the BeforeCall and AfterCall messages";
-}
-
-TEST_F(ServerFileContextTest, DisableEnableVertexAttribArray)
-{
- Debug_glEnableVertexAttribArray(dbg->MAX_VERTEX_ATTRIBS + 2); // should just ignore invalid index
-
- glesv2debugger::Message read;
- rewind(file);
- Read(read);
- EXPECT_EQ(read.glEnableVertexAttribArray, read.function());
- EXPECT_EQ(dbg->MAX_VERTEX_ATTRIBS + 2, read.arg0());
- Read(read);
-
- rewind(file);
- Debug_glDisableVertexAttribArray(dbg->MAX_VERTEX_ATTRIBS + 4); // should just ignore invalid index
- rewind(file);
- Read(read);
- Read(read);
-
- for (unsigned int i = 0; i < dbg->MAX_VERTEX_ATTRIBS; i += 5) {
- rewind(file);
- Debug_glEnableVertexAttribArray(i);
- EXPECT_TRUE(dbg->vertexAttribs[i].enabled);
- rewind(file);
- Read(read);
- EXPECT_EQ(read.glEnableVertexAttribArray, read.function());
- EXPECT_EQ(i, read.arg0());
- Read(read);
-
- rewind(file);
- Debug_glDisableVertexAttribArray(i);
- EXPECT_FALSE(dbg->vertexAttribs[i].enabled);
- rewind(file);
- Read(read);
- EXPECT_EQ(read.glDisableVertexAttribArray, read.function());
- EXPECT_EQ(i, read.arg0());
- Read(read);
- }
-}
diff --git a/opengl/libs/GLES2_dbg/test/test_socket.cpp b/opengl/libs/GLES2_dbg/test/test_socket.cpp
deleted file mode 100644
index 9f815e2..0000000
--- a/opengl/libs/GLES2_dbg/test/test_socket.cpp
+++ /dev/null
@@ -1,468 +0,0 @@
-/*
- ** Copyright 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.
- ** 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.
- */
-
-#include <sys/socket.h>
-#include <sys/ioctl.h>
-
-#include "header.h"
-#include "gtest/gtest.h"
-#include "hooks.h"
-
-namespace android
-{
-extern int serverSock, clientSock;
-};
-
-void * glNoop();
-
-class SocketContextTest : public ::testing::Test
-{
-protected:
- DbgContext* dbg;
- gl_hooks_t hooks;
- int sock;
- char * buffer;
- unsigned int bufferSize;
-
- SocketContextTest() : sock(-1) {
- }
-
- virtual ~SocketContextTest() {
- }
-
- virtual void SetUp() {
- dbg = new DbgContext(1, &hooks, 32);
- ASSERT_TRUE(dbg != NULL);
- for (unsigned int i = 0; i < sizeof(hooks) / sizeof(void *); i++)
- ((void **)&hooks)[i] = (void *)glNoop;
-
- int socks[2] = {-1, -1};
- ASSERT_EQ(0, socketpair(AF_UNIX, SOCK_STREAM, 0, socks));
- clientSock = socks[0];
- sock = socks[1];
-
- bufferSize = 128;
- buffer = new char [128];
- ASSERT_NE((char *)NULL, buffer);
- }
-
- virtual void TearDown() {
- close(sock);
- close(clientSock);
- clientSock = -1;
- delete buffer;
- }
-
- void Write(glesv2debugger::Message & msg) const {
- msg.set_context_id((int)dbg);
- msg.set_type(msg.Response);
- ASSERT_TRUE(msg.has_context_id());
- ASSERT_TRUE(msg.has_function());
- ASSERT_TRUE(msg.has_type());
- ASSERT_TRUE(msg.has_expect_response());
- static std::string str;
- msg.SerializeToString(&str);
- const uint32_t len = str.length();
- ASSERT_EQ(sizeof(len), send(sock, &len, sizeof(len), 0));
- ASSERT_EQ(str.length(), send(sock, str.data(), str.length(), 0));
- }
-
- void Read(glesv2debugger::Message & msg) {
- int available = 0;
- ASSERT_EQ(0, ioctl(sock, FIONREAD, &available));
- ASSERT_GT(available, 0);
- uint32_t len = 0;
- ASSERT_EQ(sizeof(len), recv(sock, &len, sizeof(len), 0));
- if (len > bufferSize) {
- bufferSize = len;
- buffer = new char[bufferSize];
- ASSERT_TRUE(buffer != NULL);
- }
- ASSERT_EQ(len, recv(sock, buffer, len, 0));
- msg.Clear();
- msg.ParseFromArray(buffer, len);
- ASSERT_TRUE(msg.has_context_id());
- ASSERT_TRUE(msg.has_function());
- ASSERT_TRUE(msg.has_type());
- ASSERT_TRUE(msg.has_expect_response());
- }
-
- void CheckNoAvailable() {
- int available = 0;
- ASSERT_EQ(0, ioctl(sock, FIONREAD, &available));
- ASSERT_EQ(available, 0);
- }
-};
-
-TEST_F(SocketContextTest, MessageLoopSkip)
-{
- static const int arg0 = 45;
- static const float arg7 = -87.2331f;
- static const int arg8 = -3;
- static const int * ret = (int *)870;
-
- struct Caller : public FunctionCall {
- const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
- msg.set_arg0(arg0);
- msg.set_arg7((int &)arg7);
- msg.set_arg8(arg8);
- return ret;
- }
- } caller;
- glesv2debugger::Message msg, read, cmd;
- dbg->expectResponse.Bit(msg.glFinish, true);
-
- cmd.set_function(cmd.SKIP);
- cmd.set_expect_response(false);
- Write(cmd);
-
- EXPECT_NE(ret, MessageLoop(caller, msg, msg.glFinish));
-
- Read(read);
- EXPECT_EQ(read.glFinish, read.function());
- EXPECT_EQ(read.BeforeCall, read.type());
- EXPECT_NE(arg0, read.arg0());
- EXPECT_NE((int &)arg7, read.arg7());
- EXPECT_NE(arg8, read.arg8());
-
- CheckNoAvailable();
-}
-
-TEST_F(SocketContextTest, MessageLoopContinue)
-{
- static const int arg0 = GL_FRAGMENT_SHADER;
- static const int ret = -342;
- struct Caller : public FunctionCall {
- const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
- msg.set_ret(ret);
- return (int *)ret;
- }
- } caller;
- glesv2debugger::Message msg, read, cmd;
- dbg->expectResponse.Bit(msg.glCreateShader, true);
-
- cmd.set_function(cmd.CONTINUE);
- cmd.set_expect_response(false); // MessageLoop should automatically skip after continue
- Write(cmd);
-
- msg.set_arg0(arg0);
- EXPECT_EQ((int *)ret, MessageLoop(caller, msg, msg.glCreateShader));
-
- Read(read);
- EXPECT_EQ(read.glCreateShader, read.function());
- EXPECT_EQ(read.BeforeCall, read.type());
- EXPECT_EQ(arg0, read.arg0());
-
- Read(read);
- EXPECT_EQ(read.glCreateShader, read.function());
- EXPECT_EQ(read.AfterCall, read.type());
- EXPECT_EQ(ret, read.ret());
-
- CheckNoAvailable();
-}
-
-TEST_F(SocketContextTest, MessageLoopGenerateCall)
-{
- static const int ret = -342;
- static unsigned int createShader, createProgram;
- createShader = 0;
- createProgram = 0;
- struct Caller : public FunctionCall {
- const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
- const int r = (int)_c->glCreateProgram();
- msg.set_ret(r);
- return (int *)r;
- }
- static GLuint CreateShader(const GLenum type) {
- createShader++;
- return type;
- }
- static GLuint CreateProgram() {
- createProgram++;
- return ret;
- }
- } caller;
- glesv2debugger::Message msg, read, cmd;
- hooks.gl.glCreateShader = caller.CreateShader;
- hooks.gl.glCreateProgram = caller.CreateProgram;
- dbg->expectResponse.Bit(msg.glCreateProgram, true);
-
- cmd.set_function(cmd.glCreateShader);
- cmd.set_arg0(GL_FRAGMENT_SHADER);
- cmd.set_expect_response(true);
- Write(cmd);
-
- cmd.Clear();
- cmd.set_function(cmd.CONTINUE);
- cmd.set_expect_response(true);
- Write(cmd);
-
- cmd.set_function(cmd.glCreateShader);
- cmd.set_arg0(GL_VERTEX_SHADER);
- cmd.set_expect_response(false); // MessageLoop should automatically skip afterwards
- Write(cmd);
-
- EXPECT_EQ((int *)ret, MessageLoop(caller, msg, msg.glCreateProgram));
-
- Read(read);
- EXPECT_EQ(read.glCreateProgram, read.function());
- EXPECT_EQ(read.BeforeCall, read.type());
-
- Read(read);
- EXPECT_EQ(read.glCreateShader, read.function());
- EXPECT_EQ(read.AfterGeneratedCall, read.type());
- EXPECT_EQ(GL_FRAGMENT_SHADER, read.ret());
-
- Read(read);
- EXPECT_EQ(read.glCreateProgram, read.function());
- EXPECT_EQ(read.AfterCall, read.type());
- EXPECT_EQ(ret, read.ret());
-
- Read(read);
- EXPECT_EQ(read.glCreateShader, read.function());
- EXPECT_EQ(read.AfterGeneratedCall, read.type());
- EXPECT_EQ(GL_VERTEX_SHADER, read.ret());
-
- EXPECT_EQ(2, createShader);
- EXPECT_EQ(1, createProgram);
-
- CheckNoAvailable();
-}
-
-TEST_F(SocketContextTest, MessageLoopSetProp)
-{
- static const int ret = -342;
- static unsigned int createShader, createProgram;
- createShader = 0;
- createProgram = 0;
- struct Caller : public FunctionCall {
- const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
- const int r = (int)_c->glCreateProgram();
- msg.set_ret(r);
- return (int *)r;
- }
- static GLuint CreateShader(const GLenum type) {
- createShader++;
- return type;
- }
- static GLuint CreateProgram() {
- createProgram++;
- return ret;
- }
- } caller;
- glesv2debugger::Message msg, read, cmd;
- hooks.gl.glCreateShader = caller.CreateShader;
- hooks.gl.glCreateProgram = caller.CreateProgram;
- dbg->expectResponse.Bit(msg.glCreateProgram, false);
-
- cmd.set_function(cmd.SETPROP);
- cmd.set_prop(cmd.ExpectResponse);
- cmd.set_arg0(cmd.glCreateProgram);
- cmd.set_arg1(true);
- cmd.set_expect_response(true);
- Write(cmd);
-
- cmd.Clear();
- cmd.set_function(cmd.glCreateShader);
- cmd.set_arg0(GL_FRAGMENT_SHADER);
- cmd.set_expect_response(true);
- Write(cmd);
-
- cmd.set_function(cmd.SETPROP);
- cmd.set_prop(cmd.CaptureDraw);
- cmd.set_arg0(819);
- cmd.set_expect_response(true);
- Write(cmd);
-
- cmd.Clear();
- cmd.set_function(cmd.CONTINUE);
- cmd.set_expect_response(true);
- Write(cmd);
-
- cmd.set_function(cmd.glCreateShader);
- cmd.set_arg0(GL_VERTEX_SHADER);
- cmd.set_expect_response(false); // MessageLoop should automatically skip afterwards
- Write(cmd);
-
- EXPECT_EQ((int *)ret, MessageLoop(caller, msg, msg.glCreateProgram));
-
- EXPECT_TRUE(dbg->expectResponse.Bit(msg.glCreateProgram));
- EXPECT_EQ(819, dbg->captureDraw);
-
- Read(read);
- EXPECT_EQ(read.glCreateProgram, read.function());
- EXPECT_EQ(read.BeforeCall, read.type());
-
- Read(read);
- EXPECT_EQ(read.glCreateShader, read.function());
- EXPECT_EQ(read.AfterGeneratedCall, read.type());
- EXPECT_EQ(GL_FRAGMENT_SHADER, read.ret());
-
- Read(read);
- EXPECT_EQ(read.glCreateProgram, read.function());
- EXPECT_EQ(read.AfterCall, read.type());
- EXPECT_EQ(ret, read.ret());
-
- Read(read);
- EXPECT_EQ(read.glCreateShader, read.function());
- EXPECT_EQ(read.AfterGeneratedCall, read.type());
- EXPECT_EQ(GL_VERTEX_SHADER, read.ret());
-
- EXPECT_EQ(2, createShader);
- EXPECT_EQ(1, createProgram);
-
- CheckNoAvailable();
-}
-
-TEST_F(SocketContextTest, TexImage2D)
-{
- static const GLenum _target = GL_TEXTURE_2D;
- static const GLint _level = 1, _internalformat = GL_RGBA;
- static const GLsizei _width = 2, _height = 2;
- static const GLint _border = 333;
- static const GLenum _format = GL_RGB, _type = GL_UNSIGNED_SHORT_5_6_5;
- static const short _pixels [_width * _height] = {11, 22, 33, 44};
- static unsigned int texImage2D;
- texImage2D = 0;
-
- struct Caller {
- static void TexImage2D(GLenum target, GLint level, GLint internalformat,
- GLsizei width, GLsizei height, GLint border,
- GLenum format, GLenum type, const GLvoid* pixels) {
- EXPECT_EQ(_target, target);
- EXPECT_EQ(_level, level);
- EXPECT_EQ(_internalformat, internalformat);
- EXPECT_EQ(_width, width);
- EXPECT_EQ(_height, height);
- EXPECT_EQ(_border, border);
- EXPECT_EQ(_format, format);
- EXPECT_EQ(_type, type);
- EXPECT_EQ(0, memcmp(_pixels, pixels, sizeof(_pixels)));
- texImage2D++;
- }
- } caller;
- glesv2debugger::Message msg, read, cmd;
- hooks.gl.glTexImage2D = caller.TexImage2D;
- dbg->expectResponse.Bit(msg.glTexImage2D, false);
-
- Debug_glTexImage2D(_target, _level, _internalformat, _width, _height, _border,
- _format, _type, _pixels);
- EXPECT_EQ(1, texImage2D);
-
- Read(read);
- EXPECT_EQ(read.glTexImage2D, read.function());
- EXPECT_EQ(read.BeforeCall, read.type());
- EXPECT_EQ(_target, read.arg0());
- EXPECT_EQ(_level, read.arg1());
- EXPECT_EQ(_internalformat, read.arg2());
- EXPECT_EQ(_width, read.arg3());
- EXPECT_EQ(_height, read.arg4());
- EXPECT_EQ(_border, read.arg5());
- EXPECT_EQ(_format, read.arg6());
- EXPECT_EQ(_type, read.arg7());
-
- EXPECT_TRUE(read.has_data());
- uint32_t dataLen = 0;
- const unsigned char * data = dbg->Decompress(read.data().data(),
- read.data().length(), &dataLen);
- EXPECT_EQ(sizeof(_pixels), dataLen);
- if (sizeof(_pixels) == dataLen)
- EXPECT_EQ(0, memcmp(_pixels, data, sizeof(_pixels)));
-
- Read(read);
- EXPECT_EQ(read.glTexImage2D, read.function());
- EXPECT_EQ(read.AfterCall, read.type());
-
- CheckNoAvailable();
-}
-
-TEST_F(SocketContextTest, CopyTexImage2D)
-{
- static const GLenum _target = GL_TEXTURE_2D;
- static const GLint _level = 1, _internalformat = GL_RGBA;
- static const GLint _x = 9, _y = 99;
- static const GLsizei _width = 2, _height = 3;
- static const GLint _border = 333;
- static const int _pixels [_width * _height] = {11, 22, 33, 44, 55, 66};
- static unsigned int copyTexImage2D, readPixels;
- copyTexImage2D = 0, readPixels = 0;
-
- struct Caller {
- static void CopyTexImage2D(GLenum target, GLint level, GLenum internalformat,
- GLint x, GLint y, GLsizei width, GLsizei height, GLint border) {
- EXPECT_EQ(_target, target);
- EXPECT_EQ(_level, level);
- EXPECT_EQ(_internalformat, internalformat);
- EXPECT_EQ(_x, x);
- EXPECT_EQ(_y, y);
- EXPECT_EQ(_width, width);
- EXPECT_EQ(_height, height);
- EXPECT_EQ(_border, border);
- copyTexImage2D++;
- }
- static void ReadPixels(GLint x, GLint y, GLsizei width, GLsizei height,
- GLenum format, GLenum type, GLvoid* pixels) {
- EXPECT_EQ(_x, x);
- EXPECT_EQ(_y, y);
- EXPECT_EQ(_width, width);
- EXPECT_EQ(_height, height);
- EXPECT_EQ(GL_RGBA, format);
- EXPECT_EQ(GL_UNSIGNED_BYTE, type);
- ASSERT_TRUE(pixels != NULL);
- memcpy(pixels, _pixels, sizeof(_pixels));
- readPixels++;
- }
- } caller;
- glesv2debugger::Message msg, read, cmd;
- hooks.gl.glCopyTexImage2D = caller.CopyTexImage2D;
- hooks.gl.glReadPixels = caller.ReadPixels;
- dbg->expectResponse.Bit(msg.glCopyTexImage2D, false);
-
- Debug_glCopyTexImage2D(_target, _level, _internalformat, _x, _y, _width, _height,
- _border);
- ASSERT_EQ(1, copyTexImage2D);
- ASSERT_EQ(1, readPixels);
-
- Read(read);
- EXPECT_EQ(read.glCopyTexImage2D, read.function());
- EXPECT_EQ(read.BeforeCall, read.type());
- EXPECT_EQ(_target, read.arg0());
- EXPECT_EQ(_level, read.arg1());
- EXPECT_EQ(_internalformat, read.arg2());
- EXPECT_EQ(_x, read.arg3());
- EXPECT_EQ(_y, read.arg4());
- EXPECT_EQ(_width, read.arg5());
- EXPECT_EQ(_height, read.arg6());
- EXPECT_EQ(_border, read.arg7());
-
- EXPECT_TRUE(read.has_data());
- EXPECT_EQ(read.ReferencedImage, read.data_type());
- EXPECT_EQ(GL_RGBA, read.pixel_format());
- EXPECT_EQ(GL_UNSIGNED_BYTE, read.pixel_type());
- uint32_t dataLen = 0;
- unsigned char * const data = dbg->Decompress(read.data().data(),
- read.data().length(), &dataLen);
- ASSERT_EQ(sizeof(_pixels), dataLen);
- for (unsigned i = 0; i < sizeof(_pixels) / sizeof(*_pixels); i++)
- EXPECT_EQ(_pixels[i], ((const int *)data)[i]) << "xor with 0 ref is identity";
- free(data);
-
- Read(read);
- EXPECT_EQ(read.glCopyTexImage2D, read.function());
- EXPECT_EQ(read.AfterCall, read.type());
-
- CheckNoAvailable();
-}
diff --git a/opengl/libs/GLES_CM/gl.cpp b/opengl/libs/GLES_CM/gl.cpp
index 2d31a35..adeaa5b 100644
--- a/opengl/libs/GLES_CM/gl.cpp
+++ b/opengl/libs/GLES_CM/gl.cpp
@@ -165,6 +165,20 @@
#undef CALL_GL_API
#undef CALL_GL_API_RETURN
+/*
+ * glGetString() is special because we expose some extensions in the wrapper
+ */
+
+extern "C" const GLubyte * __glGetString(GLenum name);
+
+const GLubyte * glGetString(GLenum name)
+{
+ const GLubyte * ret = egl_get_string_for_current_context(name);
+ if (ret == NULL) {
+ ret = __glGetString(name);
+ }
+ return ret;
+}
/*
* These GL calls are special because they need to EGL to retrieve some
diff --git a/opengl/libs/GLES_CM/gl_api.in b/opengl/libs/GLES_CM/gl_api.in
index 7f20c4f..c8f6b0c 100644
--- a/opengl/libs/GLES_CM/gl_api.in
+++ b/opengl/libs/GLES_CM/gl_api.in
@@ -262,7 +262,7 @@
void API_ENTRY(glGetPointerv)(GLenum pname, GLvoid **params) {
CALL_GL_API(glGetPointerv, pname, params);
}
-const GLubyte * API_ENTRY(glGetString)(GLenum name) {
+const GLubyte * API_ENTRY(__glGetString)(GLenum name) {
CALL_GL_API_RETURN(glGetString, name);
}
void API_ENTRY(glGetTexEnviv)(GLenum env, GLenum pname, GLint *params) {
diff --git a/opengl/libs/GLES_CM/glext_api.in b/opengl/libs/GLES_CM/glext_api.in
index 5393fa6..268a535 100644
--- a/opengl/libs/GLES_CM/glext_api.in
+++ b/opengl/libs/GLES_CM/glext_api.in
@@ -280,15 +280,57 @@
GLboolean API_ENTRY(glIsVertexArrayOES)(GLuint array) {
CALL_GL_API_RETURN(glIsVertexArrayOES, array);
}
+void API_ENTRY(glRenderbufferStorageMultisampleAPPLE)(GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height) {
+ CALL_GL_API(glRenderbufferStorageMultisampleAPPLE, target, samples, internalformat, width, height);
+}
+void API_ENTRY(glResolveMultisampleFramebufferAPPLE)(void) {
+ CALL_GL_API(glResolveMultisampleFramebufferAPPLE);
+}
void API_ENTRY(glDiscardFramebufferEXT)(GLenum target, GLsizei numAttachments, const GLenum *attachments) {
CALL_GL_API(glDiscardFramebufferEXT, target, numAttachments, attachments);
}
+void API_ENTRY(glRenderbufferStorageMultisampleEXT)(GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height) {
+ CALL_GL_API(glRenderbufferStorageMultisampleEXT, target, samples, internalformat, width, height);
+}
+void API_ENTRY(glFramebufferTexture2DMultisampleEXT)(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level, GLsizei samples) {
+ CALL_GL_API(glFramebufferTexture2DMultisampleEXT, target, attachment, textarget, texture, level, samples);
+}
void API_ENTRY(glMultiDrawArraysEXT)(GLenum mode, GLint *first, GLsizei *count, GLsizei primcount) {
CALL_GL_API(glMultiDrawArraysEXT, mode, first, count, primcount);
}
void API_ENTRY(glMultiDrawElementsEXT)(GLenum mode, const GLsizei *count, GLenum type, const GLvoid* *indices, GLsizei primcount) {
CALL_GL_API(glMultiDrawElementsEXT, mode, count, type, indices, primcount);
}
+GLenum API_ENTRY(glGetGraphicsResetStatusEXT)(void) {
+ CALL_GL_API_RETURN(glGetGraphicsResetStatusEXT);
+}
+void API_ENTRY(glReadnPixelsEXT)(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLsizei bufSize, void *data) {
+ CALL_GL_API(glReadnPixelsEXT, x, y, width, height, format, type, bufSize, data);
+}
+void API_ENTRY(glGetnUniformfvEXT)(GLuint program, GLint location, GLsizei bufSize, float *params) {
+ CALL_GL_API(glGetnUniformfvEXT, program, location, bufSize, params);
+}
+void API_ENTRY(glGetnUniformivEXT)(GLuint program, GLint location, GLsizei bufSize, GLint *params) {
+ CALL_GL_API(glGetnUniformivEXT, program, location, bufSize, params);
+}
+void API_ENTRY(glTexStorage1DEXT)(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width) {
+ CALL_GL_API(glTexStorage1DEXT, target, levels, internalformat, width);
+}
+void API_ENTRY(glTexStorage2DEXT)(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height) {
+ CALL_GL_API(glTexStorage2DEXT, target, levels, internalformat, width, height);
+}
+void API_ENTRY(glTexStorage3DEXT)(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth) {
+ CALL_GL_API(glTexStorage3DEXT, target, levels, internalformat, width, height, depth);
+}
+void API_ENTRY(glTextureStorage1DEXT)(GLuint texture, GLenum target, GLsizei levels, GLenum internalformat, GLsizei width) {
+ CALL_GL_API(glTextureStorage1DEXT, texture, target, levels, internalformat, width);
+}
+void API_ENTRY(glTextureStorage2DEXT)(GLuint texture, GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height) {
+ CALL_GL_API(glTextureStorage2DEXT, texture, target, levels, internalformat, width, height);
+}
+void API_ENTRY(glTextureStorage3DEXT)(GLuint texture, GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth) {
+ CALL_GL_API(glTextureStorage3DEXT, texture, target, levels, internalformat, width, height, depth);
+}
void API_ENTRY(glClipPlanefIMG)(GLenum p, const GLfloat *eqn) {
CALL_GL_API(glClipPlanefIMG, p, eqn);
}
diff --git a/opengl/libs/GLES_trace/gltrace.proto b/opengl/libs/GLES_trace/gltrace.proto
index 7dde69f..11cf24f 100644
--- a/opengl/libs/GLES_trace/gltrace.proto
+++ b/opengl/libs/GLES_trace/gltrace.proto
@@ -400,6 +400,68 @@
glViewport = 374;
glWeightPointerOES = 375;
+ glActiveShaderProgramEXT = 502;
+ glAlphaFuncQCOM = 503;
+ glBeginQueryEXT = 504;
+ glBindProgramPipelineEXT = 505;
+ glBlitFramebufferANGLE = 506;
+ glCreateShaderProgramvEXT = 507;
+ glDeleteProgramPipelinesEXT = 508;
+ glDeleteQueriesEXT = 509;
+ glDrawBuffersNV = 510;
+ glEndQueryEXT = 511;
+ glFramebufferTexture2DMultisampleEXT = 512;
+ glGenProgramPipelinesEXT = 513;
+ glGenQueriesEXT = 514;
+ glGetGraphicsResetStatusEXT = 515;
+ glGetObjectLabelEXT = 516;
+ glGetProgramPipelineInfoLogEXT = 517;
+ glGetProgramPipelineivEXT = 518;
+ glGetQueryObjectuivEXT = 519;
+ glGetQueryivEXT = 520;
+ glGetnUniformfvEXT = 521;
+ glGetnUniformivEXT = 521;
+ glInsertEventMarkerEXT = 522;
+ glIsProgramPipelineEXT = 523;
+ glIsQueryEXT = 524;
+ glLabelObjectEXT = 525;
+ glPopGroupMarkerEXT = 526;
+ glProgramParameteriEXT = 527;
+ glProgramUniform1fEXT = 528;
+ glProgramUniform1fvEXT = 529;
+ glProgramUniform1iEXT = 530;
+ glProgramUniform1ivEXT = 531;
+ glProgramUniform2fEXT = 532;
+ glProgramUniform2fvEXT = 533;
+ glProgramUniform2iEXT = 534;
+ glProgramUniform2ivEXT = 535;
+ glProgramUniform3fEXT = 536;
+ glProgramUniform3fvEXT = 537;
+ glProgramUniform3iEXT = 538;
+ glProgramUniform3ivEXT = 539;
+ glProgramUniform4fEXT = 540;
+ glProgramUniform4fvEXT = 541;
+ glProgramUniform4iEXT = 542;
+ glProgramUniform4ivEXT = 543;
+ glProgramUniformMatrix2fvEXT = 544;
+ glProgramUniformMatrix3fvEXT = 545;
+ glProgramUniformMatrix4fvEXT = 546;
+ glPushGroupMarkerEXT = 547;
+ glReadBufferNV = 548;
+ glReadnPixelsEXT = 549;
+ glRenderbufferStorageMultisampleANGLE = 550;
+ glRenderbufferStorageMultisampleAPPLE = 551;
+ glRenderbufferStorageMultisampleEXT = 552;
+ glResolveMultisampleFramebufferAPPLE = 553;
+ glTexStorage1DEXT = 554;
+ glTexStorage2DEXT = 555;
+ glTexStorage3DEXT = 556;
+ glTextureStorage1DEXT = 557;
+ glTextureStorage2DEXT = 558;
+ glTextureStorage3DEXT = 559;
+ glUseProgramStagesEXT = 560;
+ glValidateProgramPipelineEXT = 561;
+
eglGetDisplay = 2000;
eglInitialize = 2001;
eglTerminate = 2002;
diff --git a/opengl/libs/GLES_trace/src/gltrace.pb.cpp b/opengl/libs/GLES_trace/src/gltrace.pb.cpp
index 9a90603..bb9d4a7 100644
--- a/opengl/libs/GLES_trace/src/gltrace.pb.cpp
+++ b/opengl/libs/GLES_trace/src/gltrace.pb.cpp
@@ -419,6 +419,66 @@
case 373:
case 374:
case 375:
+ case 502:
+ case 503:
+ case 504:
+ case 505:
+ case 506:
+ case 507:
+ case 508:
+ case 509:
+ case 510:
+ case 511:
+ case 512:
+ case 513:
+ case 514:
+ case 515:
+ case 516:
+ case 517:
+ case 518:
+ case 519:
+ case 520:
+ case 521:
+ case 522:
+ case 523:
+ case 524:
+ case 525:
+ case 526:
+ case 527:
+ case 528:
+ case 529:
+ case 530:
+ case 531:
+ case 532:
+ case 533:
+ case 534:
+ case 535:
+ case 536:
+ case 537:
+ case 538:
+ case 539:
+ case 540:
+ case 541:
+ case 542:
+ case 543:
+ case 544:
+ case 545:
+ case 546:
+ case 547:
+ case 548:
+ case 549:
+ case 550:
+ case 551:
+ case 552:
+ case 553:
+ case 554:
+ case 555:
+ case 556:
+ case 557:
+ case 558:
+ case 559:
+ case 560:
+ case 561:
case 2000:
case 2001:
case 2002:
@@ -850,6 +910,67 @@
const GLMessage_Function GLMessage::glVertexPointer;
const GLMessage_Function GLMessage::glViewport;
const GLMessage_Function GLMessage::glWeightPointerOES;
+const GLMessage_Function GLMessage::glActiveShaderProgramEXT;
+const GLMessage_Function GLMessage::glAlphaFuncQCOM;
+const GLMessage_Function GLMessage::glBeginQueryEXT;
+const GLMessage_Function GLMessage::glBindProgramPipelineEXT;
+const GLMessage_Function GLMessage::glBlitFramebufferANGLE;
+const GLMessage_Function GLMessage::glCreateShaderProgramvEXT;
+const GLMessage_Function GLMessage::glDeleteProgramPipelinesEXT;
+const GLMessage_Function GLMessage::glDeleteQueriesEXT;
+const GLMessage_Function GLMessage::glDrawBuffersNV;
+const GLMessage_Function GLMessage::glEndQueryEXT;
+const GLMessage_Function GLMessage::glFramebufferTexture2DMultisampleEXT;
+const GLMessage_Function GLMessage::glGenProgramPipelinesEXT;
+const GLMessage_Function GLMessage::glGenQueriesEXT;
+const GLMessage_Function GLMessage::glGetGraphicsResetStatusEXT;
+const GLMessage_Function GLMessage::glGetObjectLabelEXT;
+const GLMessage_Function GLMessage::glGetProgramPipelineInfoLogEXT;
+const GLMessage_Function GLMessage::glGetProgramPipelineivEXT;
+const GLMessage_Function GLMessage::glGetQueryObjectuivEXT;
+const GLMessage_Function GLMessage::glGetQueryivEXT;
+const GLMessage_Function GLMessage::glGetnUniformfvEXT;
+const GLMessage_Function GLMessage::glGetnUniformivEXT;
+const GLMessage_Function GLMessage::glInsertEventMarkerEXT;
+const GLMessage_Function GLMessage::glIsProgramPipelineEXT;
+const GLMessage_Function GLMessage::glIsQueryEXT;
+const GLMessage_Function GLMessage::glLabelObjectEXT;
+const GLMessage_Function GLMessage::glPopGroupMarkerEXT;
+const GLMessage_Function GLMessage::glProgramParameteriEXT;
+const GLMessage_Function GLMessage::glProgramUniform1fEXT;
+const GLMessage_Function GLMessage::glProgramUniform1fvEXT;
+const GLMessage_Function GLMessage::glProgramUniform1iEXT;
+const GLMessage_Function GLMessage::glProgramUniform1ivEXT;
+const GLMessage_Function GLMessage::glProgramUniform2fEXT;
+const GLMessage_Function GLMessage::glProgramUniform2fvEXT;
+const GLMessage_Function GLMessage::glProgramUniform2iEXT;
+const GLMessage_Function GLMessage::glProgramUniform2ivEXT;
+const GLMessage_Function GLMessage::glProgramUniform3fEXT;
+const GLMessage_Function GLMessage::glProgramUniform3fvEXT;
+const GLMessage_Function GLMessage::glProgramUniform3iEXT;
+const GLMessage_Function GLMessage::glProgramUniform3ivEXT;
+const GLMessage_Function GLMessage::glProgramUniform4fEXT;
+const GLMessage_Function GLMessage::glProgramUniform4fvEXT;
+const GLMessage_Function GLMessage::glProgramUniform4iEXT;
+const GLMessage_Function GLMessage::glProgramUniform4ivEXT;
+const GLMessage_Function GLMessage::glProgramUniformMatrix2fvEXT;
+const GLMessage_Function GLMessage::glProgramUniformMatrix3fvEXT;
+const GLMessage_Function GLMessage::glProgramUniformMatrix4fvEXT;
+const GLMessage_Function GLMessage::glPushGroupMarkerEXT;
+const GLMessage_Function GLMessage::glReadBufferNV;
+const GLMessage_Function GLMessage::glReadnPixelsEXT;
+const GLMessage_Function GLMessage::glRenderbufferStorageMultisampleANGLE;
+const GLMessage_Function GLMessage::glRenderbufferStorageMultisampleAPPLE;
+const GLMessage_Function GLMessage::glRenderbufferStorageMultisampleEXT;
+const GLMessage_Function GLMessage::glResolveMultisampleFramebufferAPPLE;
+const GLMessage_Function GLMessage::glTexStorage1DEXT;
+const GLMessage_Function GLMessage::glTexStorage2DEXT;
+const GLMessage_Function GLMessage::glTexStorage3DEXT;
+const GLMessage_Function GLMessage::glTextureStorage1DEXT;
+const GLMessage_Function GLMessage::glTextureStorage2DEXT;
+const GLMessage_Function GLMessage::glTextureStorage3DEXT;
+const GLMessage_Function GLMessage::glUseProgramStagesEXT;
+const GLMessage_Function GLMessage::glValidateProgramPipelineEXT;
const GLMessage_Function GLMessage::eglGetDisplay;
const GLMessage_Function GLMessage::eglInitialize;
const GLMessage_Function GLMessage::eglTerminate;
diff --git a/opengl/libs/GLES_trace/src/gltrace.pb.h b/opengl/libs/GLES_trace/src/gltrace.pb.h
index 5a7a16f..e3b8990 100644
--- a/opengl/libs/GLES_trace/src/gltrace.pb.h
+++ b/opengl/libs/GLES_trace/src/gltrace.pb.h
@@ -427,6 +427,67 @@
GLMessage_Function_glVertexPointer = 373,
GLMessage_Function_glViewport = 374,
GLMessage_Function_glWeightPointerOES = 375,
+ GLMessage_Function_glActiveShaderProgramEXT = 502,
+ GLMessage_Function_glAlphaFuncQCOM = 503,
+ GLMessage_Function_glBeginQueryEXT = 504,
+ GLMessage_Function_glBindProgramPipelineEXT = 505,
+ GLMessage_Function_glBlitFramebufferANGLE = 506,
+ GLMessage_Function_glCreateShaderProgramvEXT = 507,
+ GLMessage_Function_glDeleteProgramPipelinesEXT = 508,
+ GLMessage_Function_glDeleteQueriesEXT = 509,
+ GLMessage_Function_glDrawBuffersNV = 510,
+ GLMessage_Function_glEndQueryEXT = 511,
+ GLMessage_Function_glFramebufferTexture2DMultisampleEXT = 512,
+ GLMessage_Function_glGenProgramPipelinesEXT = 513,
+ GLMessage_Function_glGenQueriesEXT = 514,
+ GLMessage_Function_glGetGraphicsResetStatusEXT = 515,
+ GLMessage_Function_glGetObjectLabelEXT = 516,
+ GLMessage_Function_glGetProgramPipelineInfoLogEXT = 517,
+ GLMessage_Function_glGetProgramPipelineivEXT = 518,
+ GLMessage_Function_glGetQueryObjectuivEXT = 519,
+ GLMessage_Function_glGetQueryivEXT = 520,
+ GLMessage_Function_glGetnUniformfvEXT = 521,
+ GLMessage_Function_glGetnUniformivEXT = 521,
+ GLMessage_Function_glInsertEventMarkerEXT = 522,
+ GLMessage_Function_glIsProgramPipelineEXT = 523,
+ GLMessage_Function_glIsQueryEXT = 524,
+ GLMessage_Function_glLabelObjectEXT = 525,
+ GLMessage_Function_glPopGroupMarkerEXT = 526,
+ GLMessage_Function_glProgramParameteriEXT = 527,
+ GLMessage_Function_glProgramUniform1fEXT = 528,
+ GLMessage_Function_glProgramUniform1fvEXT = 529,
+ GLMessage_Function_glProgramUniform1iEXT = 530,
+ GLMessage_Function_glProgramUniform1ivEXT = 531,
+ GLMessage_Function_glProgramUniform2fEXT = 532,
+ GLMessage_Function_glProgramUniform2fvEXT = 533,
+ GLMessage_Function_glProgramUniform2iEXT = 534,
+ GLMessage_Function_glProgramUniform2ivEXT = 535,
+ GLMessage_Function_glProgramUniform3fEXT = 536,
+ GLMessage_Function_glProgramUniform3fvEXT = 537,
+ GLMessage_Function_glProgramUniform3iEXT = 538,
+ GLMessage_Function_glProgramUniform3ivEXT = 539,
+ GLMessage_Function_glProgramUniform4fEXT = 540,
+ GLMessage_Function_glProgramUniform4fvEXT = 541,
+ GLMessage_Function_glProgramUniform4iEXT = 542,
+ GLMessage_Function_glProgramUniform4ivEXT = 543,
+ GLMessage_Function_glProgramUniformMatrix2fvEXT = 544,
+ GLMessage_Function_glProgramUniformMatrix3fvEXT = 545,
+ GLMessage_Function_glProgramUniformMatrix4fvEXT = 546,
+ GLMessage_Function_glPushGroupMarkerEXT = 547,
+ GLMessage_Function_glReadBufferNV = 548,
+ GLMessage_Function_glReadnPixelsEXT = 549,
+ GLMessage_Function_glRenderbufferStorageMultisampleANGLE = 550,
+ GLMessage_Function_glRenderbufferStorageMultisampleAPPLE = 551,
+ GLMessage_Function_glRenderbufferStorageMultisampleEXT = 552,
+ GLMessage_Function_glResolveMultisampleFramebufferAPPLE = 553,
+ GLMessage_Function_glTexStorage1DEXT = 554,
+ GLMessage_Function_glTexStorage2DEXT = 555,
+ GLMessage_Function_glTexStorage3DEXT = 556,
+ GLMessage_Function_glTextureStorage1DEXT = 557,
+ GLMessage_Function_glTextureStorage2DEXT = 558,
+ GLMessage_Function_glTextureStorage3DEXT = 559,
+ GLMessage_Function_glUseProgramStagesEXT = 560,
+ GLMessage_Function_glValidateProgramPipelineEXT = 561,
GLMessage_Function_eglGetDisplay = 2000,
GLMessage_Function_eglInitialize = 2001,
GLMessage_Function_eglTerminate = 2002,
@@ -1182,6 +1243,67 @@
static const Function glVertexPointer = GLMessage_Function_glVertexPointer;
static const Function glViewport = GLMessage_Function_glViewport;
static const Function glWeightPointerOES = GLMessage_Function_glWeightPointerOES;
+ static const Function glActiveShaderProgramEXT = GLMessage_Function_glActiveShaderProgramEXT;
+ static const Function glAlphaFuncQCOM = GLMessage_Function_glAlphaFuncQCOM;
+ static const Function glBeginQueryEXT = GLMessage_Function_glBeginQueryEXT;
+ static const Function glBindProgramPipelineEXT = GLMessage_Function_glBindProgramPipelineEXT;
+ static const Function glBlitFramebufferANGLE = GLMessage_Function_glBlitFramebufferANGLE;
+ static const Function glCreateShaderProgramvEXT = GLMessage_Function_glCreateShaderProgramvEXT;
+ static const Function glDeleteProgramPipelinesEXT = GLMessage_Function_glDeleteProgramPipelinesEXT;
+ static const Function glDeleteQueriesEXT = GLMessage_Function_glDeleteQueriesEXT;
+ static const Function glDrawBuffersNV = GLMessage_Function_glDrawBuffersNV;
+ static const Function glEndQueryEXT = GLMessage_Function_glEndQueryEXT;
+ static const Function glFramebufferTexture2DMultisampleEXT = GLMessage_Function_glFramebufferTexture2DMultisampleEXT;
+ static const Function glGenProgramPipelinesEXT = GLMessage_Function_glGenProgramPipelinesEXT;
+ static const Function glGenQueriesEXT = GLMessage_Function_glGenQueriesEXT;
+ static const Function glGetGraphicsResetStatusEXT = GLMessage_Function_glGetGraphicsResetStatusEXT;
+ static const Function glGetObjectLabelEXT = GLMessage_Function_glGetObjectLabelEXT;
+ static const Function glGetProgramPipelineInfoLogEXT = GLMessage_Function_glGetProgramPipelineInfoLogEXT;
+ static const Function glGetProgramPipelineivEXT = GLMessage_Function_glGetProgramPipelineivEXT;
+ static const Function glGetQueryObjectuivEXT = GLMessage_Function_glGetQueryObjectuivEXT;
+ static const Function glGetQueryivEXT = GLMessage_Function_glGetQueryivEXT;
+ static const Function glGetnUniformfvEXT = GLMessage_Function_glGetnUniformfvEXT;
+ static const Function glGetnUniformivEXT = GLMessage_Function_glGetnUniformivEXT;
+ static const Function glInsertEventMarkerEXT = GLMessage_Function_glInsertEventMarkerEXT;
+ static const Function glIsProgramPipelineEXT = GLMessage_Function_glIsProgramPipelineEXT;
+ static const Function glIsQueryEXT = GLMessage_Function_glIsQueryEXT;
+ static const Function glLabelObjectEXT = GLMessage_Function_glLabelObjectEXT;
+ static const Function glPopGroupMarkerEXT = GLMessage_Function_glPopGroupMarkerEXT;
+ static const Function glProgramParameteriEXT = GLMessage_Function_glProgramParameteriEXT;
+ static const Function glProgramUniform1fEXT = GLMessage_Function_glProgramUniform1fEXT;
+ static const Function glProgramUniform1fvEXT = GLMessage_Function_glProgramUniform1fvEXT;
+ static const Function glProgramUniform1iEXT = GLMessage_Function_glProgramUniform1iEXT;
+ static const Function glProgramUniform1ivEXT = GLMessage_Function_glProgramUniform1ivEXT;
+ static const Function glProgramUniform2fEXT = GLMessage_Function_glProgramUniform2fEXT;
+ static const Function glProgramUniform2fvEXT = GLMessage_Function_glProgramUniform2fvEXT;
+ static const Function glProgramUniform2iEXT = GLMessage_Function_glProgramUniform2iEXT;
+ static const Function glProgramUniform2ivEXT = GLMessage_Function_glProgramUniform2ivEXT;
+ static const Function glProgramUniform3fEXT = GLMessage_Function_glProgramUniform3fEXT;
+ static const Function glProgramUniform3fvEXT = GLMessage_Function_glProgramUniform3fvEXT;
+ static const Function glProgramUniform3iEXT = GLMessage_Function_glProgramUniform3iEXT;
+ static const Function glProgramUniform3ivEXT = GLMessage_Function_glProgramUniform3ivEXT;
+ static const Function glProgramUniform4fEXT = GLMessage_Function_glProgramUniform4fEXT;
+ static const Function glProgramUniform4fvEXT = GLMessage_Function_glProgramUniform4fvEXT;
+ static const Function glProgramUniform4iEXT = GLMessage_Function_glProgramUniform4iEXT;
+ static const Function glProgramUniform4ivEXT = GLMessage_Function_glProgramUniform4ivEXT;
+ static const Function glProgramUniformMatrix2fvEXT = GLMessage_Function_glProgramUniformMatrix2fvEXT;
+ static const Function glProgramUniformMatrix3fvEXT = GLMessage_Function_glProgramUniformMatrix3fvEXT;
+ static const Function glProgramUniformMatrix4fvEXT = GLMessage_Function_glProgramUniformMatrix4fvEXT;
+ static const Function glPushGroupMarkerEXT = GLMessage_Function_glPushGroupMarkerEXT;
+ static const Function glReadBufferNV = GLMessage_Function_glReadBufferNV;
+ static const Function glReadnPixelsEXT = GLMessage_Function_glReadnPixelsEXT;
+ static const Function glRenderbufferStorageMultisampleANGLE = GLMessage_Function_glRenderbufferStorageMultisampleANGLE;
+ static const Function glRenderbufferStorageMultisampleAPPLE = GLMessage_Function_glRenderbufferStorageMultisampleAPPLE;
+ static const Function glRenderbufferStorageMultisampleEXT = GLMessage_Function_glRenderbufferStorageMultisampleEXT;
+ static const Function glResolveMultisampleFramebufferAPPLE = GLMessage_Function_glResolveMultisampleFramebufferAPPLE;
+ static const Function glTexStorage1DEXT = GLMessage_Function_glTexStorage1DEXT;
+ static const Function glTexStorage2DEXT = GLMessage_Function_glTexStorage2DEXT;
+ static const Function glTexStorage3DEXT = GLMessage_Function_glTexStorage3DEXT;
+ static const Function glTextureStorage1DEXT = GLMessage_Function_glTextureStorage1DEXT;
+ static const Function glTextureStorage2DEXT = GLMessage_Function_glTextureStorage2DEXT;
+ static const Function glTextureStorage3DEXT = GLMessage_Function_glTextureStorage3DEXT;
+ static const Function glUseProgramStagesEXT = GLMessage_Function_glUseProgramStagesEXT;
+ static const Function glValidateProgramPipelineEXT = GLMessage_Function_glValidateProgramPipelineEXT;
static const Function eglGetDisplay = GLMessage_Function_eglGetDisplay;
static const Function eglInitialize = GLMessage_Function_eglInitialize;
static const Function eglTerminate = GLMessage_Function_eglTerminate;
diff --git a/opengl/libs/GLES_trace/src/gltrace_api.cpp b/opengl/libs/GLES_trace/src/gltrace_api.cpp
index c8e820d..a2366ac 100644
--- a/opengl/libs/GLES_trace/src/gltrace_api.cpp
+++ b/opengl/libs/GLES_trace/src/gltrace_api.cpp
@@ -5809,6 +5809,339 @@
glContext->traceGLMessage(&glmsg);
}
+void GLTrace_glBlitFramebufferANGLE(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter) {
+ GLMessage glmsg;
+ GLTraceContext *glContext = getGLTraceContext();
+
+ glmsg.set_function(GLMessage::glBlitFramebufferANGLE);
+
+ // copy argument srcX0
+ GLMessage_DataType *arg_srcX0 = glmsg.add_args();
+ arg_srcX0->set_isarray(false);
+ arg_srcX0->set_type(GLMessage::DataType::INT);
+ arg_srcX0->add_intvalue(srcX0);
+
+ // copy argument srcY0
+ GLMessage_DataType *arg_srcY0 = glmsg.add_args();
+ arg_srcY0->set_isarray(false);
+ arg_srcY0->set_type(GLMessage::DataType::INT);
+ arg_srcY0->add_intvalue(srcY0);
+
+ // copy argument srcX1
+ GLMessage_DataType *arg_srcX1 = glmsg.add_args();
+ arg_srcX1->set_isarray(false);
+ arg_srcX1->set_type(GLMessage::DataType::INT);
+ arg_srcX1->add_intvalue(srcX1);
+
+ // copy argument srcY1
+ GLMessage_DataType *arg_srcY1 = glmsg.add_args();
+ arg_srcY1->set_isarray(false);
+ arg_srcY1->set_type(GLMessage::DataType::INT);
+ arg_srcY1->add_intvalue(srcY1);
+
+ // copy argument dstX0
+ GLMessage_DataType *arg_dstX0 = glmsg.add_args();
+ arg_dstX0->set_isarray(false);
+ arg_dstX0->set_type(GLMessage::DataType::INT);
+ arg_dstX0->add_intvalue(dstX0);
+
+ // copy argument dstY0
+ GLMessage_DataType *arg_dstY0 = glmsg.add_args();
+ arg_dstY0->set_isarray(false);
+ arg_dstY0->set_type(GLMessage::DataType::INT);
+ arg_dstY0->add_intvalue(dstY0);
+
+ // copy argument dstX1
+ GLMessage_DataType *arg_dstX1 = glmsg.add_args();
+ arg_dstX1->set_isarray(false);
+ arg_dstX1->set_type(GLMessage::DataType::INT);
+ arg_dstX1->add_intvalue(dstX1);
+
+ // copy argument dstY1
+ GLMessage_DataType *arg_dstY1 = glmsg.add_args();
+ arg_dstY1->set_isarray(false);
+ arg_dstY1->set_type(GLMessage::DataType::INT);
+ arg_dstY1->add_intvalue(dstY1);
+
+ // copy argument mask
+ GLMessage_DataType *arg_mask = glmsg.add_args();
+ arg_mask->set_isarray(false);
+ arg_mask->set_type(GLMessage::DataType::INT);
+ arg_mask->add_intvalue(mask);
+
+ // copy argument filter
+ GLMessage_DataType *arg_filter = glmsg.add_args();
+ arg_filter->set_isarray(false);
+ arg_filter->set_type(GLMessage::DataType::ENUM);
+ arg_filter->add_intvalue((int)filter);
+
+ // call function
+ nsecs_t start_time = systemTime();
+ glContext->hooks->gl.glBlitFramebufferANGLE(srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1, mask, filter);
+ nsecs_t end_time = systemTime();
+
+ fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ glContext->traceGLMessage(&glmsg);
+}
+
+void GLTrace_glRenderbufferStorageMultisampleANGLE(GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height) {
+ GLMessage glmsg;
+ GLTraceContext *glContext = getGLTraceContext();
+
+ glmsg.set_function(GLMessage::glRenderbufferStorageMultisampleANGLE);
+
+ // copy argument target
+ GLMessage_DataType *arg_target = glmsg.add_args();
+ arg_target->set_isarray(false);
+ arg_target->set_type(GLMessage::DataType::ENUM);
+ arg_target->add_intvalue((int)target);
+
+ // copy argument samples
+ GLMessage_DataType *arg_samples = glmsg.add_args();
+ arg_samples->set_isarray(false);
+ arg_samples->set_type(GLMessage::DataType::INT);
+ arg_samples->add_intvalue(samples);
+
+ // copy argument internalformat
+ GLMessage_DataType *arg_internalformat = glmsg.add_args();
+ arg_internalformat->set_isarray(false);
+ arg_internalformat->set_type(GLMessage::DataType::ENUM);
+ arg_internalformat->add_intvalue((int)internalformat);
+
+ // copy argument width
+ GLMessage_DataType *arg_width = glmsg.add_args();
+ arg_width->set_isarray(false);
+ arg_width->set_type(GLMessage::DataType::INT);
+ arg_width->add_intvalue(width);
+
+ // copy argument height
+ GLMessage_DataType *arg_height = glmsg.add_args();
+ arg_height->set_isarray(false);
+ arg_height->set_type(GLMessage::DataType::INT);
+ arg_height->add_intvalue(height);
+
+ // call function
+ nsecs_t start_time = systemTime();
+ glContext->hooks->gl.glRenderbufferStorageMultisampleANGLE(target, samples, internalformat, width, height);
+ nsecs_t end_time = systemTime();
+
+ fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ glContext->traceGLMessage(&glmsg);
+}
+
+void GLTrace_glRenderbufferStorageMultisampleAPPLE(GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height) {
+ GLMessage glmsg;
+ GLTraceContext *glContext = getGLTraceContext();
+
+ glmsg.set_function(GLMessage::glRenderbufferStorageMultisampleAPPLE);
+
+ // copy argument target
+ GLMessage_DataType *arg_target = glmsg.add_args();
+ arg_target->set_isarray(false);
+ arg_target->set_type(GLMessage::DataType::ENUM);
+ arg_target->add_intvalue((int)target);
+
+ // copy argument samples
+ GLMessage_DataType *arg_samples = glmsg.add_args();
+ arg_samples->set_isarray(false);
+ arg_samples->set_type(GLMessage::DataType::INT);
+ arg_samples->add_intvalue(samples);
+
+ // copy argument internalformat
+ GLMessage_DataType *arg_internalformat = glmsg.add_args();
+ arg_internalformat->set_isarray(false);
+ arg_internalformat->set_type(GLMessage::DataType::ENUM);
+ arg_internalformat->add_intvalue((int)internalformat);
+
+ // copy argument width
+ GLMessage_DataType *arg_width = glmsg.add_args();
+ arg_width->set_isarray(false);
+ arg_width->set_type(GLMessage::DataType::INT);
+ arg_width->add_intvalue(width);
+
+ // copy argument height
+ GLMessage_DataType *arg_height = glmsg.add_args();
+ arg_height->set_isarray(false);
+ arg_height->set_type(GLMessage::DataType::INT);
+ arg_height->add_intvalue(height);
+
+ // call function
+ nsecs_t start_time = systemTime();
+ glContext->hooks->gl.glRenderbufferStorageMultisampleAPPLE(target, samples, internalformat, width, height);
+ nsecs_t end_time = systemTime();
+
+ fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ glContext->traceGLMessage(&glmsg);
+}
+
+void GLTrace_glResolveMultisampleFramebufferAPPLE(void) {
+ GLMessage glmsg;
+ GLTraceContext *glContext = getGLTraceContext();
+
+ glmsg.set_function(GLMessage::glResolveMultisampleFramebufferAPPLE);
+
+ // call function
+ nsecs_t start_time = systemTime();
+ glContext->hooks->gl.glResolveMultisampleFramebufferAPPLE();
+ nsecs_t end_time = systemTime();
+
+ fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ glContext->traceGLMessage(&glmsg);
+}
+
+void GLTrace_glLabelObjectEXT(GLenum type, GLuint object, GLsizei length, const GLchar *label) {
+ GLMessage glmsg;
+ GLTraceContext *glContext = getGLTraceContext();
+
+ glmsg.set_function(GLMessage::glLabelObjectEXT);
+
+ // copy argument type
+ GLMessage_DataType *arg_type = glmsg.add_args();
+ arg_type->set_isarray(false);
+ arg_type->set_type(GLMessage::DataType::ENUM);
+ arg_type->add_intvalue((int)type);
+
+ // copy argument object
+ GLMessage_DataType *arg_object = glmsg.add_args();
+ arg_object->set_isarray(false);
+ arg_object->set_type(GLMessage::DataType::INT);
+ arg_object->add_intvalue(object);
+
+ // copy argument length
+ GLMessage_DataType *arg_length = glmsg.add_args();
+ arg_length->set_isarray(false);
+ arg_length->set_type(GLMessage::DataType::INT);
+ arg_length->add_intvalue(length);
+
+ // copy argument label
+ GLMessage_DataType *arg_label = glmsg.add_args();
+ arg_label->set_isarray(false);
+ arg_label->set_type(GLMessage::DataType::INT);
+ arg_label->add_intvalue((int)label);
+
+ // call function
+ nsecs_t start_time = systemTime();
+ glContext->hooks->gl.glLabelObjectEXT(type, object, length, label);
+ nsecs_t end_time = systemTime();
+
+ fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ glContext->traceGLMessage(&glmsg);
+}
+
+void GLTrace_glGetObjectLabelEXT(GLenum type, GLuint object, GLsizei bufSize, GLsizei *length, GLchar *label) {
+ GLMessage glmsg;
+ GLTraceContext *glContext = getGLTraceContext();
+
+ glmsg.set_function(GLMessage::glGetObjectLabelEXT);
+
+ // copy argument type
+ GLMessage_DataType *arg_type = glmsg.add_args();
+ arg_type->set_isarray(false);
+ arg_type->set_type(GLMessage::DataType::ENUM);
+ arg_type->add_intvalue((int)type);
+
+ // copy argument object
+ GLMessage_DataType *arg_object = glmsg.add_args();
+ arg_object->set_isarray(false);
+ arg_object->set_type(GLMessage::DataType::INT);
+ arg_object->add_intvalue(object);
+
+ // copy argument bufSize
+ GLMessage_DataType *arg_bufSize = glmsg.add_args();
+ arg_bufSize->set_isarray(false);
+ arg_bufSize->set_type(GLMessage::DataType::INT);
+ arg_bufSize->add_intvalue(bufSize);
+
+ // copy argument length
+ GLMessage_DataType *arg_length = glmsg.add_args();
+ arg_length->set_isarray(false);
+ arg_length->set_type(GLMessage::DataType::INT);
+ arg_length->add_intvalue((int)length);
+
+ // copy argument label
+ GLMessage_DataType *arg_label = glmsg.add_args();
+ arg_label->set_isarray(false);
+ arg_label->set_type(GLMessage::DataType::INT);
+ arg_label->add_intvalue((int)label);
+
+ // call function
+ nsecs_t start_time = systemTime();
+ glContext->hooks->gl.glGetObjectLabelEXT(type, object, bufSize, length, label);
+ nsecs_t end_time = systemTime();
+
+ fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ glContext->traceGLMessage(&glmsg);
+}
+
+void GLTrace_glInsertEventMarkerEXT(GLsizei length, const GLchar *marker) {
+ GLMessage glmsg;
+ GLTraceContext *glContext = getGLTraceContext();
+
+ glmsg.set_function(GLMessage::glInsertEventMarkerEXT);
+
+ // copy argument length
+ GLMessage_DataType *arg_length = glmsg.add_args();
+ arg_length->set_isarray(false);
+ arg_length->set_type(GLMessage::DataType::INT);
+ arg_length->add_intvalue(length);
+
+ // copy argument marker
+ GLMessage_DataType *arg_marker = glmsg.add_args();
+ arg_marker->set_isarray(false);
+ arg_marker->set_type(GLMessage::DataType::INT);
+ arg_marker->add_intvalue((int)marker);
+
+ // call function
+ nsecs_t start_time = systemTime();
+ glContext->hooks->gl.glInsertEventMarkerEXT(length, marker);
+ nsecs_t end_time = systemTime();
+
+ fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ glContext->traceGLMessage(&glmsg);
+}
+
+void GLTrace_glPushGroupMarkerEXT(GLsizei length, const GLchar *marker) {
+ GLMessage glmsg;
+ GLTraceContext *glContext = getGLTraceContext();
+
+ glmsg.set_function(GLMessage::glPushGroupMarkerEXT);
+
+ // copy argument length
+ GLMessage_DataType *arg_length = glmsg.add_args();
+ arg_length->set_isarray(false);
+ arg_length->set_type(GLMessage::DataType::INT);
+ arg_length->add_intvalue(length);
+
+ // copy argument marker
+ GLMessage_DataType *arg_marker = glmsg.add_args();
+ arg_marker->set_isarray(false);
+ arg_marker->set_type(GLMessage::DataType::INT);
+ arg_marker->add_intvalue((int)marker);
+
+ // call function
+ nsecs_t start_time = systemTime();
+ glContext->hooks->gl.glPushGroupMarkerEXT(length, marker);
+ nsecs_t end_time = systemTime();
+
+ fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ glContext->traceGLMessage(&glmsg);
+}
+
+void GLTrace_glPopGroupMarkerEXT(void) {
+ GLMessage glmsg;
+ GLTraceContext *glContext = getGLTraceContext();
+
+ glmsg.set_function(GLMessage::glPopGroupMarkerEXT);
+
+ // call function
+ nsecs_t start_time = systemTime();
+ glContext->hooks->gl.glPopGroupMarkerEXT();
+ nsecs_t end_time = systemTime();
+
+ fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ glContext->traceGLMessage(&glmsg);
+}
+
void GLTrace_glDiscardFramebufferEXT(GLenum target, GLsizei numAttachments, const GLenum *attachments) {
GLMessage glmsg;
GLTraceContext *glContext = getGLTraceContext();
@@ -5842,6 +6175,102 @@
glContext->traceGLMessage(&glmsg);
}
+void GLTrace_glRenderbufferStorageMultisampleEXT(GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height) {
+ GLMessage glmsg;
+ GLTraceContext *glContext = getGLTraceContext();
+
+ glmsg.set_function(GLMessage::glRenderbufferStorageMultisampleEXT);
+
+ // copy argument target
+ GLMessage_DataType *arg_target = glmsg.add_args();
+ arg_target->set_isarray(false);
+ arg_target->set_type(GLMessage::DataType::ENUM);
+ arg_target->add_intvalue((int)target);
+
+ // copy argument samples
+ GLMessage_DataType *arg_samples = glmsg.add_args();
+ arg_samples->set_isarray(false);
+ arg_samples->set_type(GLMessage::DataType::INT);
+ arg_samples->add_intvalue(samples);
+
+ // copy argument internalformat
+ GLMessage_DataType *arg_internalformat = glmsg.add_args();
+ arg_internalformat->set_isarray(false);
+ arg_internalformat->set_type(GLMessage::DataType::ENUM);
+ arg_internalformat->add_intvalue((int)internalformat);
+
+ // copy argument width
+ GLMessage_DataType *arg_width = glmsg.add_args();
+ arg_width->set_isarray(false);
+ arg_width->set_type(GLMessage::DataType::INT);
+ arg_width->add_intvalue(width);
+
+ // copy argument height
+ GLMessage_DataType *arg_height = glmsg.add_args();
+ arg_height->set_isarray(false);
+ arg_height->set_type(GLMessage::DataType::INT);
+ arg_height->add_intvalue(height);
+
+ // call function
+ nsecs_t start_time = systemTime();
+ glContext->hooks->gl.glRenderbufferStorageMultisampleEXT(target, samples, internalformat, width, height);
+ nsecs_t end_time = systemTime();
+
+ fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ glContext->traceGLMessage(&glmsg);
+}
+
+void GLTrace_glFramebufferTexture2DMultisampleEXT(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level, GLsizei samples) {
+ GLMessage glmsg;
+ GLTraceContext *glContext = getGLTraceContext();
+
+ glmsg.set_function(GLMessage::glFramebufferTexture2DMultisampleEXT);
+
+ // copy argument target
+ GLMessage_DataType *arg_target = glmsg.add_args();
+ arg_target->set_isarray(false);
+ arg_target->set_type(GLMessage::DataType::ENUM);
+ arg_target->add_intvalue((int)target);
+
+ // copy argument attachment
+ GLMessage_DataType *arg_attachment = glmsg.add_args();
+ arg_attachment->set_isarray(false);
+ arg_attachment->set_type(GLMessage::DataType::ENUM);
+ arg_attachment->add_intvalue((int)attachment);
+
+ // copy argument textarget
+ GLMessage_DataType *arg_textarget = glmsg.add_args();
+ arg_textarget->set_isarray(false);
+ arg_textarget->set_type(GLMessage::DataType::ENUM);
+ arg_textarget->add_intvalue((int)textarget);
+
+ // copy argument texture
+ GLMessage_DataType *arg_texture = glmsg.add_args();
+ arg_texture->set_isarray(false);
+ arg_texture->set_type(GLMessage::DataType::INT);
+ arg_texture->add_intvalue(texture);
+
+ // copy argument level
+ GLMessage_DataType *arg_level = glmsg.add_args();
+ arg_level->set_isarray(false);
+ arg_level->set_type(GLMessage::DataType::INT);
+ arg_level->add_intvalue(level);
+
+ // copy argument samples
+ GLMessage_DataType *arg_samples = glmsg.add_args();
+ arg_samples->set_isarray(false);
+ arg_samples->set_type(GLMessage::DataType::INT);
+ arg_samples->add_intvalue(samples);
+
+ // call function
+ nsecs_t start_time = systemTime();
+ glContext->hooks->gl.glFramebufferTexture2DMultisampleEXT(target, attachment, textarget, texture, level, samples);
+ nsecs_t end_time = systemTime();
+
+ fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ glContext->traceGLMessage(&glmsg);
+}
+
void GLTrace_glMultiDrawArraysEXT(GLenum mode, GLint *first, GLsizei *count, GLsizei primcount) {
GLMessage glmsg;
GLTraceContext *glContext = getGLTraceContext();
@@ -5926,6 +6355,1769 @@
glContext->traceGLMessage(&glmsg);
}
+void GLTrace_glGenQueriesEXT(GLsizei n, GLuint *ids) {
+ GLMessage glmsg;
+ GLTraceContext *glContext = getGLTraceContext();
+
+ glmsg.set_function(GLMessage::glGenQueriesEXT);
+
+ // copy argument n
+ GLMessage_DataType *arg_n = glmsg.add_args();
+ arg_n->set_isarray(false);
+ arg_n->set_type(GLMessage::DataType::INT);
+ arg_n->add_intvalue(n);
+
+ // copy argument ids
+ GLMessage_DataType *arg_ids = glmsg.add_args();
+ arg_ids->set_isarray(false);
+ arg_ids->set_type(GLMessage::DataType::INT);
+ arg_ids->add_intvalue((int)ids);
+
+ // call function
+ nsecs_t start_time = systemTime();
+ glContext->hooks->gl.glGenQueriesEXT(n, ids);
+ nsecs_t end_time = systemTime();
+
+ fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ glContext->traceGLMessage(&glmsg);
+}
+
+void GLTrace_glDeleteQueriesEXT(GLsizei n, const GLuint *ids) {
+ GLMessage glmsg;
+ GLTraceContext *glContext = getGLTraceContext();
+
+ glmsg.set_function(GLMessage::glDeleteQueriesEXT);
+
+ // copy argument n
+ GLMessage_DataType *arg_n = glmsg.add_args();
+ arg_n->set_isarray(false);
+ arg_n->set_type(GLMessage::DataType::INT);
+ arg_n->add_intvalue(n);
+
+ // copy argument ids
+ GLMessage_DataType *arg_ids = glmsg.add_args();
+ arg_ids->set_isarray(false);
+ arg_ids->set_type(GLMessage::DataType::INT);
+ arg_ids->add_intvalue((int)ids);
+
+ // call function
+ nsecs_t start_time = systemTime();
+ glContext->hooks->gl.glDeleteQueriesEXT(n, ids);
+ nsecs_t end_time = systemTime();
+
+ fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ glContext->traceGLMessage(&glmsg);
+}
+
+GLboolean GLTrace_glIsQueryEXT(GLuint id) {
+ GLMessage glmsg;
+ GLTraceContext *glContext = getGLTraceContext();
+
+ glmsg.set_function(GLMessage::glIsQueryEXT);
+
+ // copy argument id
+ GLMessage_DataType *arg_id = glmsg.add_args();
+ arg_id->set_isarray(false);
+ arg_id->set_type(GLMessage::DataType::INT);
+ arg_id->add_intvalue(id);
+
+ // call function
+ nsecs_t start_time = systemTime();
+ GLboolean retValue = glContext->hooks->gl.glIsQueryEXT(id);
+ nsecs_t end_time = systemTime();
+
+ // set return value
+ GLMessage_DataType *rt = glmsg.mutable_returnvalue();
+ rt->set_isarray(false);
+ rt->set_type(GLMessage::DataType::BOOL);
+ rt->add_boolvalue(retValue);
+
+ fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ glContext->traceGLMessage(&glmsg);
+
+ return retValue;
+}
+
+void GLTrace_glBeginQueryEXT(GLenum target, GLuint id) {
+ GLMessage glmsg;
+ GLTraceContext *glContext = getGLTraceContext();
+
+ glmsg.set_function(GLMessage::glBeginQueryEXT);
+
+ // copy argument target
+ GLMessage_DataType *arg_target = glmsg.add_args();
+ arg_target->set_isarray(false);
+ arg_target->set_type(GLMessage::DataType::ENUM);
+ arg_target->add_intvalue((int)target);
+
+ // copy argument id
+ GLMessage_DataType *arg_id = glmsg.add_args();
+ arg_id->set_isarray(false);
+ arg_id->set_type(GLMessage::DataType::INT);
+ arg_id->add_intvalue(id);
+
+ // call function
+ nsecs_t start_time = systemTime();
+ glContext->hooks->gl.glBeginQueryEXT(target, id);
+ nsecs_t end_time = systemTime();
+
+ fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ glContext->traceGLMessage(&glmsg);
+}
+
+void GLTrace_glEndQueryEXT(GLenum target) {
+ GLMessage glmsg;
+ GLTraceContext *glContext = getGLTraceContext();
+
+ glmsg.set_function(GLMessage::glEndQueryEXT);
+
+ // copy argument target
+ GLMessage_DataType *arg_target = glmsg.add_args();
+ arg_target->set_isarray(false);
+ arg_target->set_type(GLMessage::DataType::ENUM);
+ arg_target->add_intvalue((int)target);
+
+ // call function
+ nsecs_t start_time = systemTime();
+ glContext->hooks->gl.glEndQueryEXT(target);
+ nsecs_t end_time = systemTime();
+
+ fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ glContext->traceGLMessage(&glmsg);
+}
+
+void GLTrace_glGetQueryivEXT(GLenum target, GLenum pname, GLint *params) {
+ GLMessage glmsg;
+ GLTraceContext *glContext = getGLTraceContext();
+
+ glmsg.set_function(GLMessage::glGetQueryivEXT);
+
+ // copy argument target
+ GLMessage_DataType *arg_target = glmsg.add_args();
+ arg_target->set_isarray(false);
+ arg_target->set_type(GLMessage::DataType::ENUM);
+ arg_target->add_intvalue((int)target);
+
+ // copy argument pname
+ GLMessage_DataType *arg_pname = glmsg.add_args();
+ arg_pname->set_isarray(false);
+ arg_pname->set_type(GLMessage::DataType::ENUM);
+ arg_pname->add_intvalue((int)pname);
+
+ // copy argument params
+ GLMessage_DataType *arg_params = glmsg.add_args();
+ arg_params->set_isarray(false);
+ arg_params->set_type(GLMessage::DataType::INT);
+ arg_params->add_intvalue((int)params);
+
+ // call function
+ nsecs_t start_time = systemTime();
+ glContext->hooks->gl.glGetQueryivEXT(target, pname, params);
+ nsecs_t end_time = systemTime();
+
+ fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ glContext->traceGLMessage(&glmsg);
+}
+
+void GLTrace_glGetQueryObjectuivEXT(GLuint id, GLenum pname, GLuint *params) {
+ GLMessage glmsg;
+ GLTraceContext *glContext = getGLTraceContext();
+
+ glmsg.set_function(GLMessage::glGetQueryObjectuivEXT);
+
+ // copy argument id
+ GLMessage_DataType *arg_id = glmsg.add_args();
+ arg_id->set_isarray(false);
+ arg_id->set_type(GLMessage::DataType::INT);
+ arg_id->add_intvalue(id);
+
+ // copy argument pname
+ GLMessage_DataType *arg_pname = glmsg.add_args();
+ arg_pname->set_isarray(false);
+ arg_pname->set_type(GLMessage::DataType::ENUM);
+ arg_pname->add_intvalue((int)pname);
+
+ // copy argument params
+ GLMessage_DataType *arg_params = glmsg.add_args();
+ arg_params->set_isarray(false);
+ arg_params->set_type(GLMessage::DataType::INT);
+ arg_params->add_intvalue((int)params);
+
+ // call function
+ nsecs_t start_time = systemTime();
+ glContext->hooks->gl.glGetQueryObjectuivEXT(id, pname, params);
+ nsecs_t end_time = systemTime();
+
+ fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ glContext->traceGLMessage(&glmsg);
+}
+
+GLenum GLTrace_glGetGraphicsResetStatusEXT(void) {
+ GLMessage glmsg;
+ GLTraceContext *glContext = getGLTraceContext();
+
+ glmsg.set_function(GLMessage::glGetGraphicsResetStatusEXT);
+
+ // call function
+ nsecs_t start_time = systemTime();
+ GLenum retValue = glContext->hooks->gl.glGetGraphicsResetStatusEXT();
+ nsecs_t end_time = systemTime();
+
+ // set return value
+ GLMessage_DataType *rt = glmsg.mutable_returnvalue();
+ rt->set_isarray(false);
+ rt->set_type(GLMessage::DataType::ENUM);
+ rt->add_intvalue((int)retValue);
+
+ fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ glContext->traceGLMessage(&glmsg);
+
+ return retValue;
+}
+
+void GLTrace_glReadnPixelsEXT(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLsizei bufSize, void *data) {
+ GLMessage glmsg;
+ GLTraceContext *glContext = getGLTraceContext();
+
+ glmsg.set_function(GLMessage::glReadnPixelsEXT);
+
+ // copy argument x
+ GLMessage_DataType *arg_x = glmsg.add_args();
+ arg_x->set_isarray(false);
+ arg_x->set_type(GLMessage::DataType::INT);
+ arg_x->add_intvalue(x);
+
+ // copy argument y
+ GLMessage_DataType *arg_y = glmsg.add_args();
+ arg_y->set_isarray(false);
+ arg_y->set_type(GLMessage::DataType::INT);
+ arg_y->add_intvalue(y);
+
+ // copy argument width
+ GLMessage_DataType *arg_width = glmsg.add_args();
+ arg_width->set_isarray(false);
+ arg_width->set_type(GLMessage::DataType::INT);
+ arg_width->add_intvalue(width);
+
+ // copy argument height
+ GLMessage_DataType *arg_height = glmsg.add_args();
+ arg_height->set_isarray(false);
+ arg_height->set_type(GLMessage::DataType::INT);
+ arg_height->add_intvalue(height);
+
+ // copy argument format
+ GLMessage_DataType *arg_format = glmsg.add_args();
+ arg_format->set_isarray(false);
+ arg_format->set_type(GLMessage::DataType::ENUM);
+ arg_format->add_intvalue((int)format);
+
+ // copy argument type
+ GLMessage_DataType *arg_type = glmsg.add_args();
+ arg_type->set_isarray(false);
+ arg_type->set_type(GLMessage::DataType::ENUM);
+ arg_type->add_intvalue((int)type);
+
+ // copy argument bufSize
+ GLMessage_DataType *arg_bufSize = glmsg.add_args();
+ arg_bufSize->set_isarray(false);
+ arg_bufSize->set_type(GLMessage::DataType::INT);
+ arg_bufSize->add_intvalue(bufSize);
+
+ // copy argument data
+ GLMessage_DataType *arg_data = glmsg.add_args();
+ arg_data->set_isarray(false);
+ arg_data->set_type(GLMessage::DataType::INT);
+ arg_data->add_intvalue((int)data);
+
+ // call function
+ nsecs_t start_time = systemTime();
+ glContext->hooks->gl.glReadnPixelsEXT(x, y, width, height, format, type, bufSize, data);
+ nsecs_t end_time = systemTime();
+
+ fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ glContext->traceGLMessage(&glmsg);
+}
+
+void GLTrace_glGetnUniformfvEXT(GLuint program, GLint location, GLsizei bufSize, float *params) {
+ GLMessage glmsg;
+ GLTraceContext *glContext = getGLTraceContext();
+
+ glmsg.set_function(GLMessage::glGetnUniformfvEXT);
+
+ // copy argument program
+ GLMessage_DataType *arg_program = glmsg.add_args();
+ arg_program->set_isarray(false);
+ arg_program->set_type(GLMessage::DataType::INT);
+ arg_program->add_intvalue(program);
+
+ // copy argument location
+ GLMessage_DataType *arg_location = glmsg.add_args();
+ arg_location->set_isarray(false);
+ arg_location->set_type(GLMessage::DataType::INT);
+ arg_location->add_intvalue(location);
+
+ // copy argument bufSize
+ GLMessage_DataType *arg_bufSize = glmsg.add_args();
+ arg_bufSize->set_isarray(false);
+ arg_bufSize->set_type(GLMessage::DataType::INT);
+ arg_bufSize->add_intvalue(bufSize);
+
+ // copy argument params
+ GLMessage_DataType *arg_params = glmsg.add_args();
+ arg_params->set_isarray(false);
+ arg_params->set_type(GLMessage::DataType::INT);
+ arg_params->add_intvalue((int)params);
+
+ // call function
+ nsecs_t start_time = systemTime();
+ glContext->hooks->gl.glGetnUniformfvEXT(program, location, bufSize, params);
+ nsecs_t end_time = systemTime();
+
+ fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ glContext->traceGLMessage(&glmsg);
+}
+
+void GLTrace_glGetnUniformivEXT(GLuint program, GLint location, GLsizei bufSize, GLint *params) {
+ GLMessage glmsg;
+ GLTraceContext *glContext = getGLTraceContext();
+
+ glmsg.set_function(GLMessage::glGetnUniformivEXT);
+
+ // copy argument program
+ GLMessage_DataType *arg_program = glmsg.add_args();
+ arg_program->set_isarray(false);
+ arg_program->set_type(GLMessage::DataType::INT);
+ arg_program->add_intvalue(program);
+
+ // copy argument location
+ GLMessage_DataType *arg_location = glmsg.add_args();
+ arg_location->set_isarray(false);
+ arg_location->set_type(GLMessage::DataType::INT);
+ arg_location->add_intvalue(location);
+
+ // copy argument bufSize
+ GLMessage_DataType *arg_bufSize = glmsg.add_args();
+ arg_bufSize->set_isarray(false);
+ arg_bufSize->set_type(GLMessage::DataType::INT);
+ arg_bufSize->add_intvalue(bufSize);
+
+ // copy argument params
+ GLMessage_DataType *arg_params = glmsg.add_args();
+ arg_params->set_isarray(false);
+ arg_params->set_type(GLMessage::DataType::INT);
+ arg_params->add_intvalue((int)params);
+
+ // call function
+ nsecs_t start_time = systemTime();
+ glContext->hooks->gl.glGetnUniformivEXT(program, location, bufSize, params);
+ nsecs_t end_time = systemTime();
+
+ fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ glContext->traceGLMessage(&glmsg);
+}
+
+void GLTrace_glUseProgramStagesEXT(GLuint pipeline, GLbitfield stages, GLuint program) {
+ GLMessage glmsg;
+ GLTraceContext *glContext = getGLTraceContext();
+
+ glmsg.set_function(GLMessage::glUseProgramStagesEXT);
+
+ // copy argument pipeline
+ GLMessage_DataType *arg_pipeline = glmsg.add_args();
+ arg_pipeline->set_isarray(false);
+ arg_pipeline->set_type(GLMessage::DataType::INT);
+ arg_pipeline->add_intvalue(pipeline);
+
+ // copy argument stages
+ GLMessage_DataType *arg_stages = glmsg.add_args();
+ arg_stages->set_isarray(false);
+ arg_stages->set_type(GLMessage::DataType::INT);
+ arg_stages->add_intvalue(stages);
+
+ // copy argument program
+ GLMessage_DataType *arg_program = glmsg.add_args();
+ arg_program->set_isarray(false);
+ arg_program->set_type(GLMessage::DataType::INT);
+ arg_program->add_intvalue(program);
+
+ // call function
+ nsecs_t start_time = systemTime();
+ glContext->hooks->gl.glUseProgramStagesEXT(pipeline, stages, program);
+ nsecs_t end_time = systemTime();
+
+ fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ glContext->traceGLMessage(&glmsg);
+}
+
+void GLTrace_glActiveShaderProgramEXT(GLuint pipeline, GLuint program) {
+ GLMessage glmsg;
+ GLTraceContext *glContext = getGLTraceContext();
+
+ glmsg.set_function(GLMessage::glActiveShaderProgramEXT);
+
+ // copy argument pipeline
+ GLMessage_DataType *arg_pipeline = glmsg.add_args();
+ arg_pipeline->set_isarray(false);
+ arg_pipeline->set_type(GLMessage::DataType::INT);
+ arg_pipeline->add_intvalue(pipeline);
+
+ // copy argument program
+ GLMessage_DataType *arg_program = glmsg.add_args();
+ arg_program->set_isarray(false);
+ arg_program->set_type(GLMessage::DataType::INT);
+ arg_program->add_intvalue(program);
+
+ // call function
+ nsecs_t start_time = systemTime();
+ glContext->hooks->gl.glActiveShaderProgramEXT(pipeline, program);
+ nsecs_t end_time = systemTime();
+
+ fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ glContext->traceGLMessage(&glmsg);
+}
+
+GLuint GLTrace_glCreateShaderProgramvEXT(GLenum type, GLsizei count, const GLchar **strings) {
+ GLMessage glmsg;
+ GLTraceContext *glContext = getGLTraceContext();
+
+ glmsg.set_function(GLMessage::glCreateShaderProgramvEXT);
+
+ // copy argument type
+ GLMessage_DataType *arg_type = glmsg.add_args();
+ arg_type->set_isarray(false);
+ arg_type->set_type(GLMessage::DataType::ENUM);
+ arg_type->add_intvalue((int)type);
+
+ // copy argument count
+ GLMessage_DataType *arg_count = glmsg.add_args();
+ arg_count->set_isarray(false);
+ arg_count->set_type(GLMessage::DataType::INT);
+ arg_count->add_intvalue(count);
+
+ // copy argument strings
+ GLMessage_DataType *arg_strings = glmsg.add_args();
+ arg_strings->set_isarray(false);
+ arg_strings->set_type(GLMessage::DataType::INT);
+ arg_strings->add_intvalue((int)strings);
+
+ // call function
+ nsecs_t start_time = systemTime();
+ GLuint retValue = glContext->hooks->gl.glCreateShaderProgramvEXT(type, count, strings);
+ nsecs_t end_time = systemTime();
+
+ // set return value
+ GLMessage_DataType *rt = glmsg.mutable_returnvalue();
+ rt->set_isarray(false);
+ rt->set_type(GLMessage::DataType::INT);
+ rt->add_intvalue(retValue);
+
+ fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ glContext->traceGLMessage(&glmsg);
+
+ return retValue;
+}
+
+void GLTrace_glBindProgramPipelineEXT(GLuint pipeline) {
+ GLMessage glmsg;
+ GLTraceContext *glContext = getGLTraceContext();
+
+ glmsg.set_function(GLMessage::glBindProgramPipelineEXT);
+
+ // copy argument pipeline
+ GLMessage_DataType *arg_pipeline = glmsg.add_args();
+ arg_pipeline->set_isarray(false);
+ arg_pipeline->set_type(GLMessage::DataType::INT);
+ arg_pipeline->add_intvalue(pipeline);
+
+ // call function
+ nsecs_t start_time = systemTime();
+ glContext->hooks->gl.glBindProgramPipelineEXT(pipeline);
+ nsecs_t end_time = systemTime();
+
+ fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ glContext->traceGLMessage(&glmsg);
+}
+
+void GLTrace_glDeleteProgramPipelinesEXT(GLsizei n, const GLuint *pipelines) {
+ GLMessage glmsg;
+ GLTraceContext *glContext = getGLTraceContext();
+
+ glmsg.set_function(GLMessage::glDeleteProgramPipelinesEXT);
+
+ // copy argument n
+ GLMessage_DataType *arg_n = glmsg.add_args();
+ arg_n->set_isarray(false);
+ arg_n->set_type(GLMessage::DataType::INT);
+ arg_n->add_intvalue(n);
+
+ // copy argument pipelines
+ GLMessage_DataType *arg_pipelines = glmsg.add_args();
+ arg_pipelines->set_isarray(false);
+ arg_pipelines->set_type(GLMessage::DataType::INT);
+ arg_pipelines->add_intvalue((int)pipelines);
+
+ // call function
+ nsecs_t start_time = systemTime();
+ glContext->hooks->gl.glDeleteProgramPipelinesEXT(n, pipelines);
+ nsecs_t end_time = systemTime();
+
+ fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ glContext->traceGLMessage(&glmsg);
+}
+
+void GLTrace_glGenProgramPipelinesEXT(GLsizei n, GLuint *pipelines) {
+ GLMessage glmsg;
+ GLTraceContext *glContext = getGLTraceContext();
+
+ glmsg.set_function(GLMessage::glGenProgramPipelinesEXT);
+
+ // copy argument n
+ GLMessage_DataType *arg_n = glmsg.add_args();
+ arg_n->set_isarray(false);
+ arg_n->set_type(GLMessage::DataType::INT);
+ arg_n->add_intvalue(n);
+
+ // copy argument pipelines
+ GLMessage_DataType *arg_pipelines = glmsg.add_args();
+ arg_pipelines->set_isarray(false);
+ arg_pipelines->set_type(GLMessage::DataType::INT);
+ arg_pipelines->add_intvalue((int)pipelines);
+
+ // call function
+ nsecs_t start_time = systemTime();
+ glContext->hooks->gl.glGenProgramPipelinesEXT(n, pipelines);
+ nsecs_t end_time = systemTime();
+
+ fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ glContext->traceGLMessage(&glmsg);
+}
+
+GLboolean GLTrace_glIsProgramPipelineEXT(GLuint pipeline) {
+ GLMessage glmsg;
+ GLTraceContext *glContext = getGLTraceContext();
+
+ glmsg.set_function(GLMessage::glIsProgramPipelineEXT);
+
+ // copy argument pipeline
+ GLMessage_DataType *arg_pipeline = glmsg.add_args();
+ arg_pipeline->set_isarray(false);
+ arg_pipeline->set_type(GLMessage::DataType::INT);
+ arg_pipeline->add_intvalue(pipeline);
+
+ // call function
+ nsecs_t start_time = systemTime();
+ GLboolean retValue = glContext->hooks->gl.glIsProgramPipelineEXT(pipeline);
+ nsecs_t end_time = systemTime();
+
+ // set return value
+ GLMessage_DataType *rt = glmsg.mutable_returnvalue();
+ rt->set_isarray(false);
+ rt->set_type(GLMessage::DataType::BOOL);
+ rt->add_boolvalue(retValue);
+
+ fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ glContext->traceGLMessage(&glmsg);
+
+ return retValue;
+}
+
+void GLTrace_glProgramParameteriEXT(GLuint program, GLenum pname, GLint value) {
+ GLMessage glmsg;
+ GLTraceContext *glContext = getGLTraceContext();
+
+ glmsg.set_function(GLMessage::glProgramParameteriEXT);
+
+ // copy argument program
+ GLMessage_DataType *arg_program = glmsg.add_args();
+ arg_program->set_isarray(false);
+ arg_program->set_type(GLMessage::DataType::INT);
+ arg_program->add_intvalue(program);
+
+ // copy argument pname
+ GLMessage_DataType *arg_pname = glmsg.add_args();
+ arg_pname->set_isarray(false);
+ arg_pname->set_type(GLMessage::DataType::ENUM);
+ arg_pname->add_intvalue((int)pname);
+
+ // copy argument value
+ GLMessage_DataType *arg_value = glmsg.add_args();
+ arg_value->set_isarray(false);
+ arg_value->set_type(GLMessage::DataType::INT);
+ arg_value->add_intvalue(value);
+
+ // call function
+ nsecs_t start_time = systemTime();
+ glContext->hooks->gl.glProgramParameteriEXT(program, pname, value);
+ nsecs_t end_time = systemTime();
+
+ fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ glContext->traceGLMessage(&glmsg);
+}
+
+void GLTrace_glGetProgramPipelineivEXT(GLuint pipeline, GLenum pname, GLint *params) {
+ GLMessage glmsg;
+ GLTraceContext *glContext = getGLTraceContext();
+
+ glmsg.set_function(GLMessage::glGetProgramPipelineivEXT);
+
+ // copy argument pipeline
+ GLMessage_DataType *arg_pipeline = glmsg.add_args();
+ arg_pipeline->set_isarray(false);
+ arg_pipeline->set_type(GLMessage::DataType::INT);
+ arg_pipeline->add_intvalue(pipeline);
+
+ // copy argument pname
+ GLMessage_DataType *arg_pname = glmsg.add_args();
+ arg_pname->set_isarray(false);
+ arg_pname->set_type(GLMessage::DataType::ENUM);
+ arg_pname->add_intvalue((int)pname);
+
+ // copy argument params
+ GLMessage_DataType *arg_params = glmsg.add_args();
+ arg_params->set_isarray(false);
+ arg_params->set_type(GLMessage::DataType::INT);
+ arg_params->add_intvalue((int)params);
+
+ // call function
+ nsecs_t start_time = systemTime();
+ glContext->hooks->gl.glGetProgramPipelineivEXT(pipeline, pname, params);
+ nsecs_t end_time = systemTime();
+
+ fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ glContext->traceGLMessage(&glmsg);
+}
+
+void GLTrace_glProgramUniform1iEXT(GLuint program, GLint location, GLint x) {
+ GLMessage glmsg;
+ GLTraceContext *glContext = getGLTraceContext();
+
+ glmsg.set_function(GLMessage::glProgramUniform1iEXT);
+
+ // copy argument program
+ GLMessage_DataType *arg_program = glmsg.add_args();
+ arg_program->set_isarray(false);
+ arg_program->set_type(GLMessage::DataType::INT);
+ arg_program->add_intvalue(program);
+
+ // copy argument location
+ GLMessage_DataType *arg_location = glmsg.add_args();
+ arg_location->set_isarray(false);
+ arg_location->set_type(GLMessage::DataType::INT);
+ arg_location->add_intvalue(location);
+
+ // copy argument x
+ GLMessage_DataType *arg_x = glmsg.add_args();
+ arg_x->set_isarray(false);
+ arg_x->set_type(GLMessage::DataType::INT);
+ arg_x->add_intvalue(x);
+
+ // call function
+ nsecs_t start_time = systemTime();
+ glContext->hooks->gl.glProgramUniform1iEXT(program, location, x);
+ nsecs_t end_time = systemTime();
+
+ fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ glContext->traceGLMessage(&glmsg);
+}
+
+void GLTrace_glProgramUniform2iEXT(GLuint program, GLint location, GLint x, GLint y) {
+ GLMessage glmsg;
+ GLTraceContext *glContext = getGLTraceContext();
+
+ glmsg.set_function(GLMessage::glProgramUniform2iEXT);
+
+ // copy argument program
+ GLMessage_DataType *arg_program = glmsg.add_args();
+ arg_program->set_isarray(false);
+ arg_program->set_type(GLMessage::DataType::INT);
+ arg_program->add_intvalue(program);
+
+ // copy argument location
+ GLMessage_DataType *arg_location = glmsg.add_args();
+ arg_location->set_isarray(false);
+ arg_location->set_type(GLMessage::DataType::INT);
+ arg_location->add_intvalue(location);
+
+ // copy argument x
+ GLMessage_DataType *arg_x = glmsg.add_args();
+ arg_x->set_isarray(false);
+ arg_x->set_type(GLMessage::DataType::INT);
+ arg_x->add_intvalue(x);
+
+ // copy argument y
+ GLMessage_DataType *arg_y = glmsg.add_args();
+ arg_y->set_isarray(false);
+ arg_y->set_type(GLMessage::DataType::INT);
+ arg_y->add_intvalue(y);
+
+ // call function
+ nsecs_t start_time = systemTime();
+ glContext->hooks->gl.glProgramUniform2iEXT(program, location, x, y);
+ nsecs_t end_time = systemTime();
+
+ fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ glContext->traceGLMessage(&glmsg);
+}
+
+void GLTrace_glProgramUniform3iEXT(GLuint program, GLint location, GLint x, GLint y, GLint z) {
+ GLMessage glmsg;
+ GLTraceContext *glContext = getGLTraceContext();
+
+ glmsg.set_function(GLMessage::glProgramUniform3iEXT);
+
+ // copy argument program
+ GLMessage_DataType *arg_program = glmsg.add_args();
+ arg_program->set_isarray(false);
+ arg_program->set_type(GLMessage::DataType::INT);
+ arg_program->add_intvalue(program);
+
+ // copy argument location
+ GLMessage_DataType *arg_location = glmsg.add_args();
+ arg_location->set_isarray(false);
+ arg_location->set_type(GLMessage::DataType::INT);
+ arg_location->add_intvalue(location);
+
+ // copy argument x
+ GLMessage_DataType *arg_x = glmsg.add_args();
+ arg_x->set_isarray(false);
+ arg_x->set_type(GLMessage::DataType::INT);
+ arg_x->add_intvalue(x);
+
+ // copy argument y
+ GLMessage_DataType *arg_y = glmsg.add_args();
+ arg_y->set_isarray(false);
+ arg_y->set_type(GLMessage::DataType::INT);
+ arg_y->add_intvalue(y);
+
+ // copy argument z
+ GLMessage_DataType *arg_z = glmsg.add_args();
+ arg_z->set_isarray(false);
+ arg_z->set_type(GLMessage::DataType::INT);
+ arg_z->add_intvalue(z);
+
+ // call function
+ nsecs_t start_time = systemTime();
+ glContext->hooks->gl.glProgramUniform3iEXT(program, location, x, y, z);
+ nsecs_t end_time = systemTime();
+
+ fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ glContext->traceGLMessage(&glmsg);
+}
+
+void GLTrace_glProgramUniform4iEXT(GLuint program, GLint location, GLint x, GLint y, GLint z, GLint w) {
+ GLMessage glmsg;
+ GLTraceContext *glContext = getGLTraceContext();
+
+ glmsg.set_function(GLMessage::glProgramUniform4iEXT);
+
+ // copy argument program
+ GLMessage_DataType *arg_program = glmsg.add_args();
+ arg_program->set_isarray(false);
+ arg_program->set_type(GLMessage::DataType::INT);
+ arg_program->add_intvalue(program);
+
+ // copy argument location
+ GLMessage_DataType *arg_location = glmsg.add_args();
+ arg_location->set_isarray(false);
+ arg_location->set_type(GLMessage::DataType::INT);
+ arg_location->add_intvalue(location);
+
+ // copy argument x
+ GLMessage_DataType *arg_x = glmsg.add_args();
+ arg_x->set_isarray(false);
+ arg_x->set_type(GLMessage::DataType::INT);
+ arg_x->add_intvalue(x);
+
+ // copy argument y
+ GLMessage_DataType *arg_y = glmsg.add_args();
+ arg_y->set_isarray(false);
+ arg_y->set_type(GLMessage::DataType::INT);
+ arg_y->add_intvalue(y);
+
+ // copy argument z
+ GLMessage_DataType *arg_z = glmsg.add_args();
+ arg_z->set_isarray(false);
+ arg_z->set_type(GLMessage::DataType::INT);
+ arg_z->add_intvalue(z);
+
+ // copy argument w
+ GLMessage_DataType *arg_w = glmsg.add_args();
+ arg_w->set_isarray(false);
+ arg_w->set_type(GLMessage::DataType::INT);
+ arg_w->add_intvalue(w);
+
+ // call function
+ nsecs_t start_time = systemTime();
+ glContext->hooks->gl.glProgramUniform4iEXT(program, location, x, y, z, w);
+ nsecs_t end_time = systemTime();
+
+ fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ glContext->traceGLMessage(&glmsg);
+}
+
+void GLTrace_glProgramUniform1fEXT(GLuint program, GLint location, GLfloat x) {
+ GLMessage glmsg;
+ GLTraceContext *glContext = getGLTraceContext();
+
+ glmsg.set_function(GLMessage::glProgramUniform1fEXT);
+
+ // copy argument program
+ GLMessage_DataType *arg_program = glmsg.add_args();
+ arg_program->set_isarray(false);
+ arg_program->set_type(GLMessage::DataType::INT);
+ arg_program->add_intvalue(program);
+
+ // copy argument location
+ GLMessage_DataType *arg_location = glmsg.add_args();
+ arg_location->set_isarray(false);
+ arg_location->set_type(GLMessage::DataType::INT);
+ arg_location->add_intvalue(location);
+
+ // copy argument x
+ GLMessage_DataType *arg_x = glmsg.add_args();
+ arg_x->set_isarray(false);
+ arg_x->set_type(GLMessage::DataType::FLOAT);
+ arg_x->add_floatvalue(x);
+
+ // call function
+ nsecs_t start_time = systemTime();
+ glContext->hooks->gl.glProgramUniform1fEXT(program, location, x);
+ nsecs_t end_time = systemTime();
+
+ fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ glContext->traceGLMessage(&glmsg);
+}
+
+void GLTrace_glProgramUniform2fEXT(GLuint program, GLint location, GLfloat x, GLfloat y) {
+ GLMessage glmsg;
+ GLTraceContext *glContext = getGLTraceContext();
+
+ glmsg.set_function(GLMessage::glProgramUniform2fEXT);
+
+ // copy argument program
+ GLMessage_DataType *arg_program = glmsg.add_args();
+ arg_program->set_isarray(false);
+ arg_program->set_type(GLMessage::DataType::INT);
+ arg_program->add_intvalue(program);
+
+ // copy argument location
+ GLMessage_DataType *arg_location = glmsg.add_args();
+ arg_location->set_isarray(false);
+ arg_location->set_type(GLMessage::DataType::INT);
+ arg_location->add_intvalue(location);
+
+ // copy argument x
+ GLMessage_DataType *arg_x = glmsg.add_args();
+ arg_x->set_isarray(false);
+ arg_x->set_type(GLMessage::DataType::FLOAT);
+ arg_x->add_floatvalue(x);
+
+ // copy argument y
+ GLMessage_DataType *arg_y = glmsg.add_args();
+ arg_y->set_isarray(false);
+ arg_y->set_type(GLMessage::DataType::FLOAT);
+ arg_y->add_floatvalue(y);
+
+ // call function
+ nsecs_t start_time = systemTime();
+ glContext->hooks->gl.glProgramUniform2fEXT(program, location, x, y);
+ nsecs_t end_time = systemTime();
+
+ fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ glContext->traceGLMessage(&glmsg);
+}
+
+void GLTrace_glProgramUniform3fEXT(GLuint program, GLint location, GLfloat x, GLfloat y, GLfloat z) {
+ GLMessage glmsg;
+ GLTraceContext *glContext = getGLTraceContext();
+
+ glmsg.set_function(GLMessage::glProgramUniform3fEXT);
+
+ // copy argument program
+ GLMessage_DataType *arg_program = glmsg.add_args();
+ arg_program->set_isarray(false);
+ arg_program->set_type(GLMessage::DataType::INT);
+ arg_program->add_intvalue(program);
+
+ // copy argument location
+ GLMessage_DataType *arg_location = glmsg.add_args();
+ arg_location->set_isarray(false);
+ arg_location->set_type(GLMessage::DataType::INT);
+ arg_location->add_intvalue(location);
+
+ // copy argument x
+ GLMessage_DataType *arg_x = glmsg.add_args();
+ arg_x->set_isarray(false);
+ arg_x->set_type(GLMessage::DataType::FLOAT);
+ arg_x->add_floatvalue(x);
+
+ // copy argument y
+ GLMessage_DataType *arg_y = glmsg.add_args();
+ arg_y->set_isarray(false);
+ arg_y->set_type(GLMessage::DataType::FLOAT);
+ arg_y->add_floatvalue(y);
+
+ // copy argument z
+ GLMessage_DataType *arg_z = glmsg.add_args();
+ arg_z->set_isarray(false);
+ arg_z->set_type(GLMessage::DataType::FLOAT);
+ arg_z->add_floatvalue(z);
+
+ // call function
+ nsecs_t start_time = systemTime();
+ glContext->hooks->gl.glProgramUniform3fEXT(program, location, x, y, z);
+ nsecs_t end_time = systemTime();
+
+ fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ glContext->traceGLMessage(&glmsg);
+}
+
+void GLTrace_glProgramUniform4fEXT(GLuint program, GLint location, GLfloat x, GLfloat y, GLfloat z, GLfloat w) {
+ GLMessage glmsg;
+ GLTraceContext *glContext = getGLTraceContext();
+
+ glmsg.set_function(GLMessage::glProgramUniform4fEXT);
+
+ // copy argument program
+ GLMessage_DataType *arg_program = glmsg.add_args();
+ arg_program->set_isarray(false);
+ arg_program->set_type(GLMessage::DataType::INT);
+ arg_program->add_intvalue(program);
+
+ // copy argument location
+ GLMessage_DataType *arg_location = glmsg.add_args();
+ arg_location->set_isarray(false);
+ arg_location->set_type(GLMessage::DataType::INT);
+ arg_location->add_intvalue(location);
+
+ // copy argument x
+ GLMessage_DataType *arg_x = glmsg.add_args();
+ arg_x->set_isarray(false);
+ arg_x->set_type(GLMessage::DataType::FLOAT);
+ arg_x->add_floatvalue(x);
+
+ // copy argument y
+ GLMessage_DataType *arg_y = glmsg.add_args();
+ arg_y->set_isarray(false);
+ arg_y->set_type(GLMessage::DataType::FLOAT);
+ arg_y->add_floatvalue(y);
+
+ // copy argument z
+ GLMessage_DataType *arg_z = glmsg.add_args();
+ arg_z->set_isarray(false);
+ arg_z->set_type(GLMessage::DataType::FLOAT);
+ arg_z->add_floatvalue(z);
+
+ // copy argument w
+ GLMessage_DataType *arg_w = glmsg.add_args();
+ arg_w->set_isarray(false);
+ arg_w->set_type(GLMessage::DataType::FLOAT);
+ arg_w->add_floatvalue(w);
+
+ // call function
+ nsecs_t start_time = systemTime();
+ glContext->hooks->gl.glProgramUniform4fEXT(program, location, x, y, z, w);
+ nsecs_t end_time = systemTime();
+
+ fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ glContext->traceGLMessage(&glmsg);
+}
+
+void GLTrace_glProgramUniform1ivEXT(GLuint program, GLint location, GLsizei count, const GLint *value) {
+ GLMessage glmsg;
+ GLTraceContext *glContext = getGLTraceContext();
+
+ glmsg.set_function(GLMessage::glProgramUniform1ivEXT);
+
+ // copy argument program
+ GLMessage_DataType *arg_program = glmsg.add_args();
+ arg_program->set_isarray(false);
+ arg_program->set_type(GLMessage::DataType::INT);
+ arg_program->add_intvalue(program);
+
+ // copy argument location
+ GLMessage_DataType *arg_location = glmsg.add_args();
+ arg_location->set_isarray(false);
+ arg_location->set_type(GLMessage::DataType::INT);
+ arg_location->add_intvalue(location);
+
+ // copy argument count
+ GLMessage_DataType *arg_count = glmsg.add_args();
+ arg_count->set_isarray(false);
+ arg_count->set_type(GLMessage::DataType::INT);
+ arg_count->add_intvalue(count);
+
+ // copy argument value
+ GLMessage_DataType *arg_value = glmsg.add_args();
+ arg_value->set_isarray(false);
+ arg_value->set_type(GLMessage::DataType::INT);
+ arg_value->add_intvalue((int)value);
+
+ // call function
+ nsecs_t start_time = systemTime();
+ glContext->hooks->gl.glProgramUniform1ivEXT(program, location, count, value);
+ nsecs_t end_time = systemTime();
+
+ fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ glContext->traceGLMessage(&glmsg);
+}
+
+void GLTrace_glProgramUniform2ivEXT(GLuint program, GLint location, GLsizei count, const GLint *value) {
+ GLMessage glmsg;
+ GLTraceContext *glContext = getGLTraceContext();
+
+ glmsg.set_function(GLMessage::glProgramUniform2ivEXT);
+
+ // copy argument program
+ GLMessage_DataType *arg_program = glmsg.add_args();
+ arg_program->set_isarray(false);
+ arg_program->set_type(GLMessage::DataType::INT);
+ arg_program->add_intvalue(program);
+
+ // copy argument location
+ GLMessage_DataType *arg_location = glmsg.add_args();
+ arg_location->set_isarray(false);
+ arg_location->set_type(GLMessage::DataType::INT);
+ arg_location->add_intvalue(location);
+
+ // copy argument count
+ GLMessage_DataType *arg_count = glmsg.add_args();
+ arg_count->set_isarray(false);
+ arg_count->set_type(GLMessage::DataType::INT);
+ arg_count->add_intvalue(count);
+
+ // copy argument value
+ GLMessage_DataType *arg_value = glmsg.add_args();
+ arg_value->set_isarray(false);
+ arg_value->set_type(GLMessage::DataType::INT);
+ arg_value->add_intvalue((int)value);
+
+ // call function
+ nsecs_t start_time = systemTime();
+ glContext->hooks->gl.glProgramUniform2ivEXT(program, location, count, value);
+ nsecs_t end_time = systemTime();
+
+ fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ glContext->traceGLMessage(&glmsg);
+}
+
+void GLTrace_glProgramUniform3ivEXT(GLuint program, GLint location, GLsizei count, const GLint *value) {
+ GLMessage glmsg;
+ GLTraceContext *glContext = getGLTraceContext();
+
+ glmsg.set_function(GLMessage::glProgramUniform3ivEXT);
+
+ // copy argument program
+ GLMessage_DataType *arg_program = glmsg.add_args();
+ arg_program->set_isarray(false);
+ arg_program->set_type(GLMessage::DataType::INT);
+ arg_program->add_intvalue(program);
+
+ // copy argument location
+ GLMessage_DataType *arg_location = glmsg.add_args();
+ arg_location->set_isarray(false);
+ arg_location->set_type(GLMessage::DataType::INT);
+ arg_location->add_intvalue(location);
+
+ // copy argument count
+ GLMessage_DataType *arg_count = glmsg.add_args();
+ arg_count->set_isarray(false);
+ arg_count->set_type(GLMessage::DataType::INT);
+ arg_count->add_intvalue(count);
+
+ // copy argument value
+ GLMessage_DataType *arg_value = glmsg.add_args();
+ arg_value->set_isarray(false);
+ arg_value->set_type(GLMessage::DataType::INT);
+ arg_value->add_intvalue((int)value);
+
+ // call function
+ nsecs_t start_time = systemTime();
+ glContext->hooks->gl.glProgramUniform3ivEXT(program, location, count, value);
+ nsecs_t end_time = systemTime();
+
+ fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ glContext->traceGLMessage(&glmsg);
+}
+
+void GLTrace_glProgramUniform4ivEXT(GLuint program, GLint location, GLsizei count, const GLint *value) {
+ GLMessage glmsg;
+ GLTraceContext *glContext = getGLTraceContext();
+
+ glmsg.set_function(GLMessage::glProgramUniform4ivEXT);
+
+ // copy argument program
+ GLMessage_DataType *arg_program = glmsg.add_args();
+ arg_program->set_isarray(false);
+ arg_program->set_type(GLMessage::DataType::INT);
+ arg_program->add_intvalue(program);
+
+ // copy argument location
+ GLMessage_DataType *arg_location = glmsg.add_args();
+ arg_location->set_isarray(false);
+ arg_location->set_type(GLMessage::DataType::INT);
+ arg_location->add_intvalue(location);
+
+ // copy argument count
+ GLMessage_DataType *arg_count = glmsg.add_args();
+ arg_count->set_isarray(false);
+ arg_count->set_type(GLMessage::DataType::INT);
+ arg_count->add_intvalue(count);
+
+ // copy argument value
+ GLMessage_DataType *arg_value = glmsg.add_args();
+ arg_value->set_isarray(false);
+ arg_value->set_type(GLMessage::DataType::INT);
+ arg_value->add_intvalue((int)value);
+
+ // call function
+ nsecs_t start_time = systemTime();
+ glContext->hooks->gl.glProgramUniform4ivEXT(program, location, count, value);
+ nsecs_t end_time = systemTime();
+
+ fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ glContext->traceGLMessage(&glmsg);
+}
+
+void GLTrace_glProgramUniform1fvEXT(GLuint program, GLint location, GLsizei count, const GLfloat *value) {
+ GLMessage glmsg;
+ GLTraceContext *glContext = getGLTraceContext();
+
+ glmsg.set_function(GLMessage::glProgramUniform1fvEXT);
+
+ // copy argument program
+ GLMessage_DataType *arg_program = glmsg.add_args();
+ arg_program->set_isarray(false);
+ arg_program->set_type(GLMessage::DataType::INT);
+ arg_program->add_intvalue(program);
+
+ // copy argument location
+ GLMessage_DataType *arg_location = glmsg.add_args();
+ arg_location->set_isarray(false);
+ arg_location->set_type(GLMessage::DataType::INT);
+ arg_location->add_intvalue(location);
+
+ // copy argument count
+ GLMessage_DataType *arg_count = glmsg.add_args();
+ arg_count->set_isarray(false);
+ arg_count->set_type(GLMessage::DataType::INT);
+ arg_count->add_intvalue(count);
+
+ // copy argument value
+ GLMessage_DataType *arg_value = glmsg.add_args();
+ arg_value->set_isarray(false);
+ arg_value->set_type(GLMessage::DataType::INT);
+ arg_value->add_intvalue((int)value);
+
+ // call function
+ nsecs_t start_time = systemTime();
+ glContext->hooks->gl.glProgramUniform1fvEXT(program, location, count, value);
+ nsecs_t end_time = systemTime();
+
+ fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ glContext->traceGLMessage(&glmsg);
+}
+
+void GLTrace_glProgramUniform2fvEXT(GLuint program, GLint location, GLsizei count, const GLfloat *value) {
+ GLMessage glmsg;
+ GLTraceContext *glContext = getGLTraceContext();
+
+ glmsg.set_function(GLMessage::glProgramUniform2fvEXT);
+
+ // copy argument program
+ GLMessage_DataType *arg_program = glmsg.add_args();
+ arg_program->set_isarray(false);
+ arg_program->set_type(GLMessage::DataType::INT);
+ arg_program->add_intvalue(program);
+
+ // copy argument location
+ GLMessage_DataType *arg_location = glmsg.add_args();
+ arg_location->set_isarray(false);
+ arg_location->set_type(GLMessage::DataType::INT);
+ arg_location->add_intvalue(location);
+
+ // copy argument count
+ GLMessage_DataType *arg_count = glmsg.add_args();
+ arg_count->set_isarray(false);
+ arg_count->set_type(GLMessage::DataType::INT);
+ arg_count->add_intvalue(count);
+
+ // copy argument value
+ GLMessage_DataType *arg_value = glmsg.add_args();
+ arg_value->set_isarray(false);
+ arg_value->set_type(GLMessage::DataType::INT);
+ arg_value->add_intvalue((int)value);
+
+ // call function
+ nsecs_t start_time = systemTime();
+ glContext->hooks->gl.glProgramUniform2fvEXT(program, location, count, value);
+ nsecs_t end_time = systemTime();
+
+ fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ glContext->traceGLMessage(&glmsg);
+}
+
+void GLTrace_glProgramUniform3fvEXT(GLuint program, GLint location, GLsizei count, const GLfloat *value) {
+ GLMessage glmsg;
+ GLTraceContext *glContext = getGLTraceContext();
+
+ glmsg.set_function(GLMessage::glProgramUniform3fvEXT);
+
+ // copy argument program
+ GLMessage_DataType *arg_program = glmsg.add_args();
+ arg_program->set_isarray(false);
+ arg_program->set_type(GLMessage::DataType::INT);
+ arg_program->add_intvalue(program);
+
+ // copy argument location
+ GLMessage_DataType *arg_location = glmsg.add_args();
+ arg_location->set_isarray(false);
+ arg_location->set_type(GLMessage::DataType::INT);
+ arg_location->add_intvalue(location);
+
+ // copy argument count
+ GLMessage_DataType *arg_count = glmsg.add_args();
+ arg_count->set_isarray(false);
+ arg_count->set_type(GLMessage::DataType::INT);
+ arg_count->add_intvalue(count);
+
+ // copy argument value
+ GLMessage_DataType *arg_value = glmsg.add_args();
+ arg_value->set_isarray(false);
+ arg_value->set_type(GLMessage::DataType::INT);
+ arg_value->add_intvalue((int)value);
+
+ // call function
+ nsecs_t start_time = systemTime();
+ glContext->hooks->gl.glProgramUniform3fvEXT(program, location, count, value);
+ nsecs_t end_time = systemTime();
+
+ fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ glContext->traceGLMessage(&glmsg);
+}
+
+void GLTrace_glProgramUniform4fvEXT(GLuint program, GLint location, GLsizei count, const GLfloat *value) {
+ GLMessage glmsg;
+ GLTraceContext *glContext = getGLTraceContext();
+
+ glmsg.set_function(GLMessage::glProgramUniform4fvEXT);
+
+ // copy argument program
+ GLMessage_DataType *arg_program = glmsg.add_args();
+ arg_program->set_isarray(false);
+ arg_program->set_type(GLMessage::DataType::INT);
+ arg_program->add_intvalue(program);
+
+ // copy argument location
+ GLMessage_DataType *arg_location = glmsg.add_args();
+ arg_location->set_isarray(false);
+ arg_location->set_type(GLMessage::DataType::INT);
+ arg_location->add_intvalue(location);
+
+ // copy argument count
+ GLMessage_DataType *arg_count = glmsg.add_args();
+ arg_count->set_isarray(false);
+ arg_count->set_type(GLMessage::DataType::INT);
+ arg_count->add_intvalue(count);
+
+ // copy argument value
+ GLMessage_DataType *arg_value = glmsg.add_args();
+ arg_value->set_isarray(false);
+ arg_value->set_type(GLMessage::DataType::INT);
+ arg_value->add_intvalue((int)value);
+
+ // call function
+ nsecs_t start_time = systemTime();
+ glContext->hooks->gl.glProgramUniform4fvEXT(program, location, count, value);
+ nsecs_t end_time = systemTime();
+
+ fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ glContext->traceGLMessage(&glmsg);
+}
+
+void GLTrace_glProgramUniformMatrix2fvEXT(GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) {
+ GLMessage glmsg;
+ GLTraceContext *glContext = getGLTraceContext();
+
+ glmsg.set_function(GLMessage::glProgramUniformMatrix2fvEXT);
+
+ // copy argument program
+ GLMessage_DataType *arg_program = glmsg.add_args();
+ arg_program->set_isarray(false);
+ arg_program->set_type(GLMessage::DataType::INT);
+ arg_program->add_intvalue(program);
+
+ // copy argument location
+ GLMessage_DataType *arg_location = glmsg.add_args();
+ arg_location->set_isarray(false);
+ arg_location->set_type(GLMessage::DataType::INT);
+ arg_location->add_intvalue(location);
+
+ // copy argument count
+ GLMessage_DataType *arg_count = glmsg.add_args();
+ arg_count->set_isarray(false);
+ arg_count->set_type(GLMessage::DataType::INT);
+ arg_count->add_intvalue(count);
+
+ // copy argument transpose
+ GLMessage_DataType *arg_transpose = glmsg.add_args();
+ arg_transpose->set_isarray(false);
+ arg_transpose->set_type(GLMessage::DataType::BOOL);
+ arg_transpose->add_boolvalue(transpose);
+
+ // copy argument value
+ GLMessage_DataType *arg_value = glmsg.add_args();
+ arg_value->set_isarray(false);
+ arg_value->set_type(GLMessage::DataType::INT);
+ arg_value->add_intvalue((int)value);
+
+ // call function
+ nsecs_t start_time = systemTime();
+ glContext->hooks->gl.glProgramUniformMatrix2fvEXT(program, location, count, transpose, value);
+ nsecs_t end_time = systemTime();
+
+ fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ glContext->traceGLMessage(&glmsg);
+}
+
+void GLTrace_glProgramUniformMatrix3fvEXT(GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) {
+ GLMessage glmsg;
+ GLTraceContext *glContext = getGLTraceContext();
+
+ glmsg.set_function(GLMessage::glProgramUniformMatrix3fvEXT);
+
+ // copy argument program
+ GLMessage_DataType *arg_program = glmsg.add_args();
+ arg_program->set_isarray(false);
+ arg_program->set_type(GLMessage::DataType::INT);
+ arg_program->add_intvalue(program);
+
+ // copy argument location
+ GLMessage_DataType *arg_location = glmsg.add_args();
+ arg_location->set_isarray(false);
+ arg_location->set_type(GLMessage::DataType::INT);
+ arg_location->add_intvalue(location);
+
+ // copy argument count
+ GLMessage_DataType *arg_count = glmsg.add_args();
+ arg_count->set_isarray(false);
+ arg_count->set_type(GLMessage::DataType::INT);
+ arg_count->add_intvalue(count);
+
+ // copy argument transpose
+ GLMessage_DataType *arg_transpose = glmsg.add_args();
+ arg_transpose->set_isarray(false);
+ arg_transpose->set_type(GLMessage::DataType::BOOL);
+ arg_transpose->add_boolvalue(transpose);
+
+ // copy argument value
+ GLMessage_DataType *arg_value = glmsg.add_args();
+ arg_value->set_isarray(false);
+ arg_value->set_type(GLMessage::DataType::INT);
+ arg_value->add_intvalue((int)value);
+
+ // call function
+ nsecs_t start_time = systemTime();
+ glContext->hooks->gl.glProgramUniformMatrix3fvEXT(program, location, count, transpose, value);
+ nsecs_t end_time = systemTime();
+
+ fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ glContext->traceGLMessage(&glmsg);
+}
+
+void GLTrace_glProgramUniformMatrix4fvEXT(GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) {
+ GLMessage glmsg;
+ GLTraceContext *glContext = getGLTraceContext();
+
+ glmsg.set_function(GLMessage::glProgramUniformMatrix4fvEXT);
+
+ // copy argument program
+ GLMessage_DataType *arg_program = glmsg.add_args();
+ arg_program->set_isarray(false);
+ arg_program->set_type(GLMessage::DataType::INT);
+ arg_program->add_intvalue(program);
+
+ // copy argument location
+ GLMessage_DataType *arg_location = glmsg.add_args();
+ arg_location->set_isarray(false);
+ arg_location->set_type(GLMessage::DataType::INT);
+ arg_location->add_intvalue(location);
+
+ // copy argument count
+ GLMessage_DataType *arg_count = glmsg.add_args();
+ arg_count->set_isarray(false);
+ arg_count->set_type(GLMessage::DataType::INT);
+ arg_count->add_intvalue(count);
+
+ // copy argument transpose
+ GLMessage_DataType *arg_transpose = glmsg.add_args();
+ arg_transpose->set_isarray(false);
+ arg_transpose->set_type(GLMessage::DataType::BOOL);
+ arg_transpose->add_boolvalue(transpose);
+
+ // copy argument value
+ GLMessage_DataType *arg_value = glmsg.add_args();
+ arg_value->set_isarray(false);
+ arg_value->set_type(GLMessage::DataType::INT);
+ arg_value->add_intvalue((int)value);
+
+ // call function
+ nsecs_t start_time = systemTime();
+ glContext->hooks->gl.glProgramUniformMatrix4fvEXT(program, location, count, transpose, value);
+ nsecs_t end_time = systemTime();
+
+ fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ glContext->traceGLMessage(&glmsg);
+}
+
+void GLTrace_glValidateProgramPipelineEXT(GLuint pipeline) {
+ GLMessage glmsg;
+ GLTraceContext *glContext = getGLTraceContext();
+
+ glmsg.set_function(GLMessage::glValidateProgramPipelineEXT);
+
+ // copy argument pipeline
+ GLMessage_DataType *arg_pipeline = glmsg.add_args();
+ arg_pipeline->set_isarray(false);
+ arg_pipeline->set_type(GLMessage::DataType::INT);
+ arg_pipeline->add_intvalue(pipeline);
+
+ // call function
+ nsecs_t start_time = systemTime();
+ glContext->hooks->gl.glValidateProgramPipelineEXT(pipeline);
+ nsecs_t end_time = systemTime();
+
+ fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ glContext->traceGLMessage(&glmsg);
+}
+
+void GLTrace_glGetProgramPipelineInfoLogEXT(GLuint pipeline, GLsizei bufSize, GLsizei *length, GLchar *infoLog) {
+ GLMessage glmsg;
+ GLTraceContext *glContext = getGLTraceContext();
+
+ glmsg.set_function(GLMessage::glGetProgramPipelineInfoLogEXT);
+
+ // copy argument pipeline
+ GLMessage_DataType *arg_pipeline = glmsg.add_args();
+ arg_pipeline->set_isarray(false);
+ arg_pipeline->set_type(GLMessage::DataType::INT);
+ arg_pipeline->add_intvalue(pipeline);
+
+ // copy argument bufSize
+ GLMessage_DataType *arg_bufSize = glmsg.add_args();
+ arg_bufSize->set_isarray(false);
+ arg_bufSize->set_type(GLMessage::DataType::INT);
+ arg_bufSize->add_intvalue(bufSize);
+
+ // copy argument length
+ GLMessage_DataType *arg_length = glmsg.add_args();
+ arg_length->set_isarray(false);
+ arg_length->set_type(GLMessage::DataType::INT);
+ arg_length->add_intvalue((int)length);
+
+ // copy argument infoLog
+ GLMessage_DataType *arg_infoLog = glmsg.add_args();
+ arg_infoLog->set_isarray(false);
+ arg_infoLog->set_type(GLMessage::DataType::INT);
+ arg_infoLog->add_intvalue((int)infoLog);
+
+ // call function
+ nsecs_t start_time = systemTime();
+ glContext->hooks->gl.glGetProgramPipelineInfoLogEXT(pipeline, bufSize, length, infoLog);
+ nsecs_t end_time = systemTime();
+
+ fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ glContext->traceGLMessage(&glmsg);
+}
+
+void GLTrace_glTexStorage1DEXT(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width) {
+ GLMessage glmsg;
+ GLTraceContext *glContext = getGLTraceContext();
+
+ glmsg.set_function(GLMessage::glTexStorage1DEXT);
+
+ // copy argument target
+ GLMessage_DataType *arg_target = glmsg.add_args();
+ arg_target->set_isarray(false);
+ arg_target->set_type(GLMessage::DataType::ENUM);
+ arg_target->add_intvalue((int)target);
+
+ // copy argument levels
+ GLMessage_DataType *arg_levels = glmsg.add_args();
+ arg_levels->set_isarray(false);
+ arg_levels->set_type(GLMessage::DataType::INT);
+ arg_levels->add_intvalue(levels);
+
+ // copy argument internalformat
+ GLMessage_DataType *arg_internalformat = glmsg.add_args();
+ arg_internalformat->set_isarray(false);
+ arg_internalformat->set_type(GLMessage::DataType::ENUM);
+ arg_internalformat->add_intvalue((int)internalformat);
+
+ // copy argument width
+ GLMessage_DataType *arg_width = glmsg.add_args();
+ arg_width->set_isarray(false);
+ arg_width->set_type(GLMessage::DataType::INT);
+ arg_width->add_intvalue(width);
+
+ // call function
+ nsecs_t start_time = systemTime();
+ glContext->hooks->gl.glTexStorage1DEXT(target, levels, internalformat, width);
+ nsecs_t end_time = systemTime();
+
+ fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ glContext->traceGLMessage(&glmsg);
+}
+
+void GLTrace_glTexStorage2DEXT(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height) {
+ GLMessage glmsg;
+ GLTraceContext *glContext = getGLTraceContext();
+
+ glmsg.set_function(GLMessage::glTexStorage2DEXT);
+
+ // copy argument target
+ GLMessage_DataType *arg_target = glmsg.add_args();
+ arg_target->set_isarray(false);
+ arg_target->set_type(GLMessage::DataType::ENUM);
+ arg_target->add_intvalue((int)target);
+
+ // copy argument levels
+ GLMessage_DataType *arg_levels = glmsg.add_args();
+ arg_levels->set_isarray(false);
+ arg_levels->set_type(GLMessage::DataType::INT);
+ arg_levels->add_intvalue(levels);
+
+ // copy argument internalformat
+ GLMessage_DataType *arg_internalformat = glmsg.add_args();
+ arg_internalformat->set_isarray(false);
+ arg_internalformat->set_type(GLMessage::DataType::ENUM);
+ arg_internalformat->add_intvalue((int)internalformat);
+
+ // copy argument width
+ GLMessage_DataType *arg_width = glmsg.add_args();
+ arg_width->set_isarray(false);
+ arg_width->set_type(GLMessage::DataType::INT);
+ arg_width->add_intvalue(width);
+
+ // copy argument height
+ GLMessage_DataType *arg_height = glmsg.add_args();
+ arg_height->set_isarray(false);
+ arg_height->set_type(GLMessage::DataType::INT);
+ arg_height->add_intvalue(height);
+
+ // call function
+ nsecs_t start_time = systemTime();
+ glContext->hooks->gl.glTexStorage2DEXT(target, levels, internalformat, width, height);
+ nsecs_t end_time = systemTime();
+
+ fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ glContext->traceGLMessage(&glmsg);
+}
+
+void GLTrace_glTexStorage3DEXT(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth) {
+ GLMessage glmsg;
+ GLTraceContext *glContext = getGLTraceContext();
+
+ glmsg.set_function(GLMessage::glTexStorage3DEXT);
+
+ // copy argument target
+ GLMessage_DataType *arg_target = glmsg.add_args();
+ arg_target->set_isarray(false);
+ arg_target->set_type(GLMessage::DataType::ENUM);
+ arg_target->add_intvalue((int)target);
+
+ // copy argument levels
+ GLMessage_DataType *arg_levels = glmsg.add_args();
+ arg_levels->set_isarray(false);
+ arg_levels->set_type(GLMessage::DataType::INT);
+ arg_levels->add_intvalue(levels);
+
+ // copy argument internalformat
+ GLMessage_DataType *arg_internalformat = glmsg.add_args();
+ arg_internalformat->set_isarray(false);
+ arg_internalformat->set_type(GLMessage::DataType::ENUM);
+ arg_internalformat->add_intvalue((int)internalformat);
+
+ // copy argument width
+ GLMessage_DataType *arg_width = glmsg.add_args();
+ arg_width->set_isarray(false);
+ arg_width->set_type(GLMessage::DataType::INT);
+ arg_width->add_intvalue(width);
+
+ // copy argument height
+ GLMessage_DataType *arg_height = glmsg.add_args();
+ arg_height->set_isarray(false);
+ arg_height->set_type(GLMessage::DataType::INT);
+ arg_height->add_intvalue(height);
+
+ // copy argument depth
+ GLMessage_DataType *arg_depth = glmsg.add_args();
+ arg_depth->set_isarray(false);
+ arg_depth->set_type(GLMessage::DataType::INT);
+ arg_depth->add_intvalue(depth);
+
+ // call function
+ nsecs_t start_time = systemTime();
+ glContext->hooks->gl.glTexStorage3DEXT(target, levels, internalformat, width, height, depth);
+ nsecs_t end_time = systemTime();
+
+ fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ glContext->traceGLMessage(&glmsg);
+}
+
+void GLTrace_glTextureStorage1DEXT(GLuint texture, GLenum target, GLsizei levels, GLenum internalformat, GLsizei width) {
+ GLMessage glmsg;
+ GLTraceContext *glContext = getGLTraceContext();
+
+ glmsg.set_function(GLMessage::glTextureStorage1DEXT);
+
+ // copy argument texture
+ GLMessage_DataType *arg_texture = glmsg.add_args();
+ arg_texture->set_isarray(false);
+ arg_texture->set_type(GLMessage::DataType::INT);
+ arg_texture->add_intvalue(texture);
+
+ // copy argument target
+ GLMessage_DataType *arg_target = glmsg.add_args();
+ arg_target->set_isarray(false);
+ arg_target->set_type(GLMessage::DataType::ENUM);
+ arg_target->add_intvalue((int)target);
+
+ // copy argument levels
+ GLMessage_DataType *arg_levels = glmsg.add_args();
+ arg_levels->set_isarray(false);
+ arg_levels->set_type(GLMessage::DataType::INT);
+ arg_levels->add_intvalue(levels);
+
+ // copy argument internalformat
+ GLMessage_DataType *arg_internalformat = glmsg.add_args();
+ arg_internalformat->set_isarray(false);
+ arg_internalformat->set_type(GLMessage::DataType::ENUM);
+ arg_internalformat->add_intvalue((int)internalformat);
+
+ // copy argument width
+ GLMessage_DataType *arg_width = glmsg.add_args();
+ arg_width->set_isarray(false);
+ arg_width->set_type(GLMessage::DataType::INT);
+ arg_width->add_intvalue(width);
+
+ // call function
+ nsecs_t start_time = systemTime();
+ glContext->hooks->gl.glTextureStorage1DEXT(texture, target, levels, internalformat, width);
+ nsecs_t end_time = systemTime();
+
+ fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ glContext->traceGLMessage(&glmsg);
+}
+
+void GLTrace_glTextureStorage2DEXT(GLuint texture, GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height) {
+ GLMessage glmsg;
+ GLTraceContext *glContext = getGLTraceContext();
+
+ glmsg.set_function(GLMessage::glTextureStorage2DEXT);
+
+ // copy argument texture
+ GLMessage_DataType *arg_texture = glmsg.add_args();
+ arg_texture->set_isarray(false);
+ arg_texture->set_type(GLMessage::DataType::INT);
+ arg_texture->add_intvalue(texture);
+
+ // copy argument target
+ GLMessage_DataType *arg_target = glmsg.add_args();
+ arg_target->set_isarray(false);
+ arg_target->set_type(GLMessage::DataType::ENUM);
+ arg_target->add_intvalue((int)target);
+
+ // copy argument levels
+ GLMessage_DataType *arg_levels = glmsg.add_args();
+ arg_levels->set_isarray(false);
+ arg_levels->set_type(GLMessage::DataType::INT);
+ arg_levels->add_intvalue(levels);
+
+ // copy argument internalformat
+ GLMessage_DataType *arg_internalformat = glmsg.add_args();
+ arg_internalformat->set_isarray(false);
+ arg_internalformat->set_type(GLMessage::DataType::ENUM);
+ arg_internalformat->add_intvalue((int)internalformat);
+
+ // copy argument width
+ GLMessage_DataType *arg_width = glmsg.add_args();
+ arg_width->set_isarray(false);
+ arg_width->set_type(GLMessage::DataType::INT);
+ arg_width->add_intvalue(width);
+
+ // copy argument height
+ GLMessage_DataType *arg_height = glmsg.add_args();
+ arg_height->set_isarray(false);
+ arg_height->set_type(GLMessage::DataType::INT);
+ arg_height->add_intvalue(height);
+
+ // call function
+ nsecs_t start_time = systemTime();
+ glContext->hooks->gl.glTextureStorage2DEXT(texture, target, levels, internalformat, width, height);
+ nsecs_t end_time = systemTime();
+
+ fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ glContext->traceGLMessage(&glmsg);
+}
+
+void GLTrace_glTextureStorage3DEXT(GLuint texture, GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth) {
+ GLMessage glmsg;
+ GLTraceContext *glContext = getGLTraceContext();
+
+ glmsg.set_function(GLMessage::glTextureStorage3DEXT);
+
+ // copy argument texture
+ GLMessage_DataType *arg_texture = glmsg.add_args();
+ arg_texture->set_isarray(false);
+ arg_texture->set_type(GLMessage::DataType::INT);
+ arg_texture->add_intvalue(texture);
+
+ // copy argument target
+ GLMessage_DataType *arg_target = glmsg.add_args();
+ arg_target->set_isarray(false);
+ arg_target->set_type(GLMessage::DataType::ENUM);
+ arg_target->add_intvalue((int)target);
+
+ // copy argument levels
+ GLMessage_DataType *arg_levels = glmsg.add_args();
+ arg_levels->set_isarray(false);
+ arg_levels->set_type(GLMessage::DataType::INT);
+ arg_levels->add_intvalue(levels);
+
+ // copy argument internalformat
+ GLMessage_DataType *arg_internalformat = glmsg.add_args();
+ arg_internalformat->set_isarray(false);
+ arg_internalformat->set_type(GLMessage::DataType::ENUM);
+ arg_internalformat->add_intvalue((int)internalformat);
+
+ // copy argument width
+ GLMessage_DataType *arg_width = glmsg.add_args();
+ arg_width->set_isarray(false);
+ arg_width->set_type(GLMessage::DataType::INT);
+ arg_width->add_intvalue(width);
+
+ // copy argument height
+ GLMessage_DataType *arg_height = glmsg.add_args();
+ arg_height->set_isarray(false);
+ arg_height->set_type(GLMessage::DataType::INT);
+ arg_height->add_intvalue(height);
+
+ // copy argument depth
+ GLMessage_DataType *arg_depth = glmsg.add_args();
+ arg_depth->set_isarray(false);
+ arg_depth->set_type(GLMessage::DataType::INT);
+ arg_depth->add_intvalue(depth);
+
+ // call function
+ nsecs_t start_time = systemTime();
+ glContext->hooks->gl.glTextureStorage3DEXT(texture, target, levels, internalformat, width, height, depth);
+ nsecs_t end_time = systemTime();
+
+ fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ glContext->traceGLMessage(&glmsg);
+}
+
void GLTrace_glRenderbufferStorageMultisampleIMG(GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height) {
GLMessage glmsg;
GLTraceContext *glContext = getGLTraceContext();
@@ -6022,6 +8214,75 @@
glContext->traceGLMessage(&glmsg);
}
+void GLTrace_glCoverageMaskNV(GLboolean mask) {
+ GLMessage glmsg;
+ GLTraceContext *glContext = getGLTraceContext();
+
+ glmsg.set_function(GLMessage::glCoverageMaskNV);
+
+ // copy argument mask
+ GLMessage_DataType *arg_mask = glmsg.add_args();
+ arg_mask->set_isarray(false);
+ arg_mask->set_type(GLMessage::DataType::BOOL);
+ arg_mask->add_boolvalue(mask);
+
+ // call function
+ nsecs_t start_time = systemTime();
+ glContext->hooks->gl.glCoverageMaskNV(mask);
+ nsecs_t end_time = systemTime();
+
+ fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ glContext->traceGLMessage(&glmsg);
+}
+
+void GLTrace_glCoverageOperationNV(GLenum operation) {
+ GLMessage glmsg;
+ GLTraceContext *glContext = getGLTraceContext();
+
+ glmsg.set_function(GLMessage::glCoverageOperationNV);
+
+ // copy argument operation
+ GLMessage_DataType *arg_operation = glmsg.add_args();
+ arg_operation->set_isarray(false);
+ arg_operation->set_type(GLMessage::DataType::ENUM);
+ arg_operation->add_intvalue((int)operation);
+
+ // call function
+ nsecs_t start_time = systemTime();
+ glContext->hooks->gl.glCoverageOperationNV(operation);
+ nsecs_t end_time = systemTime();
+
+ fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ glContext->traceGLMessage(&glmsg);
+}
+
+void GLTrace_glDrawBuffersNV(GLsizei n, const GLenum *bufs) {
+ GLMessage glmsg;
+ GLTraceContext *glContext = getGLTraceContext();
+
+ glmsg.set_function(GLMessage::glDrawBuffersNV);
+
+ // copy argument n
+ GLMessage_DataType *arg_n = glmsg.add_args();
+ arg_n->set_isarray(false);
+ arg_n->set_type(GLMessage::DataType::INT);
+ arg_n->add_intvalue(n);
+
+ // copy argument bufs
+ GLMessage_DataType *arg_bufs = glmsg.add_args();
+ arg_bufs->set_isarray(false);
+ arg_bufs->set_type(GLMessage::DataType::INT);
+ arg_bufs->add_intvalue((int)bufs);
+
+ // call function
+ nsecs_t start_time = systemTime();
+ glContext->hooks->gl.glDrawBuffersNV(n, bufs);
+ nsecs_t end_time = systemTime();
+
+ fixupGLMessage(glContext, start_time, end_time, &glmsg);
+ glContext->traceGLMessage(&glmsg);
+}
+
void GLTrace_glDeleteFencesNV(GLsizei n, const GLuint *fences) {
GLMessage glmsg;
GLTraceContext *glContext = getGLTraceContext();
@@ -6215,42 +8476,48 @@
glContext->traceGLMessage(&glmsg);
}
-void GLTrace_glCoverageMaskNV(GLboolean mask) {
+void GLTrace_glReadBufferNV(GLenum mode) {
GLMessage glmsg;
GLTraceContext *glContext = getGLTraceContext();
- glmsg.set_function(GLMessage::glCoverageMaskNV);
+ glmsg.set_function(GLMessage::glReadBufferNV);
- // copy argument mask
- GLMessage_DataType *arg_mask = glmsg.add_args();
- arg_mask->set_isarray(false);
- arg_mask->set_type(GLMessage::DataType::BOOL);
- arg_mask->add_boolvalue(mask);
+ // copy argument mode
+ GLMessage_DataType *arg_mode = glmsg.add_args();
+ arg_mode->set_isarray(false);
+ arg_mode->set_type(GLMessage::DataType::ENUM);
+ arg_mode->add_intvalue((int)mode);
// call function
nsecs_t start_time = systemTime();
- glContext->hooks->gl.glCoverageMaskNV(mask);
+ glContext->hooks->gl.glReadBufferNV(mode);
nsecs_t end_time = systemTime();
fixupGLMessage(glContext, start_time, end_time, &glmsg);
glContext->traceGLMessage(&glmsg);
}
-void GLTrace_glCoverageOperationNV(GLenum operation) {
+void GLTrace_glAlphaFuncQCOM(GLenum func, GLclampf ref) {
GLMessage glmsg;
GLTraceContext *glContext = getGLTraceContext();
- glmsg.set_function(GLMessage::glCoverageOperationNV);
+ glmsg.set_function(GLMessage::glAlphaFuncQCOM);
- // copy argument operation
- GLMessage_DataType *arg_operation = glmsg.add_args();
- arg_operation->set_isarray(false);
- arg_operation->set_type(GLMessage::DataType::ENUM);
- arg_operation->add_intvalue((int)operation);
+ // copy argument func
+ GLMessage_DataType *arg_func = glmsg.add_args();
+ arg_func->set_isarray(false);
+ arg_func->set_type(GLMessage::DataType::ENUM);
+ arg_func->add_intvalue((int)func);
+
+ // copy argument ref
+ GLMessage_DataType *arg_ref = glmsg.add_args();
+ arg_ref->set_isarray(false);
+ arg_ref->set_type(GLMessage::DataType::FLOAT);
+ arg_ref->add_floatvalue(ref);
// call function
nsecs_t start_time = systemTime();
- glContext->hooks->gl.glCoverageOperationNV(operation);
+ glContext->hooks->gl.glAlphaFuncQCOM(func, ref);
nsecs_t end_time = systemTime();
fixupGLMessage(glContext, start_time, end_time, &glmsg);
diff --git a/opengl/libs/GLES_trace/src/gltrace_api.h b/opengl/libs/GLES_trace/src/gltrace_api.h
index 71b5a584..debcac0 100644
--- a/opengl/libs/GLES_trace/src/gltrace_api.h
+++ b/opengl/libs/GLES_trace/src/gltrace_api.h
@@ -194,11 +194,72 @@
void GLTrace_glBeginPerfMonitorAMD(GLuint monitor);
void GLTrace_glEndPerfMonitorAMD(GLuint monitor);
void GLTrace_glGetPerfMonitorCounterDataAMD(GLuint monitor, GLenum pname, GLsizei dataSize, GLuint *data, GLint *bytesWritten);
+void GLTrace_glBlitFramebufferANGLE(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter);
+void GLTrace_glRenderbufferStorageMultisampleANGLE(GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height);
+void GLTrace_glRenderbufferStorageMultisampleAPPLE(GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height);
+void GLTrace_glResolveMultisampleFramebufferAPPLE(void);
+void GLTrace_glLabelObjectEXT(GLenum type, GLuint object, GLsizei length, const GLchar *label);
+void GLTrace_glGetObjectLabelEXT(GLenum type, GLuint object, GLsizei bufSize, GLsizei *length, GLchar *label);
+void GLTrace_glInsertEventMarkerEXT(GLsizei length, const GLchar *marker);
+void GLTrace_glPushGroupMarkerEXT(GLsizei length, const GLchar *marker);
+void GLTrace_glPopGroupMarkerEXT(void);
void GLTrace_glDiscardFramebufferEXT(GLenum target, GLsizei numAttachments, const GLenum *attachments);
+void GLTrace_glRenderbufferStorageMultisampleEXT(GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height);
+void GLTrace_glFramebufferTexture2DMultisampleEXT(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level, GLsizei samples);
void GLTrace_glMultiDrawArraysEXT(GLenum mode, GLint *first, GLsizei *count, GLsizei primcount);
void GLTrace_glMultiDrawElementsEXT(GLenum mode, const GLsizei *count, GLenum type, const GLvoid* *indices, GLsizei primcount);
+void GLTrace_glGenQueriesEXT(GLsizei n, GLuint *ids);
+void GLTrace_glDeleteQueriesEXT(GLsizei n, const GLuint *ids);
+GLboolean GLTrace_glIsQueryEXT(GLuint id);
+void GLTrace_glBeginQueryEXT(GLenum target, GLuint id);
+void GLTrace_glEndQueryEXT(GLenum target);
+void GLTrace_glGetQueryivEXT(GLenum target, GLenum pname, GLint *params);
+void GLTrace_glGetQueryObjectuivEXT(GLuint id, GLenum pname, GLuint *params);
+GLenum GLTrace_glGetGraphicsResetStatusEXT(void);
+void GLTrace_glReadnPixelsEXT(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLsizei bufSize, void *data);
+void GLTrace_glGetnUniformfvEXT(GLuint program, GLint location, GLsizei bufSize, float *params);
+void GLTrace_glGetnUniformivEXT(GLuint program, GLint location, GLsizei bufSize, GLint *params);
+void GLTrace_glUseProgramStagesEXT(GLuint pipeline, GLbitfield stages, GLuint program);
+void GLTrace_glActiveShaderProgramEXT(GLuint pipeline, GLuint program);
+GLuint GLTrace_glCreateShaderProgramvEXT(GLenum type, GLsizei count, const GLchar **strings);
+void GLTrace_glBindProgramPipelineEXT(GLuint pipeline);
+void GLTrace_glDeleteProgramPipelinesEXT(GLsizei n, const GLuint *pipelines);
+void GLTrace_glGenProgramPipelinesEXT(GLsizei n, GLuint *pipelines);
+GLboolean GLTrace_glIsProgramPipelineEXT(GLuint pipeline);
+void GLTrace_glProgramParameteriEXT(GLuint program, GLenum pname, GLint value);
+void GLTrace_glGetProgramPipelineivEXT(GLuint pipeline, GLenum pname, GLint *params);
+void GLTrace_glProgramUniform1iEXT(GLuint program, GLint location, GLint x);
+void GLTrace_glProgramUniform2iEXT(GLuint program, GLint location, GLint x, GLint y);
+void GLTrace_glProgramUniform3iEXT(GLuint program, GLint location, GLint x, GLint y, GLint z);
+void GLTrace_glProgramUniform4iEXT(GLuint program, GLint location, GLint x, GLint y, GLint z, GLint w);
+void GLTrace_glProgramUniform1fEXT(GLuint program, GLint location, GLfloat x);
+void GLTrace_glProgramUniform2fEXT(GLuint program, GLint location, GLfloat x, GLfloat y);
+void GLTrace_glProgramUniform3fEXT(GLuint program, GLint location, GLfloat x, GLfloat y, GLfloat z);
+void GLTrace_glProgramUniform4fEXT(GLuint program, GLint location, GLfloat x, GLfloat y, GLfloat z, GLfloat w);
+void GLTrace_glProgramUniform1ivEXT(GLuint program, GLint location, GLsizei count, const GLint *value);
+void GLTrace_glProgramUniform2ivEXT(GLuint program, GLint location, GLsizei count, const GLint *value);
+void GLTrace_glProgramUniform3ivEXT(GLuint program, GLint location, GLsizei count, const GLint *value);
+void GLTrace_glProgramUniform4ivEXT(GLuint program, GLint location, GLsizei count, const GLint *value);
+void GLTrace_glProgramUniform1fvEXT(GLuint program, GLint location, GLsizei count, const GLfloat *value);
+void GLTrace_glProgramUniform2fvEXT(GLuint program, GLint location, GLsizei count, const GLfloat *value);
+void GLTrace_glProgramUniform3fvEXT(GLuint program, GLint location, GLsizei count, const GLfloat *value);
+void GLTrace_glProgramUniform4fvEXT(GLuint program, GLint location, GLsizei count, const GLfloat *value);
+void GLTrace_glProgramUniformMatrix2fvEXT(GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
+void GLTrace_glProgramUniformMatrix3fvEXT(GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
+void GLTrace_glProgramUniformMatrix4fvEXT(GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
+void GLTrace_glValidateProgramPipelineEXT(GLuint pipeline);
+void GLTrace_glGetProgramPipelineInfoLogEXT(GLuint pipeline, GLsizei bufSize, GLsizei *length, GLchar *infoLog);
+void GLTrace_glTexStorage1DEXT(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width);
+void GLTrace_glTexStorage2DEXT(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height);
+void GLTrace_glTexStorage3DEXT(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth);
+void GLTrace_glTextureStorage1DEXT(GLuint texture, GLenum target, GLsizei levels, GLenum internalformat, GLsizei width);
+void GLTrace_glTextureStorage2DEXT(GLuint texture, GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height);
+void GLTrace_glTextureStorage3DEXT(GLuint texture, GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth);
void GLTrace_glRenderbufferStorageMultisampleIMG(GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height);
void GLTrace_glFramebufferTexture2DMultisampleIMG(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level, GLsizei samples);
+void GLTrace_glCoverageMaskNV(GLboolean mask);
+void GLTrace_glCoverageOperationNV(GLenum operation);
+void GLTrace_glDrawBuffersNV(GLsizei n, const GLenum *bufs);
void GLTrace_glDeleteFencesNV(GLsizei n, const GLuint *fences);
void GLTrace_glGenFencesNV(GLsizei n, GLuint *fences);
GLboolean GLTrace_glIsFenceNV(GLuint fence);
@@ -206,8 +267,8 @@
void GLTrace_glGetFenceivNV(GLuint fence, GLenum pname, GLint *params);
void GLTrace_glFinishFenceNV(GLuint fence);
void GLTrace_glSetFenceNV(GLuint fence, GLenum condition);
-void GLTrace_glCoverageMaskNV(GLboolean mask);
-void GLTrace_glCoverageOperationNV(GLenum operation);
+void GLTrace_glReadBufferNV(GLenum mode);
+void GLTrace_glAlphaFuncQCOM(GLenum func, GLclampf ref);
void GLTrace_glGetDriverControlsQCOM(GLint *num, GLsizei size, GLuint *driverControls);
void GLTrace_glGetDriverControlStringQCOM(GLuint driverControl, GLsizei bufSize, GLsizei *length, GLchar *driverControlString);
void GLTrace_glEnableDriverControlQCOM(GLuint driverControl);
diff --git a/opengl/libs/GLES_trace/src/gltrace_eglapi.cpp b/opengl/libs/GLES_trace/src/gltrace_eglapi.cpp
index c237d75..c442153 100644
--- a/opengl/libs/GLES_trace/src/gltrace_eglapi.cpp
+++ b/opengl/libs/GLES_trace/src/gltrace_eglapi.cpp
@@ -77,12 +77,10 @@
}
void GLTrace_start() {
- char value[PROPERTY_VALUE_MAX];
+ char udsName[PROPERTY_VALUE_MAX];
- property_get("debug.egl.debug_port", value, "5039");
- const unsigned short port = (unsigned short)atoi(value);
-
- int clientSocket = gltrace::acceptClientConnection(port);
+ property_get("debug.egl.debug_portname", udsName, "gltrace");
+ int clientSocket = gltrace::acceptClientConnection(udsName);
if (clientSocket < 0) {
ALOGE("Error creating GLTrace server socket. Quitting application.");
exit(-1);
diff --git a/opengl/libs/GLES_trace/src/gltrace_fixup.cpp b/opengl/libs/GLES_trace/src/gltrace_fixup.cpp
index daba3ff..871b5dc 100644
--- a/opengl/libs/GLES_trace/src/gltrace_fixup.cpp
+++ b/opengl/libs/GLES_trace/src/gltrace_fixup.cpp
@@ -358,6 +358,14 @@
fixup_addFBContents(context, glmsg, CURRENTLY_BOUND_FB);
}
break;
+ case GLMessage::glPushGroupMarkerEXT:
+ /* void PushGroupMarkerEXT(sizei length, const char *marker); */
+ fixup_CStringPtr(1, glmsg);
+ break;
+ case GLMessage::glInsertEventMarkerEXT:
+ /* void InsertEventMarkerEXT(sizei length, const char *marker); */
+ fixup_CStringPtr(1, glmsg);
+ break;
default:
break;
}
diff --git a/opengl/libs/GLES_trace/src/gltrace_transport.cpp b/opengl/libs/GLES_trace/src/gltrace_transport.cpp
index ce3fae5..5251b12 100644
--- a/opengl/libs/GLES_trace/src/gltrace_transport.cpp
+++ b/opengl/libs/GLES_trace/src/gltrace_transport.cpp
@@ -17,9 +17,10 @@
#include <stdlib.h>
#include <unistd.h>
+#include <unistd.h>
#include <sys/socket.h>
+#include <sys/un.h>
#include <netinet/in.h>
-#include <arpa/inet.h>
#include <cutils/log.h>
@@ -28,22 +29,24 @@
namespace android {
namespace gltrace {
-int acceptClientConnection(int serverPort) {
- int serverSocket = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
+int acceptClientConnection(char *sockname) {
+ int serverSocket = socket(AF_LOCAL, SOCK_STREAM, 0);
if (serverSocket < 0) {
ALOGE("Error (%d) while creating socket. Check if app has network permissions.",
serverSocket);
return -1;
}
- struct sockaddr_in server, client;
+ struct sockaddr_un server, client;
- server.sin_family = AF_INET;
- server.sin_addr.s_addr = htonl(INADDR_ANY);
- server.sin_port = htons(serverPort);
+ memset(&server, 0, sizeof server);
+ server.sun_family = AF_UNIX;
+ // the first byte of sun_path should be '\0' for abstract namespace
+ strcpy(server.sun_path + 1, sockname);
- socklen_t sockaddr_len = sizeof(sockaddr_in);
- if (bind(serverSocket, (struct sockaddr *) &server, sizeof(server)) < 0) {
+ // note that sockaddr_len should be set to the exact size of the buffer that is used.
+ socklen_t sockaddr_len = sizeof(server.sun_family) + strlen(sockname) + 1;
+ if (bind(serverSocket, (struct sockaddr *) &server, sockaddr_len) < 0) {
close(serverSocket);
ALOGE("Failed to bind the server socket");
return -1;
@@ -55,7 +58,7 @@
return -1;
}
- ALOGD("gltrace::waitForClientConnection: server listening @ port %d", serverPort);
+ ALOGD("gltrace::waitForClientConnection: server listening @ path %s", sockname);
int clientSocket = accept(serverSocket, (struct sockaddr *)&client, &sockaddr_len);
if (clientSocket < 0) {
@@ -64,7 +67,7 @@
return -1;
}
- ALOGD("gltrace::waitForClientConnection: client connected: %s", inet_ntoa(client.sin_addr));
+ ALOGD("gltrace::waitForClientConnection: client connected.");
// do not accept any more incoming connections
close(serverSocket);
diff --git a/opengl/libs/GLES_trace/src/gltrace_transport.h b/opengl/libs/GLES_trace/src/gltrace_transport.h
index d31df7b..3665035 100644
--- a/opengl/libs/GLES_trace/src/gltrace_transport.h
+++ b/opengl/libs/GLES_trace/src/gltrace_transport.h
@@ -76,10 +76,11 @@
};
/**
- * Utility method: start a server at @serverPort, and wait for a client
- * connection. Returns the connected client socket on success, or -1 on failure.
+ * Utility method: start a server listening at @sockName (unix domain socket,
+ * abstract namespace path), and wait for a client connection.
+ * Returns the connected client socket on success, or -1 on failure.
*/
-int acceptClientConnection(int serverPort);
+int acceptClientConnection(char *sockName);
};
};
diff --git a/opengl/libs/GLES_trace/tools/genapi.py b/opengl/libs/GLES_trace/tools/genapi.py
index 9b7a1cf..557e407 100755
--- a/opengl/libs/GLES_trace/tools/genapi.py
+++ b/opengl/libs/GLES_trace/tools/genapi.py
@@ -26,11 +26,11 @@
# module. The only reason to use pyratemp is that it is extremly
# simple to install:
# $ wget http://www.simple-is-better.org/template/pyratemp-current/pyratemp.py
-# Put the file in the GLES2_trace/tools folder, or update PYTHONPATH
+# Put the file in the GLES_trace/tools folder, or update PYTHONPATH
# to point to wherever it was downloaded.
#
# USAGE
-# $ cd GLES2_trace - run the program from GLES2_trace folder
+# $ cd GLES_trace - run the program from GLES2_trace folder
# $ ./tools/genapi.py - generates a .cpp and .h file
# $ mv *.cpp *.h src/ - move the generated files into the src folder
diff --git a/opengl/libs/GLES_trace/tools/testgenapi.py b/opengl/libs/GLES_trace/tools/testgenapi.py
index 58a12a8..fe14954 100644
--- a/opengl/libs/GLES_trace/tools/testgenapi.py
+++ b/opengl/libs/GLES_trace/tools/testgenapi.py
@@ -15,7 +15,7 @@
# limitations under the License.
#
# USAGE
-# $ cd GLES2_trace/tools
+# $ cd GLES_trace/tools
# $ python testgenapi.py
import unittest
@@ -45,9 +45,9 @@
glext_apis = getApis('../../GLES_CM/glext_api.in', 'GL1Ext')
self.assertEqual(len(gl2_apis), 142)
- self.assertEqual(len(gl2ext_apis), 60)
+ self.assertEqual(len(gl2ext_apis), 121)
self.assertEqual(len(gl_apis), 145)
- self.assertEqual(len(glext_apis), 126)
+ self.assertEqual(len(glext_apis), 140)
def test_parseArgs(self):
args = parseArgs("void")
diff --git a/opengl/libs/egl_impl.h b/opengl/libs/egl_impl.h
index a809316..8ff51ec 100644
--- a/opengl/libs/egl_impl.h
+++ b/opengl/libs/egl_impl.h
@@ -29,6 +29,7 @@
namespace android {
// ----------------------------------------------------------------------------
+EGLAPI const GLubyte * egl_get_string_for_current_context(GLenum name);
EGLAPI EGLImageKHR egl_get_image_for_current_context(EGLImageKHR image);
// ----------------------------------------------------------------------------
diff --git a/opengl/libs/entries.in b/opengl/libs/entries.in
index 61acb5f..6316d78 100644
--- a/opengl/libs/entries.in
+++ b/opengl/libs/entries.in
@@ -1,13 +1,17 @@
+GL_ENTRY(void, glActiveShaderProgramEXT, GLuint pipeline, GLuint program)
GL_ENTRY(void, glActiveTexture, GLenum texture)
GL_ENTRY(void, glAlphaFunc, GLenum func, GLclampf ref)
+GL_ENTRY(void, glAlphaFuncQCOM, GLenum func, GLclampf ref)
GL_ENTRY(void, glAlphaFuncx, GLenum func, GLclampx ref)
GL_ENTRY(void, glAlphaFuncxOES, GLenum func, GLclampx ref)
GL_ENTRY(void, glAttachShader, GLuint program, GLuint shader)
GL_ENTRY(void, glBeginPerfMonitorAMD, GLuint monitor)
+GL_ENTRY(void, glBeginQueryEXT, GLenum target, GLuint id)
GL_ENTRY(void, glBindAttribLocation, GLuint program, GLuint index, const GLchar* name)
GL_ENTRY(void, glBindBuffer, GLenum target, GLuint buffer)
GL_ENTRY(void, glBindFramebuffer, GLenum target, GLuint framebuffer)
GL_ENTRY(void, glBindFramebufferOES, GLenum target, GLuint framebuffer)
+GL_ENTRY(void, glBindProgramPipelineEXT, GLuint pipeline)
GL_ENTRY(void, glBindRenderbuffer, GLenum target, GLuint renderbuffer)
GL_ENTRY(void, glBindRenderbufferOES, GLenum target, GLuint renderbuffer)
GL_ENTRY(void, glBindTexture, GLenum target, GLuint texture)
@@ -20,6 +24,7 @@
GL_ENTRY(void, glBlendFunc, GLenum sfactor, GLenum dfactor)
GL_ENTRY(void, glBlendFuncSeparate, GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha)
GL_ENTRY(void, glBlendFuncSeparateOES, GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha)
+GL_ENTRY(void, glBlitFramebufferANGLE, GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter)
GL_ENTRY(void, glBufferData, GLenum target, GLsizeiptr size, const GLvoid *data, GLenum usage)
GL_ENTRY(void, glBufferSubData, GLenum target, GLintptr offset, GLsizeiptr size, const GLvoid *data)
GL_ENTRY(GLenum, glCheckFramebufferStatus, GLenum target)
@@ -58,6 +63,7 @@
GL_ENTRY(void, glCoverageOperationNV, GLenum operation)
GL_ENTRY(GLuint, glCreateProgram, void)
GL_ENTRY(GLuint, glCreateShader, GLenum type)
+GL_ENTRY(GLuint, glCreateShaderProgramvEXT, GLenum type, GLsizei count, const GLchar **strings)
GL_ENTRY(void, glCullFace, GLenum mode)
GL_ENTRY(void, glCurrentPaletteMatrixOES, GLuint matrixpaletteindex)
GL_ENTRY(void, glDeleteBuffers, GLsizei n, const GLuint *buffers)
@@ -66,6 +72,8 @@
GL_ENTRY(void, glDeleteFramebuffersOES, GLsizei n, const GLuint* framebuffers)
GL_ENTRY(void, glDeletePerfMonitorsAMD, GLsizei n, GLuint *monitors)
GL_ENTRY(void, glDeleteProgram, GLuint program)
+GL_ENTRY(void, glDeleteProgramPipelinesEXT, GLsizei n, const GLuint *pipelines)
+GL_ENTRY(void, glDeleteQueriesEXT, GLsizei n, const GLuint *ids)
GL_ENTRY(void, glDeleteRenderbuffers, GLsizei n, const GLuint* renderbuffers)
GL_ENTRY(void, glDeleteRenderbuffersOES, GLsizei n, const GLuint* renderbuffers)
GL_ENTRY(void, glDeleteShader, GLuint shader)
@@ -84,6 +92,7 @@
GL_ENTRY(void, glDisableVertexAttribArray, GLuint index)
GL_ENTRY(void, glDiscardFramebufferEXT, GLenum target, GLsizei numAttachments, const GLenum *attachments)
GL_ENTRY(void, glDrawArrays, GLenum mode, GLint first, GLsizei count)
+GL_ENTRY(void, glDrawBuffersNV, GLsizei n, const GLenum *bufs)
GL_ENTRY(void, glDrawElements, GLenum mode, GLsizei count, GLenum type, const GLvoid *indices)
GL_ENTRY(void, glDrawTexfOES, GLfloat x, GLfloat y, GLfloat z, GLfloat width, GLfloat height)
GL_ENTRY(void, glDrawTexfvOES, const GLfloat *coords)
@@ -100,6 +109,7 @@
GL_ENTRY(void, glEnableDriverControlQCOM, GLuint driverControl)
GL_ENTRY(void, glEnableVertexAttribArray, GLuint index)
GL_ENTRY(void, glEndPerfMonitorAMD, GLuint monitor)
+GL_ENTRY(void, glEndQueryEXT, GLenum target)
GL_ENTRY(void, glEndTilingQCOM, GLbitfield preserveMask)
GL_ENTRY(void, glExtGetBufferPointervQCOM, GLenum target, GLvoid **params)
GL_ENTRY(void, glExtGetBuffersQCOM, GLuint *buffers, GLint maxBuffers, GLint *numBuffers)
@@ -125,6 +135,7 @@
GL_ENTRY(void, glFramebufferRenderbuffer, GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer)
GL_ENTRY(void, glFramebufferRenderbufferOES, GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer)
GL_ENTRY(void, glFramebufferTexture2D, GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level)
+GL_ENTRY(void, glFramebufferTexture2DMultisampleEXT, GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level, GLsizei samples)
GL_ENTRY(void, glFramebufferTexture2DMultisampleIMG, GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level, GLsizei samples)
GL_ENTRY(void, glFramebufferTexture2DOES, GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level)
GL_ENTRY(void, glFramebufferTexture3DOES, GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level, GLint zoffset)
@@ -138,6 +149,8 @@
GL_ENTRY(void, glGenFramebuffers, GLsizei n, GLuint* framebuffers)
GL_ENTRY(void, glGenFramebuffersOES, GLsizei n, GLuint* framebuffers)
GL_ENTRY(void, glGenPerfMonitorsAMD, GLsizei n, GLuint *monitors)
+GL_ENTRY(void, glGenProgramPipelinesEXT, GLsizei n, GLuint *pipelines)
+GL_ENTRY(void, glGenQueriesEXT, GLsizei n, GLuint *ids)
GL_ENTRY(void, glGenRenderbuffers, GLsizei n, GLuint* renderbuffers)
GL_ENTRY(void, glGenRenderbuffersOES, GLsizei n, GLuint* renderbuffers)
GL_ENTRY(void, glGenTextures, GLsizei n, GLuint *textures)
@@ -164,6 +177,7 @@
GL_ENTRY(void, glGetFloatv, GLenum pname, GLfloat *params)
GL_ENTRY(void, glGetFramebufferAttachmentParameteriv, GLenum target, GLenum attachment, GLenum pname, GLint* params)
GL_ENTRY(void, glGetFramebufferAttachmentParameterivOES, GLenum target, GLenum attachment, GLenum pname, GLint* params)
+GL_ENTRY(GLenum, glGetGraphicsResetStatusEXT, void)
GL_ENTRY(void, glGetIntegerv, GLenum pname, GLint *params)
GL_ENTRY(void, glGetLightfv, GLenum light, GLenum pname, GLfloat *params)
GL_ENTRY(void, glGetLightxv, GLenum light, GLenum pname, GLfixed *params)
@@ -171,6 +185,7 @@
GL_ENTRY(void, glGetMaterialfv, GLenum face, GLenum pname, GLfloat *params)
GL_ENTRY(void, glGetMaterialxv, GLenum face, GLenum pname, GLfixed *params)
GL_ENTRY(void, glGetMaterialxvOES, GLenum face, GLenum pname, GLfixed *params)
+GL_ENTRY(void, glGetObjectLabelEXT, GLenum type, GLuint object, GLsizei bufSize, GLsizei *length, GLchar *label)
GL_ENTRY(void, glGetPerfMonitorCounterDataAMD, GLuint monitor, GLenum pname, GLsizei dataSize, GLuint *data, GLint *bytesWritten)
GL_ENTRY(void, glGetPerfMonitorCounterInfoAMD, GLuint group, GLuint counter, GLenum pname, GLvoid *data)
GL_ENTRY(void, glGetPerfMonitorCounterStringAMD, GLuint group, GLuint counter, GLsizei bufSize, GLsizei *length, GLchar *counterString)
@@ -180,7 +195,11 @@
GL_ENTRY(void, glGetPointerv, GLenum pname, GLvoid **params)
GL_ENTRY(void, glGetProgramBinaryOES, GLuint program, GLsizei bufSize, GLsizei *length, GLenum *binaryFormat, GLvoid *binary)
GL_ENTRY(void, glGetProgramInfoLog, GLuint program, GLsizei bufsize, GLsizei* length, GLchar* infolog)
+GL_ENTRY(void, glGetProgramPipelineInfoLogEXT, GLuint pipeline, GLsizei bufSize, GLsizei *length, GLchar *infoLog)
+GL_ENTRY(void, glGetProgramPipelineivEXT, GLuint pipeline, GLenum pname, GLint *params)
GL_ENTRY(void, glGetProgramiv, GLuint program, GLenum pname, GLint* params)
+GL_ENTRY(void, glGetQueryObjectuivEXT, GLuint id, GLenum pname, GLuint *params)
+GL_ENTRY(void, glGetQueryivEXT, GLenum target, GLenum pname, GLint *params)
GL_ENTRY(void, glGetRenderbufferParameteriv, GLenum target, GLenum pname, GLint* params)
GL_ENTRY(void, glGetRenderbufferParameterivOES, GLenum target, GLenum pname, GLint* params)
GL_ENTRY(void, glGetShaderInfoLog, GLuint shader, GLsizei bufsize, GLsizei* length, GLchar* infolog)
@@ -205,18 +224,24 @@
GL_ENTRY(void, glGetVertexAttribPointerv, GLuint index, GLenum pname, GLvoid** pointer)
GL_ENTRY(void, glGetVertexAttribfv, GLuint index, GLenum pname, GLfloat* params)
GL_ENTRY(void, glGetVertexAttribiv, GLuint index, GLenum pname, GLint* params)
+GL_ENTRY(void, glGetnUniformfvEXT, GLuint program, GLint location, GLsizei bufSize, float *params)
+GL_ENTRY(void, glGetnUniformivEXT, GLuint program, GLint location, GLsizei bufSize, GLint *params)
GL_ENTRY(void, glHint, GLenum target, GLenum mode)
+GL_ENTRY(void, glInsertEventMarkerEXT, GLsizei length, const GLchar *marker)
GL_ENTRY(GLboolean, glIsBuffer, GLuint buffer)
GL_ENTRY(GLboolean, glIsEnabled, GLenum cap)
GL_ENTRY(GLboolean, glIsFenceNV, GLuint fence)
GL_ENTRY(GLboolean, glIsFramebuffer, GLuint framebuffer)
GL_ENTRY(GLboolean, glIsFramebufferOES, GLuint framebuffer)
GL_ENTRY(GLboolean, glIsProgram, GLuint program)
+GL_ENTRY(GLboolean, glIsProgramPipelineEXT, GLuint pipeline)
+GL_ENTRY(GLboolean, glIsQueryEXT, GLuint id)
GL_ENTRY(GLboolean, glIsRenderbuffer, GLuint renderbuffer)
GL_ENTRY(GLboolean, glIsRenderbufferOES, GLuint renderbuffer)
GL_ENTRY(GLboolean, glIsShader, GLuint shader)
GL_ENTRY(GLboolean, glIsTexture, GLuint texture)
GL_ENTRY(GLboolean, glIsVertexArrayOES, GLuint array)
+GL_ENTRY(void, glLabelObjectEXT, GLenum type, GLuint object, GLsizei length, const GLchar *label)
GL_ENTRY(void, glLightModelf, GLenum pname, GLfloat param)
GL_ENTRY(void, glLightModelfv, GLenum pname, const GLfloat *params)
GL_ENTRY(void, glLightModelx, GLenum pname, GLfixed param)
@@ -278,15 +303,43 @@
GL_ENTRY(void, glPolygonOffset, GLfloat factor, GLfloat units)
GL_ENTRY(void, glPolygonOffsetx, GLfixed factor, GLfixed units)
GL_ENTRY(void, glPolygonOffsetxOES, GLfixed factor, GLfixed units)
+GL_ENTRY(void, glPopGroupMarkerEXT, void)
GL_ENTRY(void, glPopMatrix, void)
GL_ENTRY(void, glProgramBinaryOES, GLuint program, GLenum binaryFormat, const GLvoid *binary, GLint length)
+GL_ENTRY(void, glProgramParameteriEXT, GLuint program, GLenum pname, GLint value)
+GL_ENTRY(void, glProgramUniform1fEXT, GLuint program, GLint location, GLfloat x)
+GL_ENTRY(void, glProgramUniform1fvEXT, GLuint program, GLint location, GLsizei count, const GLfloat *value)
+GL_ENTRY(void, glProgramUniform1iEXT, GLuint program, GLint location, GLint x)
+GL_ENTRY(void, glProgramUniform1ivEXT, GLuint program, GLint location, GLsizei count, const GLint *value)
+GL_ENTRY(void, glProgramUniform2fEXT, GLuint program, GLint location, GLfloat x, GLfloat y)
+GL_ENTRY(void, glProgramUniform2fvEXT, GLuint program, GLint location, GLsizei count, const GLfloat *value)
+GL_ENTRY(void, glProgramUniform2iEXT, GLuint program, GLint location, GLint x, GLint y)
+GL_ENTRY(void, glProgramUniform2ivEXT, GLuint program, GLint location, GLsizei count, const GLint *value)
+GL_ENTRY(void, glProgramUniform3fEXT, GLuint program, GLint location, GLfloat x, GLfloat y, GLfloat z)
+GL_ENTRY(void, glProgramUniform3fvEXT, GLuint program, GLint location, GLsizei count, const GLfloat *value)
+GL_ENTRY(void, glProgramUniform3iEXT, GLuint program, GLint location, GLint x, GLint y, GLint z)
+GL_ENTRY(void, glProgramUniform3ivEXT, GLuint program, GLint location, GLsizei count, const GLint *value)
+GL_ENTRY(void, glProgramUniform4fEXT, GLuint program, GLint location, GLfloat x, GLfloat y, GLfloat z, GLfloat w)
+GL_ENTRY(void, glProgramUniform4fvEXT, GLuint program, GLint location, GLsizei count, const GLfloat *value)
+GL_ENTRY(void, glProgramUniform4iEXT, GLuint program, GLint location, GLint x, GLint y, GLint z, GLint w)
+GL_ENTRY(void, glProgramUniform4ivEXT, GLuint program, GLint location, GLsizei count, const GLint *value)
+GL_ENTRY(void, glProgramUniformMatrix2fvEXT, GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value)
+GL_ENTRY(void, glProgramUniformMatrix3fvEXT, GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value)
+GL_ENTRY(void, glProgramUniformMatrix4fvEXT, GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value)
+GL_ENTRY(void, glPushGroupMarkerEXT, GLsizei length, const GLchar *marker)
GL_ENTRY(void, glPushMatrix, void)
GL_ENTRY(GLbitfield, glQueryMatrixxOES, GLfixed mantissa[16], GLint exponent[16])
+GL_ENTRY(void, glReadBufferNV, GLenum mode)
GL_ENTRY(void, glReadPixels, GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLvoid *pixels)
+GL_ENTRY(void, glReadnPixelsEXT, GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLsizei bufSize, void *data)
GL_ENTRY(void, glReleaseShaderCompiler, void)
GL_ENTRY(void, glRenderbufferStorage, GLenum target, GLenum internalformat, GLsizei width, GLsizei height)
+GL_ENTRY(void, glRenderbufferStorageMultisampleANGLE, GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height)
+GL_ENTRY(void, glRenderbufferStorageMultisampleAPPLE, GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height)
+GL_ENTRY(void, glRenderbufferStorageMultisampleEXT, GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height)
GL_ENTRY(void, glRenderbufferStorageMultisampleIMG, GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height)
GL_ENTRY(void, glRenderbufferStorageOES, GLenum target, GLenum internalformat, GLsizei width, GLsizei height)
+GL_ENTRY(void, glResolveMultisampleFramebufferAPPLE, void)
GL_ENTRY(void, glRotatef, GLfloat angle, GLfloat x, GLfloat y, GLfloat z)
GL_ENTRY(void, glRotatex, GLfixed angle, GLfixed x, GLfixed y, GLfixed z)
GL_ENTRY(void, glRotatexOES, GLfixed angle, GLfixed x, GLfixed y, GLfixed z)
@@ -335,8 +388,14 @@
GL_ENTRY(void, glTexParameterxOES, GLenum target, GLenum pname, GLfixed param)
GL_ENTRY(void, glTexParameterxv, GLenum target, GLenum pname, const GLfixed *params)
GL_ENTRY(void, glTexParameterxvOES, GLenum target, GLenum pname, const GLfixed *params)
+GL_ENTRY(void, glTexStorage1DEXT, GLenum target, GLsizei levels, GLenum internalformat, GLsizei width)
+GL_ENTRY(void, glTexStorage2DEXT, GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height)
+GL_ENTRY(void, glTexStorage3DEXT, GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth)
GL_ENTRY(void, glTexSubImage2D, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *pixels)
GL_ENTRY(void, glTexSubImage3DOES, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const GLvoid* pixels)
+GL_ENTRY(void, glTextureStorage1DEXT, GLuint texture, GLenum target, GLsizei levels, GLenum internalformat, GLsizei width)
+GL_ENTRY(void, glTextureStorage2DEXT, GLuint texture, GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height)
+GL_ENTRY(void, glTextureStorage3DEXT, GLuint texture, GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth)
GL_ENTRY(void, glTranslatef, GLfloat x, GLfloat y, GLfloat z)
GL_ENTRY(void, glTranslatex, GLfixed x, GLfixed y, GLfixed z)
GL_ENTRY(void, glTranslatexOES, GLfixed x, GLfixed y, GLfixed z)
@@ -361,7 +420,9 @@
GL_ENTRY(void, glUniformMatrix4fv, GLint location, GLsizei count, GLboolean transpose, const GLfloat* value)
GL_ENTRY(GLboolean, glUnmapBufferOES, GLenum target)
GL_ENTRY(void, glUseProgram, GLuint program)
+GL_ENTRY(void, glUseProgramStagesEXT, GLuint pipeline, GLbitfield stages, GLuint program)
GL_ENTRY(void, glValidateProgram, GLuint program)
+GL_ENTRY(void, glValidateProgramPipelineEXT, GLuint pipeline)
GL_ENTRY(void, glVertexAttrib1f, GLuint indx, GLfloat x)
GL_ENTRY(void, glVertexAttrib1fv, GLuint indx, const GLfloat* values)
GL_ENTRY(void, glVertexAttrib2f, GLuint indx, GLfloat x, GLfloat y)
diff --git a/opengl/libs/enums.in b/opengl/libs/enums.in
index f9752c2..bfbc866 100644
--- a/opengl/libs/enums.in
+++ b/opengl/libs/enums.in
@@ -1,4 +1,6 @@
GL_ENUM(0x0000,GL_POINTS)
+GL_ENUM(0x00000001,GL_VERTEX_SHADER_BIT_EXT)
+GL_ENUM(0x00000002,GL_FRAGMENT_SHADER_BIT_EXT)
GL_ENUM(0x0001,GL_LINES)
GL_ENUM(0x0002,GL_LINE_LOOP)
GL_ENUM(0x0003,GL_LINE_STRIP)
@@ -92,6 +94,7 @@
GL_ENUM(0x0BE2,GL_BLEND)
GL_ENUM(0x0BF0,GL_LOGIC_OP_MODE)
GL_ENUM(0x0BF2,GL_COLOR_LOGIC_OP)
+GL_ENUM(0x0C02,GL_READ_BUFFER_NV)
GL_ENUM(0x0C10,GL_SCISSOR_BOX)
GL_ENUM(0x0C11,GL_SCISSOR_TEST)
GL_ENUM(0x0C22,GL_COLOR_CLEAR_VALUE)
@@ -100,6 +103,9 @@
GL_ENUM(0x0C51,GL_POINT_SMOOTH_HINT)
GL_ENUM(0x0C52,GL_LINE_SMOOTH_HINT)
GL_ENUM(0x0C54,GL_FOG_HINT)
+GL_ENUM(0x0CF2,GL_UNPACK_ROW_LENGTH)
+GL_ENUM(0x0CF3,GL_UNPACK_SKIP_ROWS)
+GL_ENUM(0x0CF4,GL_UNPACK_SKIP_PIXELS)
GL_ENUM(0x0CF5,GL_UNPACK_ALIGNMENT)
GL_ENUM(0x0D05,GL_PACK_ALIGNMENT)
GL_ENUM(0x0D1C,GL_ALPHA_SCALE)
@@ -166,6 +172,7 @@
GL_ENUM(0x1802,GL_STENCIL_EXT)
GL_ENUM(0x1901,GL_STENCIL_INDEX)
GL_ENUM(0x1902,GL_DEPTH_COMPONENT)
+GL_ENUM(0x1903,GL_RED_EXT)
GL_ENUM(0x1906,GL_ALPHA)
GL_ENUM(0x1907,GL_RGB)
GL_ENUM(0x1908,GL_RGBA)
@@ -230,10 +237,15 @@
GL_ENUM(0x8037,GL_POLYGON_OFFSET_FILL)
GL_ENUM(0x8038,GL_POLYGON_OFFSET_FACTOR)
GL_ENUM(0x803A,GL_RESCALE_NORMAL)
+GL_ENUM(0x803C,GL_ALPHA8_EXT)
+GL_ENUM(0x8040,GL_LUMINANCE8_EXT)
+GL_ENUM(0x8045,GL_LUMINANCE8_ALPHA8_EXT)
GL_ENUM(0x8051,GL_RGB8_OES)
+GL_ENUM(0x8052,GL_RGB10_EXT)
GL_ENUM(0x8056,GL_RGBA4_OES)
GL_ENUM(0x8057,GL_RGB5_A1_OES)
GL_ENUM(0x8058,GL_RGBA8_OES)
+GL_ENUM(0x8059,GL_RGB10_A2_EXT)
GL_ENUM(0x8069,GL_TEXTURE_BINDING_2D)
GL_ENUM(0x806A,GL_TEXTURE_BINDING_3D_OES)
GL_ENUM(0x806F,GL_TEXTURE_3D_OES)
@@ -276,11 +288,28 @@
GL_ENUM(0x8128,GL_POINT_FADE_THRESHOLD_SIZE)
GL_ENUM(0x8129,GL_POINT_DISTANCE_ATTENUATION)
GL_ENUM(0x812F,GL_CLAMP_TO_EDGE)
+GL_ENUM(0x813D,GL_TEXTURE_MAX_LEVEL_APPLE)
GL_ENUM(0x8191,GL_GENERATE_MIPMAP)
GL_ENUM(0x8192,GL_GENERATE_MIPMAP_HINT)
GL_ENUM(0x81A5,GL_DEPTH_COMPONENT16_OES)
GL_ENUM(0x81A6,GL_DEPTH_COMPONENT24_OES)
GL_ENUM(0x81A7,GL_DEPTH_COMPONENT32_OES)
+GL_ENUM(0x8210,GL_FRAMEBUFFER_ATTACHMENT_COLOR_ENCODING_EXT)
+GL_ENUM(0x8211,GL_FRAMEBUFFER_ATTACHMENT_COMPONENT_TYPE_EXT)
+GL_ENUM(0x8227,GL_RG_EXT)
+GL_ENUM(0x8229,GL_R8_EXT)
+GL_ENUM(0x822B,GL_RG8_EXT)
+GL_ENUM(0x822D,GL_R16F_EXT)
+GL_ENUM(0x822F,GL_RG16F_EXT)
+GL_ENUM(0x8252,GL_LOSE_CONTEXT_ON_RESET_EXT)
+GL_ENUM(0x8253,GL_GUILTY_CONTEXT_RESET_EXT)
+GL_ENUM(0x8254,GL_INNOCENT_CONTEXT_RESET_EXT)
+GL_ENUM(0x8255,GL_UNKNOWN_CONTEXT_RESET_EXT)
+GL_ENUM(0x8256,GL_RESET_NOTIFICATION_STRATEGY_EXT)
+GL_ENUM(0x8258,GL_PROGRAM_SEPARABLE_EXT)
+GL_ENUM(0x8259,GL_ACTIVE_PROGRAM_EXT)
+GL_ENUM(0x825A,GL_PROGRAM_PIPELINE_BINDING_EXT)
+GL_ENUM(0x8261,GL_NO_RESET_NOTIFICATION_EXT)
GL_ENUM(0x8363,GL_UNSIGNED_SHORT_5_6_5)
GL_ENUM(0x8365,GL_UNSIGNED_SHORT_4_4_4_4_REV_EXT)
GL_ENUM(0x8366,GL_UNSIGNED_SHORT_1_5_5_5_REV_EXT)
@@ -372,6 +401,8 @@
GL_ENUM(0x8599,GL_OPERAND1_ALPHA)
GL_ENUM(0x859A,GL_OPERAND2_ALPHA)
GL_ENUM(0x85B5,GL_VERTEX_ARRAY_BINDING_OES)
+GL_ENUM(0x85BA,GL_UNSIGNED_SHORT_8_8_APPLE)
+GL_ENUM(0x85BB,GL_UNSIGNED_SHORT_8_8_REV_APPLE)
GL_ENUM(0x8622,GL_VERTEX_ATTRIB_ARRAY_ENABLED)
GL_ENUM(0x8623,GL_VERTEX_ATTRIB_ARRAY_SIZE)
GL_ENUM(0x8624,GL_VERTEX_ATTRIB_ARRAY_STRIDE)
@@ -401,7 +432,34 @@
GL_ENUM(0x8801,GL_STENCIL_BACK_FAIL)
GL_ENUM(0x8802,GL_STENCIL_BACK_PASS_DEPTH_FAIL)
GL_ENUM(0x8803,GL_STENCIL_BACK_PASS_DEPTH_PASS)
+GL_ENUM(0x8814,GL_RGBA32F_EXT)
+GL_ENUM(0x8815,GL_RGB32F_EXT)
+GL_ENUM(0x8816,GL_ALPHA32F_EXT)
+GL_ENUM(0x8818,GL_LUMINANCE32F_EXT)
+GL_ENUM(0x8819,GL_LUMINANCE_ALPHA32F_EXT)
+GL_ENUM(0x881A,GL_RGBA16F_EXT)
+GL_ENUM(0x881B,GL_RGB16F_EXT)
+GL_ENUM(0x881C,GL_ALPHA16F_EXT)
+GL_ENUM(0x881E,GL_LUMINANCE16F_EXT)
+GL_ENUM(0x881F,GL_LUMINANCE_ALPHA16F_EXT)
GL_ENUM(0x8823,GL_WRITEONLY_RENDERING_QCOM)
+GL_ENUM(0x8824,GL_MAX_DRAW_BUFFERS_NV)
+GL_ENUM(0x8825,GL_DRAW_BUFFER0_NV)
+GL_ENUM(0x8826,GL_DRAW_BUFFER1_NV)
+GL_ENUM(0x8827,GL_DRAW_BUFFER2_NV)
+GL_ENUM(0x8828,GL_DRAW_BUFFER3_NV)
+GL_ENUM(0x8829,GL_DRAW_BUFFER4_NV)
+GL_ENUM(0x882A,GL_DRAW_BUFFER5_NV)
+GL_ENUM(0x882B,GL_DRAW_BUFFER6_NV)
+GL_ENUM(0x882C,GL_DRAW_BUFFER7_NV)
+GL_ENUM(0x882D,GL_DRAW_BUFFER8_NV)
+GL_ENUM(0x882E,GL_DRAW_BUFFER9_NV)
+GL_ENUM(0x882F,GL_DRAW_BUFFER10_NV)
+GL_ENUM(0x8830,GL_DRAW_BUFFER11_NV)
+GL_ENUM(0x8831,GL_DRAW_BUFFER12_NV)
+GL_ENUM(0x8832,GL_DRAW_BUFFER13_NV)
+GL_ENUM(0x8833,GL_DRAW_BUFFER14_NV)
+GL_ENUM(0x8834,GL_DRAW_BUFFER15_NV)
GL_ENUM(0x883D,GL_BLEND_EQUATION_ALPHA_OES)
GL_ENUM(0x8840,GL_MATRIX_PALETTE_OES)
GL_ENUM(0x8842,GL_MAX_PALETTE_MATRICES_OES)
@@ -411,8 +469,14 @@
GL_ENUM(0x8847,GL_MATRIX_INDEX_ARRAY_TYPE_OES)
GL_ENUM(0x8848,GL_MATRIX_INDEX_ARRAY_STRIDE_OES)
GL_ENUM(0x8849,GL_MATRIX_INDEX_ARRAY_POINTER_OES)
+GL_ENUM(0x884C,GL_TEXTURE_COMPARE_MODE_EXT)
+GL_ENUM(0x884D,GL_TEXTURE_COMPARE_FUNC_EXT)
+GL_ENUM(0x884E,GL_COMPARE_REF_TO_TEXTURE_EXT)
GL_ENUM(0x8861,GL_POINT_SPRITE_OES)
GL_ENUM(0x8862,GL_COORD_REPLACE_OES)
+GL_ENUM(0x8865,GL_CURRENT_QUERY_EXT)
+GL_ENUM(0x8866,GL_QUERY_RESULT_EXT)
+GL_ENUM(0x8867,GL_QUERY_RESULT_AVAILABLE_EXT)
GL_ENUM(0x8869,GL_MAX_VERTEX_ATTRIBS)
GL_ENUM(0x886A,GL_VERTEX_ATTRIB_ARRAY_NORMALIZED)
GL_ENUM(0x8872,GL_MAX_TEXTURE_IMAGE_UNITS)
@@ -440,8 +504,12 @@
GL_ENUM(0x898D,GL_MODELVIEW_MATRIX_FLOAT_AS_INT_BITS_OES)
GL_ENUM(0x898E,GL_PROJECTION_MATRIX_FLOAT_AS_INT_BITS_OES)
GL_ENUM(0x898F,GL_TEXTURE_MATRIX_FLOAT_AS_INT_BITS_OES)
+GL_ENUM(0x8A1F,GL_RGB_422_APPLE)
+GL_ENUM(0x8A4F,GL_PROGRAM_PIPELINE_OBJECT_EXT)
GL_ENUM(0x8B30,GL_FRAGMENT_SHADER)
GL_ENUM(0x8B31,GL_VERTEX_SHADER)
+GL_ENUM(0x8B40,GL_PROGRAM_OBJECT_EXT)
+GL_ENUM(0x8B48,GL_SHADER_OBJECT_EXT)
GL_ENUM(0x8B4C,GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS)
GL_ENUM(0x8B4D,GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS)
GL_ENUM(0x8B4F,GL_SHADER_TYPE)
@@ -461,6 +529,7 @@
GL_ENUM(0x8B5E,GL_SAMPLER_2D)
GL_ENUM(0x8B5F,GL_SAMPLER_3D_OES)
GL_ENUM(0x8B60,GL_SAMPLER_CUBE)
+GL_ENUM(0x8B62,GL_SAMPLER_2D_SHADOW_EXT)
GL_ENUM(0x8B80,GL_DELETE_STATUS)
GL_ENUM(0x8B81,GL_COMPILE_STATUS)
GL_ENUM(0x8B82,GL_LINK_STATUS)
@@ -520,6 +589,11 @@
GL_ENUM(0x8C08,GL_FRAGMENT_ALPHA_MODULATE_IMG)
GL_ENUM(0x8C09,GL_ADD_BLEND_IMG)
GL_ENUM(0x8C0A,GL_SGX_BINARY_IMG)
+GL_ENUM(0x8C17,GL_UNSIGNED_NORMALIZED_EXT)
+GL_ENUM(0x8C2F,GL_ANY_SAMPLES_PASSED_EXT)
+GL_ENUM(0x8C40,GL_SRGB_EXT)
+GL_ENUM(0x8C42,GL_SRGB_ALPHA_EXT)
+GL_ENUM(0x8C43,GL_SRGB8_ALPHA8_EXT)
GL_ENUM(0x8C92,GL_ATC_RGB_AMD)
GL_ENUM(0x8C93,GL_ATC_RGBA_EXPLICIT_ALPHA_AMD)
GL_ENUM(0x8CA3,GL_STENCIL_BACK_REF)
@@ -527,6 +601,10 @@
GL_ENUM(0x8CA5,GL_STENCIL_BACK_WRITEMASK)
GL_ENUM(0x8CA6,GL_FRAMEBUFFER_BINDING_OES)
GL_ENUM(0x8CA7,GL_RENDERBUFFER_BINDING_OES)
+GL_ENUM(0x8CA8,GL_READ_FRAMEBUFFER_APPLE)
+GL_ENUM(0x8CA9,GL_DRAW_FRAMEBUFFER_APPLE)
+GL_ENUM(0x8CAA,GL_READ_FRAMEBUFFER_BINDING_APPLE)
+GL_ENUM(0x8CAB,GL_RENDERBUFFER_SAMPLES_APPLE)
GL_ENUM(0x8CD0,GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE_OES)
GL_ENUM(0x8CD1,GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME_OES)
GL_ENUM(0x8CD2,GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL_OES)
@@ -538,7 +616,23 @@
GL_ENUM(0x8CD9,GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS_OES)
GL_ENUM(0x8CDA,GL_FRAMEBUFFER_INCOMPLETE_FORMATS_OES)
GL_ENUM(0x8CDD,GL_FRAMEBUFFER_UNSUPPORTED_OES)
+GL_ENUM(0x8CDF,GL_MAX_COLOR_ATTACHMENTS_NV)
GL_ENUM(0x8CE0,GL_COLOR_ATTACHMENT0_OES)
+GL_ENUM(0x8CE1,GL_COLOR_ATTACHMENT1_NV)
+GL_ENUM(0x8CE2,GL_COLOR_ATTACHMENT2_NV)
+GL_ENUM(0x8CE3,GL_COLOR_ATTACHMENT3_NV)
+GL_ENUM(0x8CE4,GL_COLOR_ATTACHMENT4_NV)
+GL_ENUM(0x8CE5,GL_COLOR_ATTACHMENT5_NV)
+GL_ENUM(0x8CE6,GL_COLOR_ATTACHMENT6_NV)
+GL_ENUM(0x8CE7,GL_COLOR_ATTACHMENT7_NV)
+GL_ENUM(0x8CE8,GL_COLOR_ATTACHMENT8_NV)
+GL_ENUM(0x8CE9,GL_COLOR_ATTACHMENT9_NV)
+GL_ENUM(0x8CEA,GL_COLOR_ATTACHMENT10_NV)
+GL_ENUM(0x8CEB,GL_COLOR_ATTACHMENT11_NV)
+GL_ENUM(0x8CEC,GL_COLOR_ATTACHMENT12_NV)
+GL_ENUM(0x8CED,GL_COLOR_ATTACHMENT13_NV)
+GL_ENUM(0x8CEE,GL_COLOR_ATTACHMENT14_NV)
+GL_ENUM(0x8CEF,GL_COLOR_ATTACHMENT15_NV)
GL_ENUM(0x8D00,GL_DEPTH_ATTACHMENT_OES)
GL_ENUM(0x8D20,GL_STENCIL_ATTACHMENT_OES)
GL_ENUM(0x8D40,GL_FRAMEBUFFER_OES)
@@ -555,6 +649,8 @@
GL_ENUM(0x8D53,GL_RENDERBUFFER_ALPHA_SIZE_OES)
GL_ENUM(0x8D54,GL_RENDERBUFFER_DEPTH_SIZE_OES)
GL_ENUM(0x8D55,GL_RENDERBUFFER_STENCIL_SIZE_OES)
+GL_ENUM(0x8D56,GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_APPLE)
+GL_ENUM(0x8D57,GL_MAX_SAMPLES_APPLE)
GL_ENUM(0x8D60,GL_TEXTURE_GEN_STR_OES)
GL_ENUM(0x8D61,GL_HALF_FLOAT_OES)
GL_ENUM(0x8D62,GL_RGB565_OES)
@@ -563,6 +659,8 @@
GL_ENUM(0x8D66,GL_SAMPLER_EXTERNAL_OES)
GL_ENUM(0x8D67,GL_TEXTURE_BINDING_EXTERNAL_OES)
GL_ENUM(0x8D68,GL_REQUIRED_TEXTURE_IMAGE_UNITS_OES)
+GL_ENUM(0x8D6A,GL_ANY_SAMPLES_PASSED_CONSERVATIVE_EXT)
+GL_ENUM(0x8D6C,GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_SAMPLES_EXT)
GL_ENUM(0x8DF0,GL_LOW_FLOAT)
GL_ENUM(0x8DF1,GL_MEDIUM_FLOAT)
GL_ENUM(0x8DF2,GL_HIGH_FLOAT)
@@ -586,9 +684,19 @@
GL_ENUM(0x8ED5,GL_COVERAGE_ALL_FRAGMENTS_NV)
GL_ENUM(0x8ED6,GL_COVERAGE_EDGE_FRAGMENTS_NV)
GL_ENUM(0x8ED7,GL_COVERAGE_AUTOMATIC_NV)
+GL_ENUM(0x8F60,GL_MALI_SHADER_BINARY_ARM)
GL_ENUM(0x8FA0,GL_PERFMON_GLOBAL_MODE_QCOM)
+GL_ENUM(0x8FC4,GL_SHADER_BINARY_VIV)
+GL_ENUM(0x90F3,GL_CONTEXT_ROBUST_ACCESS_EXT)
+GL_ENUM(0x912F,GL_TEXTURE_IMMUTABLE_FORMAT_EXT)
GL_ENUM(0x9130,GL_SGX_PROGRAM_BINARY_IMG)
-GL_ENUM(0x9133,GL_RENDERBUFFER_SAMPLES_IMG)
-GL_ENUM(0x9134,GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_IMG)
-GL_ENUM(0x9135,GL_MAX_SAMPLES_IMG)
+GL_ENUM(0x9133,GL_RENDERBUFFER_SAMPLES_EXT)
+GL_ENUM(0x9134,GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_EXT)
+GL_ENUM(0x9135,GL_MAX_SAMPLES_EXT)
GL_ENUM(0x9136,GL_TEXTURE_SAMPLES_IMG)
+GL_ENUM(0x9151,GL_BUFFER_OBJECT_EXT)
+GL_ENUM(0x9153,GL_QUERY_OBJECT_EXT)
+GL_ENUM(0x9154,GL_VERTEX_ARRAY_OBJECT_EXT)
+GL_ENUM(0x9250,GL_SHADER_BINARY_DMP)
+GL_ENUM(0x93A1,GL_BGRA8_EXT)
+GL_ENUM(0xFFFFFFFF,GL_ALL_SHADER_BITS_EXT)
diff --git a/opengl/libs/hooks.h b/opengl/libs/hooks.h
index 7ac88cd..8b1b389 100644
--- a/opengl/libs/hooks.h
+++ b/opengl/libs/hooks.h
@@ -37,7 +37,12 @@
#endif
#undef NELEM
#define NELEM(x) (sizeof(x)/sizeof(*(x)))
-#define MAX_NUMBER_OF_GL_EXTENSIONS 64
+
+// maximum number of GL extensions that can be used simultaneously in
+// a given process. this limitation exists because we need to have
+// a static function for each extension and currently these static functions
+// are generated at compile time.
+#define MAX_NUMBER_OF_GL_EXTENSIONS 256
#if defined(HAVE_ANDROID_OS) && !USE_SLOW_BINDING && __OPTIMIZE__
diff --git a/opengl/libs/tools/glapigen b/opengl/libs/tools/glapigen
index bd8dda3..9be40cf 100755
--- a/opengl/libs/tools/glapigen
+++ b/opengl/libs/tools/glapigen
@@ -43,6 +43,9 @@
if ($name eq "glEGLImageTargetRenderbufferStorageOES") {
$prefix = "__";
}
+ if ($name eq "glGetString") {
+ $prefix = "__";
+ }
printf("%s API_ENTRY(%s%s)(%s)", $type, $prefix, $name, $args);
diff --git a/opengl/libs/trace.in b/opengl/libs/trace.in
index 3d492af..a5c5c84 100644
--- a/opengl/libs/trace.in
+++ b/opengl/libs/trace.in
@@ -1,13 +1,17 @@
+TRACE_GL_VOID(glActiveShaderProgramEXT, (GLuint pipeline, GLuint program), (pipeline, program), 2, "GLuint", pipeline, "GLuint", program)
TRACE_GL_VOID(glActiveTexture, (GLenum texture), (texture), 1, "GLenum", texture)
TRACE_GL_VOID(glAlphaFunc, (GLenum func, GLclampf ref), (func, ref), 2, "GLenum", func, "GLclampf", ref)
+TRACE_GL_VOID(glAlphaFuncQCOM, (GLenum func, GLclampf ref), (func, ref), 2, "GLenum", func, "GLclampf", ref)
TRACE_GL_VOID(glAlphaFuncx, (GLenum func, GLclampx ref), (func, ref), 2, "GLenum", func, "GLclampx", ref)
TRACE_GL_VOID(glAlphaFuncxOES, (GLenum func, GLclampx ref), (func, ref), 2, "GLenum", func, "GLclampx", ref)
TRACE_GL_VOID(glAttachShader, (GLuint program, GLuint shader), (program, shader), 2, "GLuint", program, "GLuint", shader)
TRACE_GL_VOID(glBeginPerfMonitorAMD, (GLuint monitor), (monitor), 1, "GLuint", monitor)
+TRACE_GL_VOID(glBeginQueryEXT, (GLenum target, GLuint id), (target, id), 2, "GLenum", target, "GLuint", id)
TRACE_GL_VOID(glBindAttribLocation, (GLuint program, GLuint index, const GLchar* name), (program, index, name), 3, "GLuint", program, "GLuint", index, "const GLchar*", name)
TRACE_GL_VOID(glBindBuffer, (GLenum target, GLuint buffer), (target, buffer), 2, "GLenum", target, "GLuint", buffer)
TRACE_GL_VOID(glBindFramebuffer, (GLenum target, GLuint framebuffer), (target, framebuffer), 2, "GLenum", target, "GLuint", framebuffer)
TRACE_GL_VOID(glBindFramebufferOES, (GLenum target, GLuint framebuffer), (target, framebuffer), 2, "GLenum", target, "GLuint", framebuffer)
+TRACE_GL_VOID(glBindProgramPipelineEXT, (GLuint pipeline), (pipeline), 1, "GLuint", pipeline)
TRACE_GL_VOID(glBindRenderbuffer, (GLenum target, GLuint renderbuffer), (target, renderbuffer), 2, "GLenum", target, "GLuint", renderbuffer)
TRACE_GL_VOID(glBindRenderbufferOES, (GLenum target, GLuint renderbuffer), (target, renderbuffer), 2, "GLenum", target, "GLuint", renderbuffer)
TRACE_GL_VOID(glBindTexture, (GLenum target, GLuint texture), (target, texture), 2, "GLenum", target, "GLuint", texture)
@@ -20,6 +24,7 @@
TRACE_GL_VOID(glBlendFunc, (GLenum sfactor, GLenum dfactor), (sfactor, dfactor), 2, "GLenum", sfactor, "GLenum", dfactor)
TRACE_GL_VOID(glBlendFuncSeparate, (GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha), (srcRGB, dstRGB, srcAlpha, dstAlpha), 4, "GLenum", srcRGB, "GLenum", dstRGB, "GLenum", srcAlpha, "GLenum", dstAlpha)
TRACE_GL_VOID(glBlendFuncSeparateOES, (GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha), (srcRGB, dstRGB, srcAlpha, dstAlpha), 4, "GLenum", srcRGB, "GLenum", dstRGB, "GLenum", srcAlpha, "GLenum", dstAlpha)
+TRACE_GL_VOID(glBlitFramebufferANGLE, (GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter), (srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1, mask, filter), 10, "GLint", srcX0, "GLint", srcY0, "GLint", srcX1, "GLint", srcY1, "GLint", dstX0, "GLint", dstY0, "GLint", dstX1, "GLint", dstY1, "GLbitfield", mask, "GLenum", filter)
TRACE_GL_VOID(glBufferData, (GLenum target, GLsizeiptr size, const GLvoid *data, GLenum usage), (target, size, data, usage), 4, "GLenum", target, "GLsizeiptr", size, "const GLvoid *", data, "GLenum", usage)
TRACE_GL_VOID(glBufferSubData, (GLenum target, GLintptr offset, GLsizeiptr size, const GLvoid *data), (target, offset, size, data), 4, "GLenum", target, "GLintptr", offset, "GLsizeiptr", size, "const GLvoid *", data)
TRACE_GL(GLenum, glCheckFramebufferStatus, (GLenum target), (target), 1, "GLenum", target)
@@ -58,6 +63,7 @@
TRACE_GL_VOID(glCoverageOperationNV, (GLenum operation), (operation), 1, "GLenum", operation)
TRACE_GL(GLuint, glCreateProgram, (void), (), 0)
TRACE_GL(GLuint, glCreateShader, (GLenum type), (type), 1, "GLenum", type)
+TRACE_GL(GLuint, glCreateShaderProgramvEXT, (GLenum type, GLsizei count, const GLchar **strings), (type, count, strings), 3, "GLenum", type, "GLsizei", count, "const GLchar **", strings)
TRACE_GL_VOID(glCullFace, (GLenum mode), (mode), 1, "GLenum", mode)
TRACE_GL_VOID(glCurrentPaletteMatrixOES, (GLuint matrixpaletteindex), (matrixpaletteindex), 1, "GLuint", matrixpaletteindex)
TRACE_GL_VOID(glDeleteBuffers, (GLsizei n, const GLuint *buffers), (n, buffers), 2, "GLsizei", n, "const GLuint *", buffers)
@@ -66,6 +72,8 @@
TRACE_GL_VOID(glDeleteFramebuffersOES, (GLsizei n, const GLuint* framebuffers), (n, framebuffers), 2, "GLsizei", n, "const GLuint*", framebuffers)
TRACE_GL_VOID(glDeletePerfMonitorsAMD, (GLsizei n, GLuint *monitors), (n, monitors), 2, "GLsizei", n, "GLuint *", monitors)
TRACE_GL_VOID(glDeleteProgram, (GLuint program), (program), 1, "GLuint", program)
+TRACE_GL_VOID(glDeleteProgramPipelinesEXT, (GLsizei n, const GLuint *pipelines), (n, pipelines), 2, "GLsizei", n, "const GLuint *", pipelines)
+TRACE_GL_VOID(glDeleteQueriesEXT, (GLsizei n, const GLuint *ids), (n, ids), 2, "GLsizei", n, "const GLuint *", ids)
TRACE_GL_VOID(glDeleteRenderbuffers, (GLsizei n, const GLuint* renderbuffers), (n, renderbuffers), 2, "GLsizei", n, "const GLuint*", renderbuffers)
TRACE_GL_VOID(glDeleteRenderbuffersOES, (GLsizei n, const GLuint* renderbuffers), (n, renderbuffers), 2, "GLsizei", n, "const GLuint*", renderbuffers)
TRACE_GL_VOID(glDeleteShader, (GLuint shader), (shader), 1, "GLuint", shader)
@@ -84,6 +92,7 @@
TRACE_GL_VOID(glDisableVertexAttribArray, (GLuint index), (index), 1, "GLuint", index)
TRACE_GL_VOID(glDiscardFramebufferEXT, (GLenum target, GLsizei numAttachments, const GLenum *attachments), (target, numAttachments, attachments), 3, "GLenum", target, "GLsizei", numAttachments, "const GLenum *", attachments)
TRACE_GL_VOID(glDrawArrays, (GLenum mode, GLint first, GLsizei count), (mode, first, count), 3, "GLenum", mode, "GLint", first, "GLsizei", count)
+TRACE_GL_VOID(glDrawBuffersNV, (GLsizei n, const GLenum *bufs), (n, bufs), 2, "GLsizei", n, "const GLenum *", bufs)
TRACE_GL_VOID(glDrawElements, (GLenum mode, GLsizei count, GLenum type, const GLvoid *indices), (mode, count, type, indices), 4, "GLenum", mode, "GLsizei", count, "GLenum", type, "const GLvoid *", indices)
TRACE_GL_VOID(glDrawTexfOES, (GLfloat x, GLfloat y, GLfloat z, GLfloat width, GLfloat height), (x, y, z, width, height), 5, "GLfloat", x, "GLfloat", y, "GLfloat", z, "GLfloat", width, "GLfloat", height)
TRACE_GL_VOID(glDrawTexfvOES, (const GLfloat *coords), (coords), 1, "const GLfloat *", coords)
@@ -100,6 +109,7 @@
TRACE_GL_VOID(glEnableDriverControlQCOM, (GLuint driverControl), (driverControl), 1, "GLuint", driverControl)
TRACE_GL_VOID(glEnableVertexAttribArray, (GLuint index), (index), 1, "GLuint", index)
TRACE_GL_VOID(glEndPerfMonitorAMD, (GLuint monitor), (monitor), 1, "GLuint", monitor)
+TRACE_GL_VOID(glEndQueryEXT, (GLenum target), (target), 1, "GLenum", target)
TRACE_GL_VOID(glEndTilingQCOM, (GLbitfield preserveMask), (preserveMask), 1, "GLbitfield", preserveMask)
TRACE_GL_VOID(glExtGetBufferPointervQCOM, (GLenum target, GLvoid **params), (target, params), 2, "GLenum", target, "GLvoid **", params)
TRACE_GL_VOID(glExtGetBuffersQCOM, (GLuint *buffers, GLint maxBuffers, GLint *numBuffers), (buffers, maxBuffers, numBuffers), 3, "GLuint *", buffers, "GLint", maxBuffers, "GLint *", numBuffers)
@@ -125,6 +135,7 @@
TRACE_GL_VOID(glFramebufferRenderbuffer, (GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer), (target, attachment, renderbuffertarget, renderbuffer), 4, "GLenum", target, "GLenum", attachment, "GLenum", renderbuffertarget, "GLuint", renderbuffer)
TRACE_GL_VOID(glFramebufferRenderbufferOES, (GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer), (target, attachment, renderbuffertarget, renderbuffer), 4, "GLenum", target, "GLenum", attachment, "GLenum", renderbuffertarget, "GLuint", renderbuffer)
TRACE_GL_VOID(glFramebufferTexture2D, (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level), (target, attachment, textarget, texture, level), 5, "GLenum", target, "GLenum", attachment, "GLenum", textarget, "GLuint", texture, "GLint", level)
+TRACE_GL_VOID(glFramebufferTexture2DMultisampleEXT, (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level, GLsizei samples), (target, attachment, textarget, texture, level, samples), 6, "GLenum", target, "GLenum", attachment, "GLenum", textarget, "GLuint", texture, "GLint", level, "GLsizei", samples)
TRACE_GL_VOID(glFramebufferTexture2DMultisampleIMG, (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level, GLsizei samples), (target, attachment, textarget, texture, level, samples), 6, "GLenum", target, "GLenum", attachment, "GLenum", textarget, "GLuint", texture, "GLint", level, "GLsizei", samples)
TRACE_GL_VOID(glFramebufferTexture2DOES, (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level), (target, attachment, textarget, texture, level), 5, "GLenum", target, "GLenum", attachment, "GLenum", textarget, "GLuint", texture, "GLint", level)
TRACE_GL_VOID(glFramebufferTexture3DOES, (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level, GLint zoffset), (target, attachment, textarget, texture, level, zoffset), 6, "GLenum", target, "GLenum", attachment, "GLenum", textarget, "GLuint", texture, "GLint", level, "GLint", zoffset)
@@ -138,6 +149,8 @@
TRACE_GL_VOID(glGenFramebuffers, (GLsizei n, GLuint* framebuffers), (n, framebuffers), 2, "GLsizei", n, "GLuint*", framebuffers)
TRACE_GL_VOID(glGenFramebuffersOES, (GLsizei n, GLuint* framebuffers), (n, framebuffers), 2, "GLsizei", n, "GLuint*", framebuffers)
TRACE_GL_VOID(glGenPerfMonitorsAMD, (GLsizei n, GLuint *monitors), (n, monitors), 2, "GLsizei", n, "GLuint *", monitors)
+TRACE_GL_VOID(glGenProgramPipelinesEXT, (GLsizei n, GLuint *pipelines), (n, pipelines), 2, "GLsizei", n, "GLuint *", pipelines)
+TRACE_GL_VOID(glGenQueriesEXT, (GLsizei n, GLuint *ids), (n, ids), 2, "GLsizei", n, "GLuint *", ids)
TRACE_GL_VOID(glGenRenderbuffers, (GLsizei n, GLuint* renderbuffers), (n, renderbuffers), 2, "GLsizei", n, "GLuint*", renderbuffers)
TRACE_GL_VOID(glGenRenderbuffersOES, (GLsizei n, GLuint* renderbuffers), (n, renderbuffers), 2, "GLsizei", n, "GLuint*", renderbuffers)
TRACE_GL_VOID(glGenTextures, (GLsizei n, GLuint *textures), (n, textures), 2, "GLsizei", n, "GLuint *", textures)
@@ -164,6 +177,7 @@
TRACE_GL_VOID(glGetFloatv, (GLenum pname, GLfloat *params), (pname, params), 2, "GLenum", pname, "GLfloat *", params)
TRACE_GL_VOID(glGetFramebufferAttachmentParameteriv, (GLenum target, GLenum attachment, GLenum pname, GLint* params), (target, attachment, pname, params), 4, "GLenum", target, "GLenum", attachment, "GLenum", pname, "GLint*", params)
TRACE_GL_VOID(glGetFramebufferAttachmentParameterivOES, (GLenum target, GLenum attachment, GLenum pname, GLint* params), (target, attachment, pname, params), 4, "GLenum", target, "GLenum", attachment, "GLenum", pname, "GLint*", params)
+TRACE_GL(GLenum, glGetGraphicsResetStatusEXT, (void), (), 0)
TRACE_GL_VOID(glGetIntegerv, (GLenum pname, GLint *params), (pname, params), 2, "GLenum", pname, "GLint *", params)
TRACE_GL_VOID(glGetLightfv, (GLenum light, GLenum pname, GLfloat *params), (light, pname, params), 3, "GLenum", light, "GLenum", pname, "GLfloat *", params)
TRACE_GL_VOID(glGetLightxv, (GLenum light, GLenum pname, GLfixed *params), (light, pname, params), 3, "GLenum", light, "GLenum", pname, "GLfixed *", params)
@@ -171,6 +185,7 @@
TRACE_GL_VOID(glGetMaterialfv, (GLenum face, GLenum pname, GLfloat *params), (face, pname, params), 3, "GLenum", face, "GLenum", pname, "GLfloat *", params)
TRACE_GL_VOID(glGetMaterialxv, (GLenum face, GLenum pname, GLfixed *params), (face, pname, params), 3, "GLenum", face, "GLenum", pname, "GLfixed *", params)
TRACE_GL_VOID(glGetMaterialxvOES, (GLenum face, GLenum pname, GLfixed *params), (face, pname, params), 3, "GLenum", face, "GLenum", pname, "GLfixed *", params)
+TRACE_GL_VOID(glGetObjectLabelEXT, (GLenum type, GLuint object, GLsizei bufSize, GLsizei *length, GLchar *label), (type, object, bufSize, length, label), 5, "GLenum", type, "GLuint", object, "GLsizei", bufSize, "GLsizei *", length, "GLchar *", label)
TRACE_GL_VOID(glGetPerfMonitorCounterDataAMD, (GLuint monitor, GLenum pname, GLsizei dataSize, GLuint *data, GLint *bytesWritten), (monitor, pname, dataSize, data, bytesWritten), 5, "GLuint", monitor, "GLenum", pname, "GLsizei", dataSize, "GLuint *", data, "GLint *", bytesWritten)
TRACE_GL_VOID(glGetPerfMonitorCounterInfoAMD, (GLuint group, GLuint counter, GLenum pname, GLvoid *data), (group, counter, pname, data), 4, "GLuint", group, "GLuint", counter, "GLenum", pname, "GLvoid *", data)
TRACE_GL_VOID(glGetPerfMonitorCounterStringAMD, (GLuint group, GLuint counter, GLsizei bufSize, GLsizei *length, GLchar *counterString), (group, counter, bufSize, length, counterString), 5, "GLuint", group, "GLuint", counter, "GLsizei", bufSize, "GLsizei *", length, "GLchar *", counterString)
@@ -180,7 +195,11 @@
TRACE_GL_VOID(glGetPointerv, (GLenum pname, GLvoid **params), (pname, params), 2, "GLenum", pname, "GLvoid **", params)
TRACE_GL_VOID(glGetProgramBinaryOES, (GLuint program, GLsizei bufSize, GLsizei *length, GLenum *binaryFormat, GLvoid *binary), (program, bufSize, length, binaryFormat, binary), 5, "GLuint", program, "GLsizei", bufSize, "GLsizei *", length, "GLenum *", binaryFormat, "GLvoid *", binary)
TRACE_GL_VOID(glGetProgramInfoLog, (GLuint program, GLsizei bufsize, GLsizei* length, GLchar* infolog), (program, bufsize, length, infolog), 4, "GLuint", program, "GLsizei", bufsize, "GLsizei*", length, "GLchar*", infolog)
+TRACE_GL_VOID(glGetProgramPipelineInfoLogEXT, (GLuint pipeline, GLsizei bufSize, GLsizei *length, GLchar *infoLog), (pipeline, bufSize, length, infoLog), 4, "GLuint", pipeline, "GLsizei", bufSize, "GLsizei *", length, "GLchar *", infoLog)
+TRACE_GL_VOID(glGetProgramPipelineivEXT, (GLuint pipeline, GLenum pname, GLint *params), (pipeline, pname, params), 3, "GLuint", pipeline, "GLenum", pname, "GLint *", params)
TRACE_GL_VOID(glGetProgramiv, (GLuint program, GLenum pname, GLint* params), (program, pname, params), 3, "GLuint", program, "GLenum", pname, "GLint*", params)
+TRACE_GL_VOID(glGetQueryObjectuivEXT, (GLuint id, GLenum pname, GLuint *params), (id, pname, params), 3, "GLuint", id, "GLenum", pname, "GLuint *", params)
+TRACE_GL_VOID(glGetQueryivEXT, (GLenum target, GLenum pname, GLint *params), (target, pname, params), 3, "GLenum", target, "GLenum", pname, "GLint *", params)
TRACE_GL_VOID(glGetRenderbufferParameteriv, (GLenum target, GLenum pname, GLint* params), (target, pname, params), 3, "GLenum", target, "GLenum", pname, "GLint*", params)
TRACE_GL_VOID(glGetRenderbufferParameterivOES, (GLenum target, GLenum pname, GLint* params), (target, pname, params), 3, "GLenum", target, "GLenum", pname, "GLint*", params)
TRACE_GL_VOID(glGetShaderInfoLog, (GLuint shader, GLsizei bufsize, GLsizei* length, GLchar* infolog), (shader, bufsize, length, infolog), 4, "GLuint", shader, "GLsizei", bufsize, "GLsizei*", length, "GLchar*", infolog)
@@ -205,18 +224,24 @@
TRACE_GL_VOID(glGetVertexAttribPointerv, (GLuint index, GLenum pname, GLvoid** pointer), (index, pname, pointer), 3, "GLuint", index, "GLenum", pname, "GLvoid**", pointer)
TRACE_GL_VOID(glGetVertexAttribfv, (GLuint index, GLenum pname, GLfloat* params), (index, pname, params), 3, "GLuint", index, "GLenum", pname, "GLfloat*", params)
TRACE_GL_VOID(glGetVertexAttribiv, (GLuint index, GLenum pname, GLint* params), (index, pname, params), 3, "GLuint", index, "GLenum", pname, "GLint*", params)
+TRACE_GL_VOID(glGetnUniformfvEXT, (GLuint program, GLint location, GLsizei bufSize, float *params), (program, location, bufSize, params), 4, "GLuint", program, "GLint", location, "GLsizei", bufSize, "float *", params)
+TRACE_GL_VOID(glGetnUniformivEXT, (GLuint program, GLint location, GLsizei bufSize, GLint *params), (program, location, bufSize, params), 4, "GLuint", program, "GLint", location, "GLsizei", bufSize, "GLint *", params)
TRACE_GL_VOID(glHint, (GLenum target, GLenum mode), (target, mode), 2, "GLenum", target, "GLenum", mode)
+TRACE_GL_VOID(glInsertEventMarkerEXT, (GLsizei length, const GLchar *marker), (length, marker), 2, "GLsizei", length, "const GLchar *", marker)
TRACE_GL(GLboolean, glIsBuffer, (GLuint buffer), (buffer), 1, "GLuint", buffer)
TRACE_GL(GLboolean, glIsEnabled, (GLenum cap), (cap), 1, "GLenum", cap)
TRACE_GL(GLboolean, glIsFenceNV, (GLuint fence), (fence), 1, "GLuint", fence)
TRACE_GL(GLboolean, glIsFramebuffer, (GLuint framebuffer), (framebuffer), 1, "GLuint", framebuffer)
TRACE_GL(GLboolean, glIsFramebufferOES, (GLuint framebuffer), (framebuffer), 1, "GLuint", framebuffer)
TRACE_GL(GLboolean, glIsProgram, (GLuint program), (program), 1, "GLuint", program)
+TRACE_GL(GLboolean, glIsProgramPipelineEXT, (GLuint pipeline), (pipeline), 1, "GLuint", pipeline)
+TRACE_GL(GLboolean, glIsQueryEXT, (GLuint id), (id), 1, "GLuint", id)
TRACE_GL(GLboolean, glIsRenderbuffer, (GLuint renderbuffer), (renderbuffer), 1, "GLuint", renderbuffer)
TRACE_GL(GLboolean, glIsRenderbufferOES, (GLuint renderbuffer), (renderbuffer), 1, "GLuint", renderbuffer)
TRACE_GL(GLboolean, glIsShader, (GLuint shader), (shader), 1, "GLuint", shader)
TRACE_GL(GLboolean, glIsTexture, (GLuint texture), (texture), 1, "GLuint", texture)
TRACE_GL(GLboolean, glIsVertexArrayOES, (GLuint array), (array), 1, "GLuint", array)
+TRACE_GL_VOID(glLabelObjectEXT, (GLenum type, GLuint object, GLsizei length, const GLchar *label), (type, object, length, label), 4, "GLenum", type, "GLuint", object, "GLsizei", length, "const GLchar *", label)
TRACE_GL_VOID(glLightModelf, (GLenum pname, GLfloat param), (pname, param), 2, "GLenum", pname, "GLfloat", param)
TRACE_GL_VOID(glLightModelfv, (GLenum pname, const GLfloat *params), (pname, params), 2, "GLenum", pname, "const GLfloat *", params)
TRACE_GL_VOID(glLightModelx, (GLenum pname, GLfixed param), (pname, param), 2, "GLenum", pname, "GLfixed", param)
@@ -278,15 +303,43 @@
TRACE_GL_VOID(glPolygonOffset, (GLfloat factor, GLfloat units), (factor, units), 2, "GLfloat", factor, "GLfloat", units)
TRACE_GL_VOID(glPolygonOffsetx, (GLfixed factor, GLfixed units), (factor, units), 2, "GLfixed", factor, "GLfixed", units)
TRACE_GL_VOID(glPolygonOffsetxOES, (GLfixed factor, GLfixed units), (factor, units), 2, "GLfixed", factor, "GLfixed", units)
+TRACE_GL_VOID(glPopGroupMarkerEXT, (void), (), 0)
TRACE_GL_VOID(glPopMatrix, (void), (), 0)
TRACE_GL_VOID(glProgramBinaryOES, (GLuint program, GLenum binaryFormat, const GLvoid *binary, GLint length), (program, binaryFormat, binary, length), 4, "GLuint", program, "GLenum", binaryFormat, "const GLvoid *", binary, "GLint", length)
+TRACE_GL_VOID(glProgramParameteriEXT, (GLuint program, GLenum pname, GLint value), (program, pname, value), 3, "GLuint", program, "GLenum", pname, "GLint", value)
+TRACE_GL_VOID(glProgramUniform1fEXT, (GLuint program, GLint location, GLfloat x), (program, location, x), 3, "GLuint", program, "GLint", location, "GLfloat", x)
+TRACE_GL_VOID(glProgramUniform1fvEXT, (GLuint program, GLint location, GLsizei count, const GLfloat *value), (program, location, count, value), 4, "GLuint", program, "GLint", location, "GLsizei", count, "const GLfloat *", value)
+TRACE_GL_VOID(glProgramUniform1iEXT, (GLuint program, GLint location, GLint x), (program, location, x), 3, "GLuint", program, "GLint", location, "GLint", x)
+TRACE_GL_VOID(glProgramUniform1ivEXT, (GLuint program, GLint location, GLsizei count, const GLint *value), (program, location, count, value), 4, "GLuint", program, "GLint", location, "GLsizei", count, "const GLint *", value)
+TRACE_GL_VOID(glProgramUniform2fEXT, (GLuint program, GLint location, GLfloat x, GLfloat y), (program, location, x, y), 4, "GLuint", program, "GLint", location, "GLfloat", x, "GLfloat", y)
+TRACE_GL_VOID(glProgramUniform2fvEXT, (GLuint program, GLint location, GLsizei count, const GLfloat *value), (program, location, count, value), 4, "GLuint", program, "GLint", location, "GLsizei", count, "const GLfloat *", value)
+TRACE_GL_VOID(glProgramUniform2iEXT, (GLuint program, GLint location, GLint x, GLint y), (program, location, x, y), 4, "GLuint", program, "GLint", location, "GLint", x, "GLint", y)
+TRACE_GL_VOID(glProgramUniform2ivEXT, (GLuint program, GLint location, GLsizei count, const GLint *value), (program, location, count, value), 4, "GLuint", program, "GLint", location, "GLsizei", count, "const GLint *", value)
+TRACE_GL_VOID(glProgramUniform3fEXT, (GLuint program, GLint location, GLfloat x, GLfloat y, GLfloat z), (program, location, x, y, z), 5, "GLuint", program, "GLint", location, "GLfloat", x, "GLfloat", y, "GLfloat", z)
+TRACE_GL_VOID(glProgramUniform3fvEXT, (GLuint program, GLint location, GLsizei count, const GLfloat *value), (program, location, count, value), 4, "GLuint", program, "GLint", location, "GLsizei", count, "const GLfloat *", value)
+TRACE_GL_VOID(glProgramUniform3iEXT, (GLuint program, GLint location, GLint x, GLint y, GLint z), (program, location, x, y, z), 5, "GLuint", program, "GLint", location, "GLint", x, "GLint", y, "GLint", z)
+TRACE_GL_VOID(glProgramUniform3ivEXT, (GLuint program, GLint location, GLsizei count, const GLint *value), (program, location, count, value), 4, "GLuint", program, "GLint", location, "GLsizei", count, "const GLint *", value)
+TRACE_GL_VOID(glProgramUniform4fEXT, (GLuint program, GLint location, GLfloat x, GLfloat y, GLfloat z, GLfloat w), (program, location, x, y, z, w), 6, "GLuint", program, "GLint", location, "GLfloat", x, "GLfloat", y, "GLfloat", z, "GLfloat", w)
+TRACE_GL_VOID(glProgramUniform4fvEXT, (GLuint program, GLint location, GLsizei count, const GLfloat *value), (program, location, count, value), 4, "GLuint", program, "GLint", location, "GLsizei", count, "const GLfloat *", value)
+TRACE_GL_VOID(glProgramUniform4iEXT, (GLuint program, GLint location, GLint x, GLint y, GLint z, GLint w), (program, location, x, y, z, w), 6, "GLuint", program, "GLint", location, "GLint", x, "GLint", y, "GLint", z, "GLint", w)
+TRACE_GL_VOID(glProgramUniform4ivEXT, (GLuint program, GLint location, GLsizei count, const GLint *value), (program, location, count, value), 4, "GLuint", program, "GLint", location, "GLsizei", count, "const GLint *", value)
+TRACE_GL_VOID(glProgramUniformMatrix2fvEXT, (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value), (program, location, count, transpose, value), 5, "GLuint", program, "GLint", location, "GLsizei", count, "GLboolean", transpose, "const GLfloat *", value)
+TRACE_GL_VOID(glProgramUniformMatrix3fvEXT, (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value), (program, location, count, transpose, value), 5, "GLuint", program, "GLint", location, "GLsizei", count, "GLboolean", transpose, "const GLfloat *", value)
+TRACE_GL_VOID(glProgramUniformMatrix4fvEXT, (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value), (program, location, count, transpose, value), 5, "GLuint", program, "GLint", location, "GLsizei", count, "GLboolean", transpose, "const GLfloat *", value)
+TRACE_GL_VOID(glPushGroupMarkerEXT, (GLsizei length, const GLchar *marker), (length, marker), 2, "GLsizei", length, "const GLchar *", marker)
TRACE_GL_VOID(glPushMatrix, (void), (), 0)
TRACE_GL(GLbitfield, glQueryMatrixxOES, (GLfixed mantissa[16], GLint exponent[16]), (mantissa, exponent), 2, "GLfixed", mantissa, "GLint", exponent)
+TRACE_GL_VOID(glReadBufferNV, (GLenum mode), (mode), 1, "GLenum", mode)
TRACE_GL_VOID(glReadPixels, (GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLvoid *pixels), (x, y, width, height, format, type, pixels), 7, "GLint", x, "GLint", y, "GLsizei", width, "GLsizei", height, "GLenum", format, "GLenum", type, "GLvoid *", pixels)
+TRACE_GL_VOID(glReadnPixelsEXT, (GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLsizei bufSize, void *data), (x, y, width, height, format, type, bufSize, data), 8, "GLint", x, "GLint", y, "GLsizei", width, "GLsizei", height, "GLenum", format, "GLenum", type, "GLsizei", bufSize, "void *", data)
TRACE_GL_VOID(glReleaseShaderCompiler, (void), (), 0)
TRACE_GL_VOID(glRenderbufferStorage, (GLenum target, GLenum internalformat, GLsizei width, GLsizei height), (target, internalformat, width, height), 4, "GLenum", target, "GLenum", internalformat, "GLsizei", width, "GLsizei", height)
+TRACE_GL_VOID(glRenderbufferStorageMultisampleANGLE, (GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height), (target, samples, internalformat, width, height), 5, "GLenum", target, "GLsizei", samples, "GLenum", internalformat, "GLsizei", width, "GLsizei", height)
+TRACE_GL_VOID(glRenderbufferStorageMultisampleAPPLE, (GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height), (target, samples, internalformat, width, height), 5, "GLenum", target, "GLsizei", samples, "GLenum", internalformat, "GLsizei", width, "GLsizei", height)
+TRACE_GL_VOID(glRenderbufferStorageMultisampleEXT, (GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height), (target, samples, internalformat, width, height), 5, "GLenum", target, "GLsizei", samples, "GLenum", internalformat, "GLsizei", width, "GLsizei", height)
TRACE_GL_VOID(glRenderbufferStorageMultisampleIMG, (GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height), (target, samples, internalformat, width, height), 5, "GLenum", target, "GLsizei", samples, "GLenum", internalformat, "GLsizei", width, "GLsizei", height)
TRACE_GL_VOID(glRenderbufferStorageOES, (GLenum target, GLenum internalformat, GLsizei width, GLsizei height), (target, internalformat, width, height), 4, "GLenum", target, "GLenum", internalformat, "GLsizei", width, "GLsizei", height)
+TRACE_GL_VOID(glResolveMultisampleFramebufferAPPLE, (void), (), 0)
TRACE_GL_VOID(glRotatef, (GLfloat angle, GLfloat x, GLfloat y, GLfloat z), (angle, x, y, z), 4, "GLfloat", angle, "GLfloat", x, "GLfloat", y, "GLfloat", z)
TRACE_GL_VOID(glRotatex, (GLfixed angle, GLfixed x, GLfixed y, GLfixed z), (angle, x, y, z), 4, "GLfixed", angle, "GLfixed", x, "GLfixed", y, "GLfixed", z)
TRACE_GL_VOID(glRotatexOES, (GLfixed angle, GLfixed x, GLfixed y, GLfixed z), (angle, x, y, z), 4, "GLfixed", angle, "GLfixed", x, "GLfixed", y, "GLfixed", z)
@@ -335,8 +388,14 @@
TRACE_GL_VOID(glTexParameterxOES, (GLenum target, GLenum pname, GLfixed param), (target, pname, param), 3, "GLenum", target, "GLenum", pname, "GLfixed", param)
TRACE_GL_VOID(glTexParameterxv, (GLenum target, GLenum pname, const GLfixed *params), (target, pname, params), 3, "GLenum", target, "GLenum", pname, "const GLfixed *", params)
TRACE_GL_VOID(glTexParameterxvOES, (GLenum target, GLenum pname, const GLfixed *params), (target, pname, params), 3, "GLenum", target, "GLenum", pname, "const GLfixed *", params)
+TRACE_GL_VOID(glTexStorage1DEXT, (GLenum target, GLsizei levels, GLenum internalformat, GLsizei width), (target, levels, internalformat, width), 4, "GLenum", target, "GLsizei", levels, "GLenum", internalformat, "GLsizei", width)
+TRACE_GL_VOID(glTexStorage2DEXT, (GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height), (target, levels, internalformat, width, height), 5, "GLenum", target, "GLsizei", levels, "GLenum", internalformat, "GLsizei", width, "GLsizei", height)
+TRACE_GL_VOID(glTexStorage3DEXT, (GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth), (target, levels, internalformat, width, height, depth), 6, "GLenum", target, "GLsizei", levels, "GLenum", internalformat, "GLsizei", width, "GLsizei", height, "GLsizei", depth)
TRACE_GL_VOID(glTexSubImage2D, (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *pixels), (target, level, xoffset, yoffset, width, height, format, type, pixels), 9, "GLenum", target, "GLint", level, "GLint", xoffset, "GLint", yoffset, "GLsizei", width, "GLsizei", height, "GLenum", format, "GLenum", type, "const GLvoid *", pixels)
TRACE_GL_VOID(glTexSubImage3DOES, (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const GLvoid* pixels), (target, level, xoffset, yoffset, zoffset, width, height, depth, format, type, pixels), 11, "GLenum", target, "GLint", level, "GLint", xoffset, "GLint", yoffset, "GLint", zoffset, "GLsizei", width, "GLsizei", height, "GLsizei", depth, "GLenum", format, "GLenum", type, "const GLvoid*", pixels)
+TRACE_GL_VOID(glTextureStorage1DEXT, (GLuint texture, GLenum target, GLsizei levels, GLenum internalformat, GLsizei width), (texture, target, levels, internalformat, width), 5, "GLuint", texture, "GLenum", target, "GLsizei", levels, "GLenum", internalformat, "GLsizei", width)
+TRACE_GL_VOID(glTextureStorage2DEXT, (GLuint texture, GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height), (texture, target, levels, internalformat, width, height), 6, "GLuint", texture, "GLenum", target, "GLsizei", levels, "GLenum", internalformat, "GLsizei", width, "GLsizei", height)
+TRACE_GL_VOID(glTextureStorage3DEXT, (GLuint texture, GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth), (texture, target, levels, internalformat, width, height, depth), 7, "GLuint", texture, "GLenum", target, "GLsizei", levels, "GLenum", internalformat, "GLsizei", width, "GLsizei", height, "GLsizei", depth)
TRACE_GL_VOID(glTranslatef, (GLfloat x, GLfloat y, GLfloat z), (x, y, z), 3, "GLfloat", x, "GLfloat", y, "GLfloat", z)
TRACE_GL_VOID(glTranslatex, (GLfixed x, GLfixed y, GLfixed z), (x, y, z), 3, "GLfixed", x, "GLfixed", y, "GLfixed", z)
TRACE_GL_VOID(glTranslatexOES, (GLfixed x, GLfixed y, GLfixed z), (x, y, z), 3, "GLfixed", x, "GLfixed", y, "GLfixed", z)
@@ -361,7 +420,9 @@
TRACE_GL_VOID(glUniformMatrix4fv, (GLint location, GLsizei count, GLboolean transpose, const GLfloat* value), (location, count, transpose, value), 4, "GLint", location, "GLsizei", count, "GLboolean", transpose, "const GLfloat*", value)
TRACE_GL(GLboolean, glUnmapBufferOES, (GLenum target), (target), 1, "GLenum", target)
TRACE_GL_VOID(glUseProgram, (GLuint program), (program), 1, "GLuint", program)
+TRACE_GL_VOID(glUseProgramStagesEXT, (GLuint pipeline, GLbitfield stages, GLuint program), (pipeline, stages, program), 3, "GLuint", pipeline, "GLbitfield", stages, "GLuint", program)
TRACE_GL_VOID(glValidateProgram, (GLuint program), (program), 1, "GLuint", program)
+TRACE_GL_VOID(glValidateProgramPipelineEXT, (GLuint pipeline), (pipeline), 1, "GLuint", pipeline)
TRACE_GL_VOID(glVertexAttrib1f, (GLuint indx, GLfloat x), (indx, x), 2, "GLuint", indx, "GLfloat", x)
TRACE_GL_VOID(glVertexAttrib1fv, (GLuint indx, const GLfloat* values), (indx, values), 2, "GLuint", indx, "const GLfloat*", values)
TRACE_GL_VOID(glVertexAttrib2f, (GLuint indx, GLfloat x, GLfloat y), (indx, x, y), 3, "GLuint", indx, "GLfloat", x, "GLfloat", y)
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_data_wimax_signal_0.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_wimax_signal_0.png
index f24d801..55272f5 100644
--- a/packages/SystemUI/res/drawable-hdpi/stat_sys_data_wimax_signal_0.png
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_wimax_signal_0.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_data_wimax_signal_0_fully.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_wimax_signal_0_fully.png
index 66eb5db..e5e6305 100644
--- a/packages/SystemUI/res/drawable-hdpi/stat_sys_data_wimax_signal_0_fully.png
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_wimax_signal_0_fully.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_data_wimax_signal_1.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_wimax_signal_1.png
index edff74a..f595ae1 100644
--- a/packages/SystemUI/res/drawable-hdpi/stat_sys_data_wimax_signal_1.png
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_wimax_signal_1.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_data_wimax_signal_1_fully.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_wimax_signal_1_fully.png
index 1cdd4eb..f555fc9 100644
--- a/packages/SystemUI/res/drawable-hdpi/stat_sys_data_wimax_signal_1_fully.png
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_wimax_signal_1_fully.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_data_wimax_signal_2.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_wimax_signal_2.png
index 95fdaf9..ecf1349 100644
--- a/packages/SystemUI/res/drawable-hdpi/stat_sys_data_wimax_signal_2.png
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_wimax_signal_2.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_data_wimax_signal_2_fully.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_wimax_signal_2_fully.png
index 8678e39..918a9f9 100644
--- a/packages/SystemUI/res/drawable-hdpi/stat_sys_data_wimax_signal_2_fully.png
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_wimax_signal_2_fully.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_data_wimax_signal_3.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_wimax_signal_3.png
index 1d2d290..f5d1479 100644
--- a/packages/SystemUI/res/drawable-hdpi/stat_sys_data_wimax_signal_3.png
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_wimax_signal_3.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_data_wimax_signal_3_fully.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_wimax_signal_3_fully.png
index c2e4b78..f58a19c 100644
--- a/packages/SystemUI/res/drawable-hdpi/stat_sys_data_wimax_signal_3_fully.png
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_wimax_signal_3_fully.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_data_wimax_signal_disconnected.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_wimax_signal_disconnected.png
index 51b839f..744b1fa 100644
--- a/packages/SystemUI/res/drawable-hdpi/stat_sys_data_wimax_signal_disconnected.png
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_wimax_signal_disconnected.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_data_wimax_signal_idle.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_wimax_signal_idle.png
index b20c5c7..bef4358 100644
--- a/packages/SystemUI/res/drawable-hdpi/stat_sys_data_wimax_signal_idle.png
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_wimax_signal_idle.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_0.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_0.png
index b0e1424..a2ba6c4 100644
--- a/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_0.png
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_0.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_0_fully.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_0_fully.png
index 797b1eb..00b560c 100644
--- a/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_0_fully.png
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_0_fully.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_1.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_1.png
index 7c479e8..fd8d2f2 100644
--- a/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_1.png
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_1.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_1_fully.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_1_fully.png
index c60def1..92364d2 100644
--- a/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_1_fully.png
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_1_fully.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_2.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_2.png
index 1cef87b..3b4aaa1 100644
--- a/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_2.png
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_2.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_2_fully.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_2_fully.png
index 61e0e95..8cea4e9 100644
--- a/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_2_fully.png
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_2_fully.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_3.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_3.png
index 48c3490..873a317 100644
--- a/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_3.png
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_3.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_3_fully.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_3_fully.png
index 71205bf..94a4a35 100644
--- a/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_3_fully.png
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_3_fully.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_4.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_4.png
index e5b0e2d..d2381fcc 100644
--- a/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_4.png
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_4.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_4_fully.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_4_fully.png
index 5e74e44..93552cb 100644
--- a/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_4_fully.png
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_4_fully.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_null.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_null.png
new file mode 100644
index 0000000..daf18c7
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_null.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_wimax_signal_0.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_wimax_signal_0.png
new file mode 100644
index 0000000..a0c7a99
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_wimax_signal_0.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_wimax_signal_0_fully.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_wimax_signal_0_fully.png
new file mode 100644
index 0000000..b1f1e5b
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_wimax_signal_0_fully.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_wimax_signal_1.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_wimax_signal_1.png
new file mode 100644
index 0000000..8b31618
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_wimax_signal_1.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_wimax_signal_1_fully.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_wimax_signal_1_fully.png
new file mode 100644
index 0000000..1a62682
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_wimax_signal_1_fully.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_wimax_signal_2.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_wimax_signal_2.png
new file mode 100644
index 0000000..ff51551
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_wimax_signal_2.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_wimax_signal_2_fully.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_wimax_signal_2_fully.png
new file mode 100644
index 0000000..0374142
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_wimax_signal_2_fully.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_wimax_signal_3.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_wimax_signal_3.png
new file mode 100644
index 0000000..8f881f2
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_wimax_signal_3.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_wimax_signal_3_fully.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_wimax_signal_3_fully.png
new file mode 100644
index 0000000..7870cee
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_wimax_signal_3_fully.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_wimax_signal_disconnected.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_wimax_signal_disconnected.png
new file mode 100644
index 0000000..65404c2
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_wimax_signal_disconnected.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_wimax_signal_idle.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_wimax_signal_idle.png
new file mode 100644
index 0000000..327f89d
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_wimax_signal_idle.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_0.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_0.png
index 76b272e..d93a661 100644
--- a/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_0.png
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_0.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_0_fully.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_0_fully.png
index 18c603d..b39cc04 100644
--- a/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_0_fully.png
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_0_fully.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_1.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_1.png
index 89274b1..4305351 100644
--- a/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_1.png
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_1.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_1_fully.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_1_fully.png
index ae8e70a..4305be2 100644
--- a/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_1_fully.png
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_1_fully.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_2.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_2.png
index 35ec9bd..beb641b 100644
--- a/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_2.png
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_2.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_2_fully.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_2_fully.png
index b082e9f..7b8ddc2 100644
--- a/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_2_fully.png
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_2_fully.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_3.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_3.png
index a2c7ed8..a4028cd 100644
--- a/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_3.png
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_3.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_3_fully.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_3_fully.png
index e12ecbf..fad1873 100644
--- a/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_3_fully.png
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_3_fully.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_4.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_4.png
index f08b75e..b5ed22b 100644
--- a/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_4.png
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_4.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_4_fully.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_4_fully.png
index 12581d5..cca7bf3 100644
--- a/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_4_fully.png
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_4_fully.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_null.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_null.png
new file mode 100644
index 0000000..5292998
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_null.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw600dp-hdpi/stat_sys_signal_0.png b/packages/SystemUI/res/drawable-sw600dp-hdpi/stat_sys_signal_0.png
index a290cf0..ac322ba 100644
--- a/packages/SystemUI/res/drawable-sw600dp-hdpi/stat_sys_signal_0.png
+++ b/packages/SystemUI/res/drawable-sw600dp-hdpi/stat_sys_signal_0.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw600dp-hdpi/stat_sys_signal_0_fully.png b/packages/SystemUI/res/drawable-sw600dp-hdpi/stat_sys_signal_0_fully.png
index 09314e9..ac322ba 100644
--- a/packages/SystemUI/res/drawable-sw600dp-hdpi/stat_sys_signal_0_fully.png
+++ b/packages/SystemUI/res/drawable-sw600dp-hdpi/stat_sys_signal_0_fully.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw600dp-hdpi/stat_sys_signal_1.png b/packages/SystemUI/res/drawable-sw600dp-hdpi/stat_sys_signal_1.png
index 90de934..f139bbe 100644
--- a/packages/SystemUI/res/drawable-sw600dp-hdpi/stat_sys_signal_1.png
+++ b/packages/SystemUI/res/drawable-sw600dp-hdpi/stat_sys_signal_1.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw600dp-hdpi/stat_sys_signal_1_fully.png b/packages/SystemUI/res/drawable-sw600dp-hdpi/stat_sys_signal_1_fully.png
index cdcac61..af67018 100644
--- a/packages/SystemUI/res/drawable-sw600dp-hdpi/stat_sys_signal_1_fully.png
+++ b/packages/SystemUI/res/drawable-sw600dp-hdpi/stat_sys_signal_1_fully.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw600dp-hdpi/stat_sys_signal_2.png b/packages/SystemUI/res/drawable-sw600dp-hdpi/stat_sys_signal_2.png
index 570a9b5..fe404e2 100644
--- a/packages/SystemUI/res/drawable-sw600dp-hdpi/stat_sys_signal_2.png
+++ b/packages/SystemUI/res/drawable-sw600dp-hdpi/stat_sys_signal_2.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw600dp-hdpi/stat_sys_signal_2_fully.png b/packages/SystemUI/res/drawable-sw600dp-hdpi/stat_sys_signal_2_fully.png
index 68f3075..1ffa9b6 100644
--- a/packages/SystemUI/res/drawable-sw600dp-hdpi/stat_sys_signal_2_fully.png
+++ b/packages/SystemUI/res/drawable-sw600dp-hdpi/stat_sys_signal_2_fully.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw600dp-hdpi/stat_sys_signal_3.png b/packages/SystemUI/res/drawable-sw600dp-hdpi/stat_sys_signal_3.png
index 07b03fa..75cd8ee 100644
--- a/packages/SystemUI/res/drawable-sw600dp-hdpi/stat_sys_signal_3.png
+++ b/packages/SystemUI/res/drawable-sw600dp-hdpi/stat_sys_signal_3.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw600dp-hdpi/stat_sys_signal_3_fully.png b/packages/SystemUI/res/drawable-sw600dp-hdpi/stat_sys_signal_3_fully.png
index 9dff62d..666d1f6 100644
--- a/packages/SystemUI/res/drawable-sw600dp-hdpi/stat_sys_signal_3_fully.png
+++ b/packages/SystemUI/res/drawable-sw600dp-hdpi/stat_sys_signal_3_fully.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw600dp-hdpi/stat_sys_signal_4.png b/packages/SystemUI/res/drawable-sw600dp-hdpi/stat_sys_signal_4.png
index f855c1c..da9607b 100644
--- a/packages/SystemUI/res/drawable-sw600dp-hdpi/stat_sys_signal_4.png
+++ b/packages/SystemUI/res/drawable-sw600dp-hdpi/stat_sys_signal_4.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw600dp-hdpi/stat_sys_signal_4_fully.png b/packages/SystemUI/res/drawable-sw600dp-hdpi/stat_sys_signal_4_fully.png
index 119ce32..d05297f 100644
--- a/packages/SystemUI/res/drawable-sw600dp-hdpi/stat_sys_signal_4_fully.png
+++ b/packages/SystemUI/res/drawable-sw600dp-hdpi/stat_sys_signal_4_fully.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw600dp-hdpi/stat_sys_signal_null.png b/packages/SystemUI/res/drawable-sw600dp-hdpi/stat_sys_signal_null.png
new file mode 100644
index 0000000..3733a38
--- /dev/null
+++ b/packages/SystemUI/res/drawable-sw600dp-hdpi/stat_sys_signal_null.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw600dp-mdpi/stat_sys_signal_0.png b/packages/SystemUI/res/drawable-sw600dp-mdpi/stat_sys_signal_0.png
index 926b081..f931c60 100644
--- a/packages/SystemUI/res/drawable-sw600dp-mdpi/stat_sys_signal_0.png
+++ b/packages/SystemUI/res/drawable-sw600dp-mdpi/stat_sys_signal_0.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw600dp-mdpi/stat_sys_signal_0_fully.png b/packages/SystemUI/res/drawable-sw600dp-mdpi/stat_sys_signal_0_fully.png
index 4498bed..f931c60 100644
--- a/packages/SystemUI/res/drawable-sw600dp-mdpi/stat_sys_signal_0_fully.png
+++ b/packages/SystemUI/res/drawable-sw600dp-mdpi/stat_sys_signal_0_fully.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw600dp-mdpi/stat_sys_signal_1.png b/packages/SystemUI/res/drawable-sw600dp-mdpi/stat_sys_signal_1.png
index 60b00a8..398f4d5 100644
--- a/packages/SystemUI/res/drawable-sw600dp-mdpi/stat_sys_signal_1.png
+++ b/packages/SystemUI/res/drawable-sw600dp-mdpi/stat_sys_signal_1.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw600dp-mdpi/stat_sys_signal_1_fully.png b/packages/SystemUI/res/drawable-sw600dp-mdpi/stat_sys_signal_1_fully.png
index 8e9be27..a0fc3f2 100644
--- a/packages/SystemUI/res/drawable-sw600dp-mdpi/stat_sys_signal_1_fully.png
+++ b/packages/SystemUI/res/drawable-sw600dp-mdpi/stat_sys_signal_1_fully.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw600dp-mdpi/stat_sys_signal_2.png b/packages/SystemUI/res/drawable-sw600dp-mdpi/stat_sys_signal_2.png
index 014d838..5fe96a3 100644
--- a/packages/SystemUI/res/drawable-sw600dp-mdpi/stat_sys_signal_2.png
+++ b/packages/SystemUI/res/drawable-sw600dp-mdpi/stat_sys_signal_2.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw600dp-mdpi/stat_sys_signal_2_fully.png b/packages/SystemUI/res/drawable-sw600dp-mdpi/stat_sys_signal_2_fully.png
index 1755088..8a66255 100644
--- a/packages/SystemUI/res/drawable-sw600dp-mdpi/stat_sys_signal_2_fully.png
+++ b/packages/SystemUI/res/drawable-sw600dp-mdpi/stat_sys_signal_2_fully.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw600dp-mdpi/stat_sys_signal_3.png b/packages/SystemUI/res/drawable-sw600dp-mdpi/stat_sys_signal_3.png
index 44e7905..e785a7a 100644
--- a/packages/SystemUI/res/drawable-sw600dp-mdpi/stat_sys_signal_3.png
+++ b/packages/SystemUI/res/drawable-sw600dp-mdpi/stat_sys_signal_3.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw600dp-mdpi/stat_sys_signal_3_fully.png b/packages/SystemUI/res/drawable-sw600dp-mdpi/stat_sys_signal_3_fully.png
index bfc17dd..63be95d 100644
--- a/packages/SystemUI/res/drawable-sw600dp-mdpi/stat_sys_signal_3_fully.png
+++ b/packages/SystemUI/res/drawable-sw600dp-mdpi/stat_sys_signal_3_fully.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw600dp-mdpi/stat_sys_signal_4.png b/packages/SystemUI/res/drawable-sw600dp-mdpi/stat_sys_signal_4.png
index e39d7d7..533bcdc 100644
--- a/packages/SystemUI/res/drawable-sw600dp-mdpi/stat_sys_signal_4.png
+++ b/packages/SystemUI/res/drawable-sw600dp-mdpi/stat_sys_signal_4.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw600dp-mdpi/stat_sys_signal_4_fully.png b/packages/SystemUI/res/drawable-sw600dp-mdpi/stat_sys_signal_4_fully.png
index 466d3b5..566172e 100644
--- a/packages/SystemUI/res/drawable-sw600dp-mdpi/stat_sys_signal_4_fully.png
+++ b/packages/SystemUI/res/drawable-sw600dp-mdpi/stat_sys_signal_4_fully.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw600dp-mdpi/stat_sys_signal_null.png b/packages/SystemUI/res/drawable-sw600dp-mdpi/stat_sys_signal_null.png
new file mode 100644
index 0000000..ab718ad
--- /dev/null
+++ b/packages/SystemUI/res/drawable-sw600dp-mdpi/stat_sys_signal_null.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw600dp-xhdpi/stat_sys_signal_0.png b/packages/SystemUI/res/drawable-sw600dp-xhdpi/stat_sys_signal_0.png
index 1744f65..ccf1ba1 100644
--- a/packages/SystemUI/res/drawable-sw600dp-xhdpi/stat_sys_signal_0.png
+++ b/packages/SystemUI/res/drawable-sw600dp-xhdpi/stat_sys_signal_0.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw600dp-xhdpi/stat_sys_signal_0_fully.png b/packages/SystemUI/res/drawable-sw600dp-xhdpi/stat_sys_signal_0_fully.png
index 6270e51..ccf1ba1 100644
--- a/packages/SystemUI/res/drawable-sw600dp-xhdpi/stat_sys_signal_0_fully.png
+++ b/packages/SystemUI/res/drawable-sw600dp-xhdpi/stat_sys_signal_0_fully.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw600dp-xhdpi/stat_sys_signal_1.png b/packages/SystemUI/res/drawable-sw600dp-xhdpi/stat_sys_signal_1.png
index b47624f..07937fe 100644
--- a/packages/SystemUI/res/drawable-sw600dp-xhdpi/stat_sys_signal_1.png
+++ b/packages/SystemUI/res/drawable-sw600dp-xhdpi/stat_sys_signal_1.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw600dp-xhdpi/stat_sys_signal_1_fully.png b/packages/SystemUI/res/drawable-sw600dp-xhdpi/stat_sys_signal_1_fully.png
index 9fd562d..ba1b077 100644
--- a/packages/SystemUI/res/drawable-sw600dp-xhdpi/stat_sys_signal_1_fully.png
+++ b/packages/SystemUI/res/drawable-sw600dp-xhdpi/stat_sys_signal_1_fully.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw600dp-xhdpi/stat_sys_signal_2.png b/packages/SystemUI/res/drawable-sw600dp-xhdpi/stat_sys_signal_2.png
index 42630a2..a705a89 100644
--- a/packages/SystemUI/res/drawable-sw600dp-xhdpi/stat_sys_signal_2.png
+++ b/packages/SystemUI/res/drawable-sw600dp-xhdpi/stat_sys_signal_2.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw600dp-xhdpi/stat_sys_signal_2_fully.png b/packages/SystemUI/res/drawable-sw600dp-xhdpi/stat_sys_signal_2_fully.png
index 1777ce7..0187d12 100644
--- a/packages/SystemUI/res/drawable-sw600dp-xhdpi/stat_sys_signal_2_fully.png
+++ b/packages/SystemUI/res/drawable-sw600dp-xhdpi/stat_sys_signal_2_fully.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw600dp-xhdpi/stat_sys_signal_3.png b/packages/SystemUI/res/drawable-sw600dp-xhdpi/stat_sys_signal_3.png
index d35d546..0ed7d6f4 100644
--- a/packages/SystemUI/res/drawable-sw600dp-xhdpi/stat_sys_signal_3.png
+++ b/packages/SystemUI/res/drawable-sw600dp-xhdpi/stat_sys_signal_3.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw600dp-xhdpi/stat_sys_signal_3_fully.png b/packages/SystemUI/res/drawable-sw600dp-xhdpi/stat_sys_signal_3_fully.png
index 324ec32..24a6e5a 100644
--- a/packages/SystemUI/res/drawable-sw600dp-xhdpi/stat_sys_signal_3_fully.png
+++ b/packages/SystemUI/res/drawable-sw600dp-xhdpi/stat_sys_signal_3_fully.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw600dp-xhdpi/stat_sys_signal_4.png b/packages/SystemUI/res/drawable-sw600dp-xhdpi/stat_sys_signal_4.png
index 54f3ae7..1a47801 100644
--- a/packages/SystemUI/res/drawable-sw600dp-xhdpi/stat_sys_signal_4.png
+++ b/packages/SystemUI/res/drawable-sw600dp-xhdpi/stat_sys_signal_4.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw600dp-xhdpi/stat_sys_signal_4_fully.png b/packages/SystemUI/res/drawable-sw600dp-xhdpi/stat_sys_signal_4_fully.png
index 290dafa..d9648b6f 100644
--- a/packages/SystemUI/res/drawable-sw600dp-xhdpi/stat_sys_signal_4_fully.png
+++ b/packages/SystemUI/res/drawable-sw600dp-xhdpi/stat_sys_signal_4_fully.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw600dp-xhdpi/stat_sys_signal_null.png b/packages/SystemUI/res/drawable-sw600dp-xhdpi/stat_sys_signal_null.png
new file mode 100644
index 0000000..023bbe6
--- /dev/null
+++ b/packages/SystemUI/res/drawable-sw600dp-xhdpi/stat_sys_signal_null.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/stat_sys_data_wimax_signal_0.png b/packages/SystemUI/res/drawable-xhdpi/stat_sys_data_wimax_signal_0.png
new file mode 100644
index 0000000..7a8d1f3
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/stat_sys_data_wimax_signal_0.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/stat_sys_data_wimax_signal_0_fully.png b/packages/SystemUI/res/drawable-xhdpi/stat_sys_data_wimax_signal_0_fully.png
new file mode 100644
index 0000000..5f86bbb
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/stat_sys_data_wimax_signal_0_fully.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/stat_sys_data_wimax_signal_1.png b/packages/SystemUI/res/drawable-xhdpi/stat_sys_data_wimax_signal_1.png
new file mode 100644
index 0000000..70e2011
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/stat_sys_data_wimax_signal_1.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/stat_sys_data_wimax_signal_1_fully.png b/packages/SystemUI/res/drawable-xhdpi/stat_sys_data_wimax_signal_1_fully.png
new file mode 100644
index 0000000..c1d1cc3
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/stat_sys_data_wimax_signal_1_fully.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/stat_sys_data_wimax_signal_2.png b/packages/SystemUI/res/drawable-xhdpi/stat_sys_data_wimax_signal_2.png
new file mode 100644
index 0000000..c62d977
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/stat_sys_data_wimax_signal_2.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/stat_sys_data_wimax_signal_2_fully.png b/packages/SystemUI/res/drawable-xhdpi/stat_sys_data_wimax_signal_2_fully.png
new file mode 100644
index 0000000..86d30df
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/stat_sys_data_wimax_signal_2_fully.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/stat_sys_data_wimax_signal_3.png b/packages/SystemUI/res/drawable-xhdpi/stat_sys_data_wimax_signal_3.png
new file mode 100644
index 0000000..b112748
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/stat_sys_data_wimax_signal_3.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/stat_sys_data_wimax_signal_3_fully.png b/packages/SystemUI/res/drawable-xhdpi/stat_sys_data_wimax_signal_3_fully.png
new file mode 100644
index 0000000..bfc7d81
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/stat_sys_data_wimax_signal_3_fully.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/stat_sys_data_wimax_signal_disconnected.png b/packages/SystemUI/res/drawable-xhdpi/stat_sys_data_wimax_signal_disconnected.png
new file mode 100644
index 0000000..bea643f3a
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/stat_sys_data_wimax_signal_disconnected.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/stat_sys_data_wimax_signal_idle.png b/packages/SystemUI/res/drawable-xhdpi/stat_sys_data_wimax_signal_idle.png
new file mode 100644
index 0000000..a8a89d6
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/stat_sys_data_wimax_signal_idle.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_0.png b/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_0.png
index 9c80517..0a28885 100644
--- a/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_0.png
+++ b/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_0.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_0_fully.png b/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_0_fully.png
index b144e18..bbe70cc 100644
--- a/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_0_fully.png
+++ b/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_0_fully.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_1.png b/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_1.png
index 32762da..9943613 100644
--- a/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_1.png
+++ b/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_1.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_1_fully.png b/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_1_fully.png
index ae02c8f..e25a55c 100644
--- a/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_1_fully.png
+++ b/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_1_fully.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_2.png b/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_2.png
index f95f677..1fc1775 100644
--- a/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_2.png
+++ b/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_2.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_2_fully.png b/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_2_fully.png
index 23343e9..d1aefca 100644
--- a/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_2_fully.png
+++ b/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_2_fully.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_3.png b/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_3.png
index d72d42b..82b9741 100644
--- a/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_3.png
+++ b/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_3.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_3_fully.png b/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_3_fully.png
index 3e5eaf4..c8c2c63 100644
--- a/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_3_fully.png
+++ b/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_3_fully.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_4.png b/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_4.png
index bf8ca9f..9f4979c 100644
--- a/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_4.png
+++ b/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_4.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_4_fully.png b/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_4_fully.png
index e9de257..b2e64b9 100644
--- a/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_4_fully.png
+++ b/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_4_fully.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_null.png b/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_null.png
new file mode 100644
index 0000000..3e7fefd
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/stat_sys_signal_null.png
Binary files differ
diff --git a/packages/SystemUI/res/layout-sw600dp/status_bar_notification_panel_title.xml b/packages/SystemUI/res/layout-sw600dp/status_bar_notification_panel_title.xml
index c9b1673..b985aaf 100644
--- a/packages/SystemUI/res/layout-sw600dp/status_bar_notification_panel_title.xml
+++ b/packages/SystemUI/res/layout-sw600dp/status_bar_notification_panel_title.xml
@@ -44,12 +44,13 @@
<FrameLayout
android:layout_height="wrap_content"
android:layout_width="wrap_content"
+ android:layout_gravity="center_vertical"
>
<ImageView
android:id="@+id/bluetooth"
android:layout_height="wrap_content"
android:layout_width="wrap_content"
- android:scaleType="centerInside"
+ android:paddingRight="16dp"
android:visibility="gone"
android:contentDescription="@null"
android:layout_gravity="center_vertical"
@@ -61,8 +62,8 @@
android:id="@+id/mobile_icon"
android:layout_height="wrap_content"
android:layout_width="wrap_content"
- android:paddingRight="4dp"
android:layout_gravity="center_vertical"
+ android:paddingRight="6dp"
>
<ImageView
@@ -86,8 +87,7 @@
android:layout_gravity="left|center_vertical"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:paddingRight="8dp"
- android:layout_weight="1"
+ android:paddingRight="12dp"
android:singleLine="true"
android:ellipsize="end"
android:text="@string/status_bar_settings_settings_button"
@@ -98,8 +98,8 @@
android:id="@+id/wifi_icon"
android:layout_height="wrap_content"
android:layout_width="wrap_content"
- android:paddingRight="4dp"
android:layout_gravity="center_vertical"
+ android:paddingRight="6dp"
>
<ImageView
@@ -123,7 +123,7 @@
android:layout_gravity="left|center_vertical"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:paddingRight="8dp"
+ android:paddingRight="12dp"
android:singleLine="true"
android:ellipsize="end"
android:text="@string/status_bar_settings_settings_button"
@@ -136,18 +136,17 @@
android:scaleType="centerInside"
android:layout_gravity="center_vertical"
android:layout_alignBaseline="@id/wifi_signal"
- android:paddingLeft="8dp"
- android:paddingRight="8dp"
+ android:paddingRight="6dp"
android:contentDescription="@null"
/>
<TextView
android:id="@+id/battery_text"
style="@style/StatusBarNotificationText"
- android:layout_width="56dp"
+ android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="left|center_vertical"
- android:paddingRight="8dp"
+ android:paddingRight="2dp"
android:singleLine="true"
android:text="@string/status_bar_settings_settings_button"
/>
diff --git a/packages/SystemUI/res/values-be/strings.xml b/packages/SystemUI/res/values-be/strings.xml
index a6c64ad..d083467 100644
--- a/packages/SystemUI/res/values-be/strings.xml
+++ b/packages/SystemUI/res/values-be/strings.xml
@@ -101,7 +101,12 @@
<string name="accessibility_wifi_one_bar" msgid="6854947280074467207">"Wi-Fi, адзiн слупок."</string>
<string name="accessibility_wifi_two_bars" msgid="3344340012058984348">"Wi-Fi, два слупкi."</string>
<string name="accessibility_wifi_three_bars" msgid="928322805193265041">"Wi-Fi, тры слупкi."</string>
- <string name="accessibility_wifi_signal_full" msgid="4826278754383492058">"Моцны сiгнал Wi-Fi."</string>
+ <string name="accessibility_wifi_signal_full" msgid="1275764416228473932">"Поўны сігнал Wi-Fi."</string>
+ <string name="accessibility_no_wimax" msgid="4329180129727630368">"Няма сiгналу WiMAX."</string>
+ <string name="accessibility_wimax_one_bar" msgid="4170994299011863648">"Адзiн слупок сiгналу WiMAX."</string>
+ <string name="accessibility_wimax_two_bars" msgid="9176236858336502288">"Два слупкi сiгналу WiMAX."</string>
+ <string name="accessibility_wimax_three_bars" msgid="6116551636752103927">"Тры слупкi сiгналу WiMAX."</string>
+ <string name="accessibility_wimax_signal_full" msgid="2768089986795579558">"Моцны сiгнал WiMAX."</string>
<string name="accessibility_data_connection_gprs" msgid="1606477224486747751">"GPRS"</string>
<string name="accessibility_data_connection_3g" msgid="8628562305003568260">"3G"</string>
<string name="accessibility_data_connection_3.5g" msgid="8664845609981692001">"3.5G"</string>
@@ -135,4 +140,5 @@
<string name="gps_notification_searching_text" msgid="8574247005642736060">"Пошук GPS"</string>
<string name="gps_notification_found_text" msgid="4619274244146446464">"Месца задана праз GPS"</string>
<string name="accessibility_clear_all" msgid="5235938559247164925">"Выдалiць усе апавяшчэннi."</string>
+ <string name="dreams_dock_launcher" msgid="3541196417659166245">"Актывацыя экраннай застаўкі"</string>
</resources>
diff --git a/packages/SystemUI/res/values-de/strings.xml b/packages/SystemUI/res/values-de/strings.xml
index e84f40f..ab4eeb4 100644
--- a/packages/SystemUI/res/values-de/strings.xml
+++ b/packages/SystemUI/res/values-de/strings.xml
@@ -133,7 +133,7 @@
<string name="data_usage_disabled_dialog_4g_title" msgid="4789143363492682629">"4G-Daten deaktiviert"</string>
<string name="data_usage_disabled_dialog_mobile_title" msgid="1046047248844821202">"Mobile Daten deaktiviert"</string>
<string name="data_usage_disabled_dialog_title" msgid="2086815304858964954">"Daten deaktiviert"</string>
- <string name="data_usage_disabled_dialog" msgid="3853117269051806280">"Sie haben die angegebenen Grenze für die Datennutzung erreicht."\n\n"Wenn Sie die Datennutzung erneut aktivieren, berechnet Ihr Mobilfunkanbieter unter Umständen zusätzliche Gebühren."</string>
+ <string name="data_usage_disabled_dialog" msgid="3853117269051806280">"Sie haben die angegebenen Grenze für den Datenverbrauch erreicht."\n\n"Wenn Sie die Datennutzung erneut aktivieren, berechnet Ihr Mobilfunkanbieter unter Umständen zusätzliche Gebühren."</string>
<string name="data_usage_disabled_dialog_enable" msgid="7729772039208664606">"Daten erneut aktivieren"</string>
<string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Keine Internetverbindung"</string>
<string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"WLAN verbunden"</string>
diff --git a/packages/SystemUI/res/values-es-rUS-large/strings.xml b/packages/SystemUI/res/values-es-rUS-large/strings.xml
index 3f96e87..dd44b28 100644
--- a/packages/SystemUI/res/values-es-rUS-large/strings.xml
+++ b/packages/SystemUI/res/values-es-rUS-large/strings.xml
@@ -19,7 +19,7 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="status_bar_clear_all_button" msgid="4661583896803349732">"Borrar todas"</string>
+ <string name="status_bar_clear_all_button" msgid="4661583896803349732">"Eliminar todas"</string>
<string name="notifications_off_title" msgid="1860117696034775851">"Notificaciones desactivadas"</string>
<string name="notifications_off_text" msgid="1439152806320786912">"Toca aquí para volver a activar las notificaciones."</string>
</resources>
diff --git a/packages/SystemUI/res/values-es-rUS/strings.xml b/packages/SystemUI/res/values-es-rUS/strings.xml
index 85818ae..a700908 100644
--- a/packages/SystemUI/res/values-es-rUS/strings.xml
+++ b/packages/SystemUI/res/values-es-rUS/strings.xml
@@ -20,7 +20,7 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="7164937344850004466">"IU del sistema"</string>
- <string name="status_bar_clear_all_button" msgid="7774721344716731603">"Borrar"</string>
+ <string name="status_bar_clear_all_button" msgid="7774721344716731603">"Eliminar"</string>
<string name="status_bar_do_not_disturb_button" msgid="5812628897510997853">"No molestar"</string>
<string name="status_bar_please_disturb_button" msgid="3345398298841572813">"Mostrar notificaciones"</string>
<string name="status_bar_recent_remove_item_title" msgid="6026395868129852968">"Eliminar de la lista"</string>
@@ -122,7 +122,7 @@
<skip />
<string name="accessibility_settings_button" msgid="799583911231893380">"Configuración del sistema"</string>
<string name="accessibility_notifications_button" msgid="4498000369779421892">"Notificaciones"</string>
- <string name="accessibility_remove_notification" msgid="3603099514902182350">"Borrar notificación"</string>
+ <string name="accessibility_remove_notification" msgid="3603099514902182350">"Eliminar notificación"</string>
<string name="accessibility_gps_enabled" msgid="3511469499240123019">"GPS habilitado"</string>
<string name="accessibility_gps_acquiring" msgid="8959333351058967158">"Adquisición de GPS"</string>
<string name="accessibility_tty_enabled" msgid="4613200365379426561">"TeleTypewriter habilitado"</string>
@@ -133,12 +133,12 @@
<string name="data_usage_disabled_dialog_4g_title" msgid="4789143363492682629">"Datos de 4G inhabilitados"</string>
<string name="data_usage_disabled_dialog_mobile_title" msgid="1046047248844821202">"Se inhabilitaron los datos móviles"</string>
<string name="data_usage_disabled_dialog_title" msgid="2086815304858964954">"Datos inhabilitados"</string>
- <string name="data_usage_disabled_dialog" msgid="3853117269051806280">"Alcanzaste el límite de uso de datos especificado."\n\n"Puede que tu operador te cobre por volver a habilitar datos."</string>
- <string name="data_usage_disabled_dialog_enable" msgid="7729772039208664606">"Volver a habilitar datos"</string>
+ <string name="data_usage_disabled_dialog" msgid="3853117269051806280">"Alcanzaste el límite de uso de datos especificado."\n\n"Puede que tu operador te cobre por volver a activar datos."</string>
+ <string name="data_usage_disabled_dialog_enable" msgid="7729772039208664606">"Volver a activar datos"</string>
<string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Sin conexión a Internet"</string>
<string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi conectado"</string>
<string name="gps_notification_searching_text" msgid="8574247005642736060">"Buscando GPS"</string>
<string name="gps_notification_found_text" msgid="4619274244146446464">"La ubicación se estableció por GPS"</string>
- <string name="accessibility_clear_all" msgid="5235938559247164925">"Borrar todas las notificaciones"</string>
+ <string name="accessibility_clear_all" msgid="5235938559247164925">"Eliminar todas las notificaciones"</string>
<string name="dreams_dock_launcher" msgid="3541196417659166245">"Activar el protector de pantalla"</string>
</resources>
diff --git a/packages/SystemUI/res/values-et/strings.xml b/packages/SystemUI/res/values-et/strings.xml
index 943b8ca..a5bfb4a 100644
--- a/packages/SystemUI/res/values-et/strings.xml
+++ b/packages/SystemUI/res/values-et/strings.xml
@@ -101,7 +101,12 @@
<string name="accessibility_wifi_one_bar" msgid="6854947280074467207">"WiFi signaal: üks post."</string>
<string name="accessibility_wifi_two_bars" msgid="3344340012058984348">"WiFi signaal: kaks posti."</string>
<string name="accessibility_wifi_three_bars" msgid="928322805193265041">"WiFi signaal: kolm posti."</string>
- <string name="accessibility_wifi_signal_full" msgid="4826278754383492058">"WiFi signaal on täis."</string>
+ <string name="accessibility_wifi_signal_full" msgid="1275764416228473932">"WiFi-signaal on tugev."</string>
+ <string name="accessibility_no_wimax" msgid="4329180129727630368">"WiMAX-i pole."</string>
+ <string name="accessibility_wimax_one_bar" msgid="4170994299011863648">"WiMAX-i on üks riba."</string>
+ <string name="accessibility_wimax_two_bars" msgid="9176236858336502288">"WiMAX-i on kaks riba."</string>
+ <string name="accessibility_wimax_three_bars" msgid="6116551636752103927">"WiMAX-i on kolm riba."</string>
+ <string name="accessibility_wimax_signal_full" msgid="2768089986795579558">"WiMAX-i signaal on tugev."</string>
<string name="accessibility_data_connection_gprs" msgid="1606477224486747751">"GPRS"</string>
<string name="accessibility_data_connection_3g" msgid="8628562305003568260">"3G"</string>
<string name="accessibility_data_connection_3.5g" msgid="8664845609981692001">"3,5G"</string>
@@ -133,4 +138,5 @@
<string name="gps_notification_searching_text" msgid="8574247005642736060">"GPS-i otsimine"</string>
<string name="gps_notification_found_text" msgid="4619274244146446464">"GPS-i määratud asukoht"</string>
<string name="accessibility_clear_all" msgid="5235938559247164925">"Kustuta kõik teatised."</string>
+ <string name="dreams_dock_launcher" msgid="3541196417659166245">"Aktiveeri ekraanisäästja"</string>
</resources>
diff --git a/packages/SystemUI/res/values-pt/strings.xml b/packages/SystemUI/res/values-pt/strings.xml
index 545d54e..dec4def 100644
--- a/packages/SystemUI/res/values-pt/strings.xml
+++ b/packages/SystemUI/res/values-pt/strings.xml
@@ -115,7 +115,7 @@
<string name="accessibility_data_connection_edge" msgid="4477457051631979278">"Edge"</string>
<string name="accessibility_data_connection_wifi" msgid="2324496756590645221">"Wi-Fi"</string>
<string name="accessibility_no_sim" msgid="8274017118472455155">"Sem SIM."</string>
- <string name="accessibility_bluetooth_tether" msgid="4102784498140271969">"Vínculo Bluetooth."</string>
+ <string name="accessibility_bluetooth_tether" msgid="4102784498140271969">"Tethering Bluetooth."</string>
<string name="accessibility_airplane_mode" msgid="834748999790763092">"Modo de avião."</string>
<!-- String.format failed for translation -->
<!-- no translation found for accessibility_battery_level (7451474187113371965) -->
diff --git a/packages/SystemUI/res/values-rm/strings.xml b/packages/SystemUI/res/values-rm/strings.xml
index 2106b89..983df47 100644
--- a/packages/SystemUI/res/values-rm/strings.xml
+++ b/packages/SystemUI/res/values-rm/strings.xml
@@ -39,8 +39,10 @@
<string name="status_bar_no_notifications_title" msgid="4755261167193833213">"Nagins avis"</string>
<string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"Actual"</string>
<string name="status_bar_latest_events_title" msgid="6594767438577593172">"Avis"</string>
- <!-- outdated translation 7923774589611311406 --> <string name="battery_low_title" msgid="2783104807551211639">"Connectar il chargiabattarias"</string>
- <!-- outdated translation 7388781709819722764 --> <string name="battery_low_subtitle" msgid="1752040062087829196">"L\'accu è prest vid."</string>
+ <!-- no translation found for battery_low_title (2783104807551211639) -->
+ <skip />
+ <!-- no translation found for battery_low_subtitle (1752040062087829196) -->
+ <skip />
<!-- no translation found for battery_low_percent_format (1077244949318261761) -->
<skip />
<!-- no translation found for invalid_charger (4549105996740522523) -->
diff --git a/packages/SystemUI/res/values-ru/strings.xml b/packages/SystemUI/res/values-ru/strings.xml
index 17330b1..963976d 100644
--- a/packages/SystemUI/res/values-ru/strings.xml
+++ b/packages/SystemUI/res/values-ru/strings.xml
@@ -36,7 +36,7 @@
<string name="status_bar_latest_events_title" msgid="6594767438577593172">"Уведомления"</string>
<string name="battery_low_title" msgid="2783104807551211639">"Подключите зарядное устройство"</string>
<string name="battery_low_subtitle" msgid="1752040062087829196">"Батарея разряжена."</string>
- <string name="battery_low_percent_format" msgid="1077244949318261761">"Осталось: <xliff:g id="NUMBER">%d%%</xliff:g>"</string>
+ <string name="battery_low_percent_format" msgid="1077244949318261761">"Осталось <xliff:g id="NUMBER">%d%%</xliff:g>"</string>
<string name="invalid_charger" msgid="4549105996740522523">"Зарядка через порт USB не поддерживается."\n"Используйте только зарядное устройство из комплекта поставки."</string>
<string name="battery_low_why" msgid="7279169609518386372">"Расход заряда батареи"</string>
<string name="status_bar_settings_settings_button" msgid="3023889916699270224">"Настройки"</string>
diff --git a/packages/SystemUI/res/values-sw/strings.xml b/packages/SystemUI/res/values-sw/strings.xml
index 3843ea9..70e29eb 100644
--- a/packages/SystemUI/res/values-sw/strings.xml
+++ b/packages/SystemUI/res/values-sw/strings.xml
@@ -26,7 +26,7 @@
<string name="status_bar_recent_remove_item_title" msgid="6026395868129852968">"Ondoa kwenye orodha"</string>
<string name="status_bar_recent_inspect_item_title" msgid="7793624864528818569">"Taarifa za programu-matumizi"</string>
<string name="status_bar_no_recent_apps" msgid="6576392951053994640">"Hakuna programu za sasa"</string>
- <string name="status_bar_accessibility_dismiss_recents" msgid="4576076075226540105">"Ondosha programu za hivi karibuni"</string>
+ <string name="status_bar_accessibility_dismiss_recents" msgid="4576076075226540105">"Ondosha prog za hivi karibuni"</string>
<!-- String.format failed for translation -->
<!-- no translation found for status_bar_accessibility_recent_apps:other (1040784359794890744) -->
<string name="status_bar_no_notifications_title" msgid="4755261167193833213">"Hakuna arifa"</string>
diff --git a/packages/SystemUI/src/com/android/systemui/net/NetworkOverLimitActivity.java b/packages/SystemUI/src/com/android/systemui/net/NetworkOverLimitActivity.java
index 723e338..888b76e 100644
--- a/packages/SystemUI/src/com/android/systemui/net/NetworkOverLimitActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/net/NetworkOverLimitActivity.java
@@ -77,7 +77,7 @@
final INetworkPolicyManager policyService = INetworkPolicyManager.Stub.asInterface(
ServiceManager.getService(Context.NETWORK_POLICY_SERVICE));
try {
- policyService.snoozePolicy(template);
+ policyService.snoozeLimit(template);
} catch (RemoteException e) {
Slog.w(TAG, "problem snoozing network policy", e);
}
diff --git a/packages/SystemUI/src/com/android/systemui/recent/RecentTasksLoader.java b/packages/SystemUI/src/com/android/systemui/recent/RecentTasksLoader.java
index dcda9c2..4145fc4 100644
--- a/packages/SystemUI/src/com/android/systemui/recent/RecentTasksLoader.java
+++ b/packages/SystemUI/src/com/android/systemui/recent/RecentTasksLoader.java
@@ -68,22 +68,13 @@
// get the icon size we want -- on tablets, we use bigger icons
boolean isTablet = res.getBoolean(R.bool.config_recents_interface_for_tablets);
- int density = res.getDisplayMetrics().densityDpi;
if (isTablet) {
- if (density == DisplayMetrics.DENSITY_LOW) {
- mIconDpi = DisplayMetrics.DENSITY_MEDIUM;
- } else if (density == DisplayMetrics.DENSITY_MEDIUM) {
- mIconDpi = DisplayMetrics.DENSITY_HIGH;
- } else if (density == DisplayMetrics.DENSITY_HIGH) {
- mIconDpi = DisplayMetrics.DENSITY_XHIGH;
- } else if (density == DisplayMetrics.DENSITY_XHIGH) {
- // We'll need to use a denser icon, or some sort of a mipmap
- mIconDpi = DisplayMetrics.DENSITY_XHIGH;
- }
+ ActivityManager activityManager =
+ (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
+ mIconDpi = activityManager.getLauncherLargeIconDensity();
} else {
mIconDpi = res.getDisplayMetrics().densityDpi;
}
- mIconDpi = isTablet ? DisplayMetrics.DENSITY_HIGH : res.getDisplayMetrics().densityDpi;
// Render the default thumbnail background
int width = (int) res.getDimensionPixelSize(com.android.internal.R.dimen.thumbnail_width);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
index 69a247d..d33ed3f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
@@ -23,6 +23,8 @@
import android.content.Context;
import android.content.res.Resources;
import android.graphics.Rect;
+import android.os.Handler;
+import android.os.Message;
import android.os.ServiceManager;
import android.util.AttributeSet;
import android.util.Slog;
@@ -66,6 +68,35 @@
int mDisabledFlags = 0;
int mNavigationIconHints = 0;
+ // workaround for LayoutTransitions leaving the nav buttons in a weird state (bug 5549288)
+ final static boolean WORKAROUND_INVALID_LAYOUT = true;
+ final static int MSG_CHECK_INVALID_LAYOUT = 8686;
+
+ private class H extends Handler {
+ public void handleMessage(Message m) {
+ switch (m.what) {
+ case MSG_CHECK_INVALID_LAYOUT:
+ final String how = "" + m.obj;
+ final int w = getWidth();
+ final int h = getHeight();
+ final int vw = mCurrentView.getWidth();
+ final int vh = mCurrentView.getHeight();
+
+ if (h != vh || w != vw) {
+ Slog.w(TAG, String.format(
+ "*** Invalid layout in navigation bar (%s this=%dx%d cur=%dx%d)",
+ how, w, h, vw, vh));
+ if (WORKAROUND_INVALID_LAYOUT) {
+ requestLayout();
+ }
+ }
+ break;
+ }
+ }
+ }
+
+ private H mHandler = new H();
+
public View getRecentsButton() {
return mCurrentView.findViewById(R.id.recent_apps);
}
@@ -275,6 +306,36 @@
}
}
+ @Override
+ protected void onSizeChanged(int w, int h, int oldw, int oldh) {
+ if (DEBUG) Slog.d(TAG, String.format(
+ "onSizeChanged: (%dx%d) old: (%dx%d)", w, h, oldw, oldh));
+ postCheckForInvalidLayout("sizeChanged");
+ super.onSizeChanged(w, h, oldw, oldh);
+ }
+
+ /*
+ @Override
+ protected void onLayout (boolean changed, int left, int top, int right, int bottom) {
+ if (DEBUG) Slog.d(TAG, String.format(
+ "onLayout: %s (%d,%d,%d,%d)",
+ changed?"changed":"notchanged", left, top, right, bottom));
+ super.onLayout(changed, left, top, right, bottom);
+ }
+
+ // uncomment this for extra defensiveness in WORKAROUND_INVALID_LAYOUT situations: if all else
+ // fails, any touch on the display will fix the layout.
+ @Override
+ public boolean onInterceptTouchEvent(MotionEvent ev) {
+ if (DEBUG) Slog.d(TAG, "onInterceptTouchEvent: " + ev.toString());
+ if (ev.getAction() == MotionEvent.ACTION_DOWN) {
+ postCheckForInvalidLayout("touch");
+ }
+ return super.onInterceptTouchEvent(ev);
+ }
+ */
+
+
private String getResourceName(int resId) {
if (resId != 0) {
final android.content.res.Resources res = mContext.getResources();
@@ -288,6 +349,10 @@
}
}
+ private void postCheckForInvalidLayout(final String how) {
+ mHandler.obtainMessage(MSG_CHECK_INVALID_LAYOUT, 0, 0, how).sendToTarget();
+ }
+
private static String visibilityToString(int vis) {
switch (vis) {
case View.INVISIBLE:
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonView.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonView.java
index 975c372..cc07240 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonView.java
@@ -55,6 +55,7 @@
float mGlowAlpha = 0f, mGlowScale = 1f, mDrawingAlpha = 1f;
boolean mSupportsLongpress = true;
RectF mRect = new RectF(0f,0f,0f,0f);
+ AnimatorSet mPressedAnim;
Runnable mCheckLongPress = new Runnable() {
public void run() {
@@ -173,7 +174,10 @@
public void setPressed(boolean pressed) {
if (mGlowBG != null) {
if (pressed != isPressed()) {
- AnimatorSet as = new AnimatorSet();
+ if (mPressedAnim != null && mPressedAnim.isRunning()) {
+ mPressedAnim.cancel();
+ }
+ final AnimatorSet as = mPressedAnim = new AnimatorSet();
if (pressed) {
if (mGlowScale < GLOW_MAX_SCALE_FACTOR)
mGlowScale = GLOW_MAX_SCALE_FACTOR;
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 d9114a5..d787e10 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkController.java
@@ -457,13 +457,13 @@
private final void updateTelephonySignalStrength() {
if (!hasService()) {
if (CHATTY) Slog.d(TAG, "updateTelephonySignalStrength: !hasService()");
- mPhoneSignalIconId = R.drawable.stat_sys_signal_0;
- mDataSignalIconId = R.drawable.stat_sys_signal_0;
+ mPhoneSignalIconId = R.drawable.stat_sys_signal_null;
+ mDataSignalIconId = R.drawable.stat_sys_signal_null;
} else {
if (mSignalStrength == null) {
if (CHATTY) Slog.d(TAG, "updateTelephonySignalStrength: mSignalStrength == null");
- mPhoneSignalIconId = R.drawable.stat_sys_signal_0;
- mDataSignalIconId = R.drawable.stat_sys_signal_0;
+ mPhoneSignalIconId = R.drawable.stat_sys_signal_null;
+ mDataSignalIconId = R.drawable.stat_sys_signal_null;
mContentDescriptionPhoneSignal = mContext.getString(
AccessibilityContentDescriptions.PHONE_SIGNAL_STRENGTH[0]);
} else {
@@ -588,8 +588,12 @@
}
}
- if ((isCdma() && isCdmaEri()) || mPhone.isNetworkRoaming()) {
- mDataTypeIconId = R.drawable.stat_sys_data_connected_roam;
+ if (isCdma()) {
+ if (isCdmaEri()) {
+ mDataTypeIconId = R.drawable.stat_sys_data_connected_roam;
+ }
+ } else if (mPhone.isNetworkRoaming()) {
+ mDataTypeIconId = R.drawable.stat_sys_data_connected_roam;
}
}
@@ -850,8 +854,10 @@
Slog.d(TAG, "updateConnectivity: intent=" + intent);
}
- NetworkInfo info = (NetworkInfo)(intent.getParcelableExtra(
- ConnectivityManager.EXTRA_NETWORK_INFO));
+ final ConnectivityManager connManager = (ConnectivityManager) mContext
+ .getSystemService(Context.CONNECTIVITY_SERVICE);
+ final NetworkInfo info = connManager.getActiveNetworkInfo();
+
int connectionStatus = intent.getIntExtra(ConnectivityManager.EXTRA_INET_CONDITION, 0);
if (CHATTY) {
@@ -888,31 +894,53 @@
String mobileLabel = "";
int N;
- if (mDataConnected) {
- mobileLabel = mNetworkName;
- if (DEBUG) {
- mobileLabel += "yyyyYYYYyyyyYYYY";
- }
- combinedSignalIconId = mDataSignalIconId;
- switch (mDataActivity) {
- case TelephonyManager.DATA_ACTIVITY_IN:
- mMobileActivityIconId = R.drawable.stat_sys_signal_in;
- break;
- case TelephonyManager.DATA_ACTIVITY_OUT:
- mMobileActivityIconId = R.drawable.stat_sys_signal_out;
- break;
- case TelephonyManager.DATA_ACTIVITY_INOUT:
- mMobileActivityIconId = R.drawable.stat_sys_signal_inout;
- break;
- default:
- mMobileActivityIconId = 0;
- break;
+ if (!mHasMobileDataFeature) {
+ mDataSignalIconId = mPhoneSignalIconId = 0;
+ mobileLabel = "";
+ } else {
+ // We want to show the carrier name if in service and either:
+ // - We are connected to mobile data, or
+ // - We are not connected to mobile data, as long as the *reason* packets are not
+ // being routed over that link is that we have better connectivity via wifi.
+ // If data is disconnected for some other reason but wifi is connected, we show nothing.
+ // Otherwise (nothing connected) we show "No internet connection".
+
+ if (mDataConnected) {
+ mobileLabel = mNetworkName;
+ } else if (mWifiConnected) {
+ if (hasService()) {
+ mobileLabel = mNetworkName;
+ } else {
+ mobileLabel = "";
+ }
+ } else {
+ mobileLabel
+ = context.getString(R.string.status_bar_settings_signal_meter_disconnected);
}
- combinedLabel = mobileLabel;
- combinedActivityIconId = mMobileActivityIconId;
- combinedSignalIconId = mDataSignalIconId; // set by updateDataIcon()
- mContentDescriptionCombinedSignal = mContentDescriptionDataType;
+ // Now for things that should only be shown when actually using mobile data.
+ if (mDataConnected) {
+ combinedSignalIconId = mDataSignalIconId;
+ switch (mDataActivity) {
+ case TelephonyManager.DATA_ACTIVITY_IN:
+ mMobileActivityIconId = R.drawable.stat_sys_signal_in;
+ break;
+ case TelephonyManager.DATA_ACTIVITY_OUT:
+ mMobileActivityIconId = R.drawable.stat_sys_signal_out;
+ break;
+ case TelephonyManager.DATA_ACTIVITY_INOUT:
+ mMobileActivityIconId = R.drawable.stat_sys_signal_inout;
+ break;
+ default:
+ mMobileActivityIconId = 0;
+ break;
+ }
+
+ combinedLabel = mobileLabel;
+ combinedActivityIconId = mMobileActivityIconId;
+ combinedSignalIconId = mDataSignalIconId; // set by updateDataIcon()
+ mContentDescriptionCombinedSignal = mContentDescriptionDataType;
+ }
}
if (mWifiConnected) {
@@ -944,6 +972,12 @@
combinedLabel = wifiLabel;
combinedSignalIconId = mWifiIconId; // set by updateWifiIcons()
mContentDescriptionCombinedSignal = mContentDescriptionWifi;
+ } else {
+ if (mHasMobileDataFeature) {
+ wifiLabel = "";
+ } else {
+ wifiLabel = context.getString(R.string.status_bar_settings_signal_meter_disconnected);
+ }
}
if (mBluetoothTethered) {
@@ -964,9 +998,17 @@
mDataTypeIconId = 0;
// combined values from connected wifi take precedence over airplane mode
- if (!mWifiConnected) {
- wifiLabel = context.getString(R.string.status_bar_settings_signal_meter_disconnected);
- combinedLabel = wifiLabel;
+ if (mWifiConnected) {
+ // Suppress "No internet connection." from mobile if wifi connected.
+ mobileLabel = "";
+ } else {
+ if (mHasMobileDataFeature) {
+ // let the mobile icon show "No internet connection."
+ wifiLabel = "";
+ } else {
+ wifiLabel = context.getString(R.string.status_bar_settings_signal_meter_disconnected);
+ combinedLabel = wifiLabel;
+ }
mContentDescriptionCombinedSignal = mContentDescriptionPhoneSignal;
combinedSignalIconId = mDataSignalIconId;
}
@@ -981,10 +1023,13 @@
mContentDescriptionCombinedSignal = mHasMobileDataFeature
? mContentDescriptionDataType : mContentDescriptionWifi;
- if ((isCdma() && isCdmaEri()) || mPhone.isNetworkRoaming()) {
+ mDataTypeIconId = 0;
+ if (isCdma()) {
+ if (isCdmaEri()) {
+ mDataTypeIconId = R.drawable.stat_sys_data_connected_roam;
+ }
+ } else if (mPhone.isNetworkRoaming()) {
mDataTypeIconId = R.drawable.stat_sys_data_connected_roam;
- } else {
- mDataTypeIconId = 0;
}
}
@@ -1026,8 +1071,13 @@
N = mPhoneSignalIconViews.size();
for (int i=0; i<N; i++) {
final ImageView v = mPhoneSignalIconViews.get(i);
- v.setImageResource(mPhoneSignalIconId);
- v.setContentDescription(mContentDescriptionPhoneSignal);
+ if (mPhoneSignalIconId == 0) {
+ v.setVisibility(View.GONE);
+ } else {
+ v.setVisibility(View.VISIBLE);
+ v.setImageResource(mPhoneSignalIconId);
+ v.setContentDescription(mContentDescriptionPhoneSignal);
+ }
}
}
@@ -1133,14 +1183,24 @@
N = mWifiLabelViews.size();
for (int i=0; i<N; i++) {
TextView v = mWifiLabelViews.get(i);
- v.setText(wifiLabel);
+ if ("".equals(wifiLabel)) {
+ v.setVisibility(View.GONE);
+ } else {
+ v.setVisibility(View.VISIBLE);
+ v.setText(wifiLabel);
+ }
}
// mobile label
N = mMobileLabelViews.size();
for (int i=0; i<N; i++) {
TextView v = mMobileLabelViews.get(i);
- v.setText(mobileLabel);
+ if ("".equals(mobileLabel)) {
+ v.setVisibility(View.GONE);
+ } else {
+ v.setVisibility(View.VISIBLE);
+ v.setText(mobileLabel);
+ }
}
}
diff --git a/packages/VpnDialogs/AndroidManifest.xml b/packages/VpnDialogs/AndroidManifest.xml
index 8e062b7..46c0f83 100644
--- a/packages/VpnDialogs/AndroidManifest.xml
+++ b/packages/VpnDialogs/AndroidManifest.xml
@@ -5,7 +5,7 @@
<application android:label="VpnDialogs"
android:allowBackup="false" >
<activity android:name=".ConfirmDialog"
- android:theme="@style/transparent">
+ android:theme="@*android:style/Theme.Holo.Dialog.Alert">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.DEFAULT"/>
@@ -13,7 +13,7 @@
</activity>
<activity android:name=".ManageDialog"
- android:theme="@style/transparent"
+ android:theme="@*android:style/Theme.Holo.Dialog.Alert"
android:noHistory="true">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
diff --git a/packages/VpnDialogs/res/values/styles.xml b/packages/VpnDialogs/res/values/styles.xml
index cf10596..e3469ec 100644
--- a/packages/VpnDialogs/res/values/styles.xml
+++ b/packages/VpnDialogs/res/values/styles.xml
@@ -15,13 +15,6 @@
-->
<resources>
-
- <style name="transparent">
- <item name="android:windowBackground">@android:color/transparent</item>
- <item name="android:windowNoTitle">true</item>
- <item name="android:windowIsFloating">true</item>
- </style>
-
<style name="label">
<item name="android:gravity">center_vertical|right</item>
<item name="android:paddingRight">2mm</item>
diff --git a/packages/VpnDialogs/src/com/android/vpndialogs/ConfirmDialog.java b/packages/VpnDialogs/src/com/android/vpndialogs/ConfirmDialog.java
index c7b4a5f..13d8019 100644
--- a/packages/VpnDialogs/src/com/android/vpndialogs/ConfirmDialog.java
+++ b/packages/VpnDialogs/src/com/android/vpndialogs/ConfirmDialog.java
@@ -16,8 +16,6 @@
package com.android.vpndialogs;
-import android.app.Activity;
-import android.app.AlertDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
@@ -32,15 +30,16 @@
import android.widget.ImageView;
import android.widget.TextView;
-public class ConfirmDialog extends Activity implements CompoundButton.OnCheckedChangeListener,
- DialogInterface.OnClickListener, DialogInterface.OnDismissListener {
+import com.android.internal.app.AlertActivity;
+
+public class ConfirmDialog extends AlertActivity implements
+ CompoundButton.OnCheckedChangeListener, DialogInterface.OnClickListener {
private static final String TAG = "VpnConfirm";
private String mPackage;
private IConnectivityManager mService;
- private AlertDialog mDialog;
private Button mButton;
@Override
@@ -67,18 +66,17 @@
getString(R.string.prompt, app.loadLabel(pm)));
((CompoundButton) view.findViewById(R.id.check)).setOnCheckedChangeListener(this);
- mDialog = new AlertDialog.Builder(this)
- .setIcon(android.R.drawable.ic_dialog_alert)
- .setTitle(android.R.string.dialog_alert_title)
- .setView(view)
- .setPositiveButton(android.R.string.ok, this)
- .setNegativeButton(android.R.string.cancel, this)
- .setCancelable(false)
- .create();
- mDialog.setOnDismissListener(this);
- mDialog.show();
+ mAlertParams.mIconId = android.R.drawable.ic_dialog_alert;
+ mAlertParams.mTitle = getText(android.R.string.dialog_alert_title);
+ mAlertParams.mPositiveButtonText = getText(android.R.string.ok);
+ mAlertParams.mPositiveButtonListener = this;
+ mAlertParams.mNegativeButtonText = getText(android.R.string.cancel);
+ mAlertParams.mNegativeButtonListener = this;
+ mAlertParams.mView = view;
+ setupAlert();
- mButton = mDialog.getButton(DialogInterface.BUTTON_POSITIVE);
+ getWindow().setCloseOnTouchOutside(false);
+ mButton = mAlert.getButton(DialogInterface.BUTTON_POSITIVE);
mButton.setEnabled(false);
} catch (Exception e) {
Log.e(TAG, "onResume", e);
@@ -87,12 +85,7 @@
}
@Override
- protected void onPause() {
- super.onPause();
- if (mDialog != null) {
- mDialog.setOnDismissListener(null);
- mDialog.dismiss();
- }
+ public void onBackPressed() {
}
@Override
@@ -103,16 +96,11 @@
@Override
public void onClick(DialogInterface dialog, int which) {
try {
- if (which == AlertDialog.BUTTON_POSITIVE && mService.prepareVpn(null, mPackage)) {
+ if (which == DialogInterface.BUTTON_POSITIVE && mService.prepareVpn(null, mPackage)) {
setResult(RESULT_OK);
}
} catch (Exception e) {
Log.e(TAG, "onClick", e);
}
}
-
- @Override
- public void onDismiss(DialogInterface dialog) {
- finish();
- }
}
diff --git a/packages/VpnDialogs/src/com/android/vpndialogs/ManageDialog.java b/packages/VpnDialogs/src/com/android/vpndialogs/ManageDialog.java
index 7fb1417..2de0251 100644
--- a/packages/VpnDialogs/src/com/android/vpndialogs/ManageDialog.java
+++ b/packages/VpnDialogs/src/com/android/vpndialogs/ManageDialog.java
@@ -16,8 +16,6 @@
package com.android.vpndialogs;
-import android.app.Activity;
-import android.app.AlertDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
@@ -35,20 +33,20 @@
import android.widget.ImageView;
import android.widget.TextView;
+import com.android.internal.app.AlertActivity;
import com.android.internal.net.VpnConfig;
import java.io.DataInputStream;
import java.io.FileInputStream;
-public class ManageDialog extends Activity implements Handler.Callback,
- DialogInterface.OnClickListener, DialogInterface.OnDismissListener {
+public class ManageDialog extends AlertActivity implements
+ DialogInterface.OnClickListener, Handler.Callback {
private static final String TAG = "VpnManage";
private VpnConfig mConfig;
private IConnectivityManager mService;
- private AlertDialog mDialog;
private TextView mDuration;
private TextView mDataTransmitted;
private TextView mDataReceived;
@@ -80,31 +78,24 @@
mDataReceived = (TextView) view.findViewById(R.id.data_received);
if (mConfig.user.equals(VpnConfig.LEGACY_VPN)) {
- mDialog = new AlertDialog.Builder(this)
- .setIcon(android.R.drawable.ic_dialog_info)
- .setTitle(R.string.legacy_title)
- .setView(view)
- .setNeutralButton(R.string.disconnect, this)
- .setNegativeButton(android.R.string.cancel, this)
- .create();
+ mAlertParams.mIconId = android.R.drawable.ic_dialog_info;
+ mAlertParams.mTitle = getText(R.string.legacy_title);
} else {
PackageManager pm = getPackageManager();
ApplicationInfo app = pm.getApplicationInfo(mConfig.user, 0);
- mDialog = new AlertDialog.Builder(this)
- .setIcon(app.loadIcon(pm))
- .setTitle(app.loadLabel(pm))
- .setView(view)
- .setNeutralButton(R.string.disconnect, this)
- .setNegativeButton(android.R.string.cancel, this)
- .create();
+ mAlertParams.mIcon = app.loadIcon(pm);
+ mAlertParams.mTitle = app.loadLabel(pm);
}
-
if (mConfig.configureIntent != null) {
- mDialog.setButton(DialogInterface.BUTTON_POSITIVE,
- getText(R.string.configure), this);
+ mAlertParams.mPositiveButtonText = getText(R.string.configure);
+ mAlertParams.mPositiveButtonListener = this;
}
- mDialog.setOnDismissListener(this);
- mDialog.show();
+ mAlertParams.mNeutralButtonText = getText(R.string.disconnect);
+ mAlertParams.mNeutralButtonListener = this;
+ mAlertParams.mNegativeButtonText = getText(android.R.string.cancel);
+ mAlertParams.mNegativeButtonListener = this;
+ mAlertParams.mView = view;
+ setupAlert();
if (mHandler == null) {
mHandler = new Handler(this);
@@ -119,18 +110,17 @@
@Override
protected void onPause() {
super.onPause();
- if (mDialog != null) {
- mDialog.setOnDismissListener(null);
- mDialog.dismiss();
+ if (!isFinishing()) {
+ finish();
}
}
@Override
public void onClick(DialogInterface dialog, int which) {
try {
- if (which == AlertDialog.BUTTON_POSITIVE) {
+ if (which == DialogInterface.BUTTON_POSITIVE) {
mConfig.configureIntent.send();
- } else if (which == AlertDialog.BUTTON_NEUTRAL) {
+ } else if (which == DialogInterface.BUTTON_NEUTRAL) {
mService.prepareVpn(mConfig.user, VpnConfig.LEGACY_VPN);
}
} catch (Exception e) {
@@ -140,15 +130,10 @@
}
@Override
- public void onDismiss(DialogInterface dialog) {
- finish();
- }
-
- @Override
public boolean handleMessage(Message message) {
mHandler.removeMessages(0);
- if (mDialog.isShowing()) {
+ if (!isFinishing()) {
if (mConfig.startTime != 0) {
long seconds = (SystemClock.elapsedRealtime() - mConfig.startTime) / 1000;
mDuration.setText(String.format("%02d:%02d:%02d",
diff --git a/policy/src/com/android/internal/policy/impl/KeyguardStatusViewManager.java b/policy/src/com/android/internal/policy/impl/KeyguardStatusViewManager.java
index f45556f..9f3de69 100644
--- a/policy/src/com/android/internal/policy/impl/KeyguardStatusViewManager.java
+++ b/policy/src/com/android/internal/policy/impl/KeyguardStatusViewManager.java
@@ -19,6 +19,7 @@
import com.android.internal.R;
import com.android.internal.telephony.IccCard;
import com.android.internal.telephony.IccCard.State;
+import com.android.internal.widget.DigitalClock;
import com.android.internal.widget.LockPatternUtils;
import com.android.internal.widget.TransportControlView;
import com.android.internal.policy.impl.KeyguardUpdateMonitor.SimStateCallback;
@@ -105,6 +106,7 @@
private CharSequence mPlmn;
private CharSequence mSpn;
protected int mPhoneState;
+ private DigitalClock mDigitalClock;
private class TransientTextManager {
private TextView mTextView;
@@ -181,6 +183,7 @@
mTransportView = (TransportControlView) findViewById(R.id.transport);
mEmergencyCallButton = (Button) findViewById(R.id.emergencyCallButton);
mEmergencyCallButtonEnabledInScreen = emergencyButtonEnabledInScreen;
+ mDigitalClock = (DigitalClock) findViewById(R.id.time);
// Hide transport control view until we know we need to show it.
if (mTransportView != null) {
@@ -290,6 +293,12 @@
/** {@inheritDoc} */
public void onResume() {
if (DEBUG) Log.v(TAG, "onResume()");
+
+ // First update the clock, if present.
+ if (mDigitalClock != null) {
+ mDigitalClock.updateTime();
+ }
+
mUpdateMonitor.registerInfoCallback(mInfoCallback);
mUpdateMonitor.registerSimStateCallback(mSimStateCallback);
resetStatusInfo();
diff --git a/policy/src/com/android/internal/policy/impl/LockPatternKeyguardView.java b/policy/src/com/android/internal/policy/impl/LockPatternKeyguardView.java
index 0d0461b..1e9784c 100644
--- a/policy/src/com/android/internal/policy/impl/LockPatternKeyguardView.java
+++ b/policy/src/com/android/internal/policy/impl/LockPatternKeyguardView.java
@@ -855,6 +855,9 @@
case Password:
secure = mLockPatternUtils.isLockPasswordEnabled();
break;
+ case Unknown:
+ // This means no security is set up
+ break;
default:
throw new IllegalStateException("unknown unlock mode " + unlockMode);
}
@@ -877,8 +880,8 @@
// Re-create the unlock screen if necessary. This is primarily required to properly handle
// SIM state changes. This typically happens when this method is called by reset()
- if (mode == Mode.UnlockScreen) {
- final UnlockMode unlockMode = getUnlockMode();
+ final UnlockMode unlockMode = getUnlockMode();
+ if (mode == Mode.UnlockScreen && unlockMode != UnlockMode.Unknown) {
if (force || mUnlockScreen == null || unlockMode != mUnlockScreenMode) {
boolean restartFaceLock = stopFaceLockIfRunning();
recreateUnlockScreen(unlockMode);
@@ -1052,11 +1055,15 @@
break;
case DevicePolicyManager.PASSWORD_QUALITY_SOMETHING:
case DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED:
- // "forgot pattern" button is only available in the pattern mode...
- if (mForgotPattern || mLockPatternUtils.isPermanentlyLocked()) {
- currentMode = UnlockMode.Account;
+ if (mLockPatternUtils.isLockPatternEnabled()) {
+ // "forgot pattern" button is only available in the pattern mode...
+ if (mForgotPattern || mLockPatternUtils.isPermanentlyLocked()) {
+ currentMode = UnlockMode.Account;
+ } else {
+ currentMode = UnlockMode.Pattern;
+ }
} else {
- currentMode = UnlockMode.Pattern;
+ currentMode = UnlockMode.Unknown;
}
break;
default:
diff --git a/policy/src/com/android/internal/policy/impl/LockScreen.java b/policy/src/com/android/internal/policy/impl/LockScreen.java
index 24a2420..3384661 100644
--- a/policy/src/com/android/internal/policy/impl/LockScreen.java
+++ b/policy/src/com/android/internal/policy/impl/LockScreen.java
@@ -23,6 +23,8 @@
import com.android.internal.widget.multiwaveview.MultiWaveView;
import android.app.ActivityManager;
+import android.app.ActivityManagerNative;
+import android.content.ActivityNotFoundException;
import android.content.Context;
import android.content.Intent;
import android.content.res.Configuration;
@@ -34,6 +36,7 @@
import android.widget.*;
import android.util.Log;
import android.media.AudioManager;
+import android.os.RemoteException;
import android.provider.MediaStore;
import android.provider.Settings;
@@ -229,8 +232,16 @@
// Start the Camera
Intent intent = new Intent(MediaStore.INTENT_ACTION_STILL_IMAGE_CAMERA);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
- mContext.startActivity(intent);
- mCallback.goToUnlockScreen();
+ try {
+ ActivityManagerNative.getDefault().dismissKeyguardOnNextActivity();
+ } catch (RemoteException e) {
+ Log.w(TAG, "can't dismiss keyguard on launch");
+ }
+ try {
+ mContext.startActivity(intent);
+ } catch (ActivityNotFoundException e) {
+ Log.w(TAG, "Camera application not found");
+ }
} else {
toggleRingMode();
mUnlockWidgetMethods.updateResources();
diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
index b440bde..2d6e4f8 100755
--- a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
+++ b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
@@ -2044,6 +2044,12 @@
mTmpNavigationFrame.offset(mNavigationBarWidth, 0);
}
}
+ // Make sure the content and current rectangles are updated to
+ // account for the restrictions from the navigation bar.
+ mContentTop = mCurTop = mDockTop;
+ mContentBottom = mCurBottom = mDockBottom;
+ mContentLeft = mCurLeft = mDockLeft;
+ mContentRight = mCurRight = mDockRight;
// And compute the final frame.
mNavigationBar.computeFrameLw(mTmpNavigationFrame, mTmpNavigationFrame,
mTmpNavigationFrame, mTmpNavigationFrame);
@@ -3647,6 +3653,12 @@
}
};
+ public void lockNow() {
+ mContext.enforceCallingOrSelfPermission(android.Manifest.permission.DEVICE_POWER, null);
+ mHandler.removeCallbacks(mScreenLockTimeout);
+ mHandler.post(mScreenLockTimeout);
+ }
+
private void updateLockScreenTimeout() {
synchronized (mScreenLockTimeout) {
boolean enable = (mAllowLockscreenWhenOn && mScreenOnEarly && mKeyguardMediator.isSecure());
diff --git a/services/audioflinger/AudioFlinger.cpp b/services/audioflinger/AudioFlinger.cpp
index d9f419b..bc2fdd6 100644
--- a/services/audioflinger/AudioFlinger.cpp
+++ b/services/audioflinger/AudioFlinger.cpp
@@ -37,8 +37,6 @@
#include <cutils/properties.h>
#include <cutils/compiler.h>
-#include <media/AudioTrack.h>
-#include <media/AudioRecord.h>
#include <media/IMediaPlayerService.h>
#include <media/IMediaDeathNotifier.h>
@@ -1742,7 +1740,7 @@
// FIXME - Current mixer implementation only supports stereo output: Always
// Allocate a stereo buffer even if HW output is mono.
- if (mMixBuffer != NULL) delete[] mMixBuffer;
+ delete[] mMixBuffer;
mMixBuffer = new int16_t[mFrameCount * 2];
memset(mMixBuffer, 0, mFrameCount * 2 * sizeof(int16_t));
@@ -1810,7 +1808,7 @@
}
-AudioFlinger::AudioStreamOut* AudioFlinger::PlaybackThread::getOutput()
+AudioFlinger::AudioStreamOut* AudioFlinger::PlaybackThread::getOutput() const
{
Mutex::Autolock _l(mLock);
return mOutput;
@@ -1868,7 +1866,7 @@
bool AudioFlinger::MixerThread::threadLoop()
{
Vector< sp<Track> > tracksToRemove;
- uint32_t mixerStatus = MIXER_IDLE;
+ mixer_state mixerStatus = MIXER_IDLE;
nsecs_t standbyTime = systemTime();
size_t mixBufferSize = mFrameCount * mFrameSize;
// FIXME: Relaxed timing because of a certain device that can't meet latency
@@ -1990,11 +1988,14 @@
if (CC_LIKELY(mixerStatus == MIXER_TRACKS_READY)) {
// mix buffers...
mAudioMixer->process();
- sleepTime = 0;
- // increase sleep time progressively when application underrun condition clears
- if (sleepTimeShift > 0) {
+ // increase sleep time progressively when application underrun condition clears.
+ // Only increase sleep time if the mixer is ready for two consecutive times to avoid
+ // that a steady state of alternating ready/not ready conditions keeps the sleep time
+ // such that we would underrun the audio HAL.
+ if ((sleepTime == 0) && (sleepTimeShift > 0)) {
sleepTimeShift--;
}
+ sleepTime = 0;
standbyTime = systemTime() + kStandbyTimeInNsecs;
//TODO: delay standby when effects have a tail
} else {
@@ -2084,10 +2085,11 @@
}
// prepareTracks_l() must be called with ThreadBase::mLock held
-uint32_t AudioFlinger::MixerThread::prepareTracks_l(const SortedVector< wp<Track> >& activeTracks, Vector< sp<Track> > *tracksToRemove)
+AudioFlinger::PlaybackThread::mixer_state AudioFlinger::MixerThread::prepareTracks_l(
+ const SortedVector< wp<Track> >& activeTracks, Vector< sp<Track> > *tracksToRemove)
{
- uint32_t mixerStatus = MIXER_IDLE;
+ mixer_state mixerStatus = MIXER_IDLE;
// find out which tracks need to be processed
size_t count = activeTracks.size();
size_t mixedTracks = 0;
@@ -2459,6 +2461,8 @@
}
if (status == NO_ERROR && reconfig) {
delete mAudioMixer;
+ // for safety in case readOutputParameters() accesses mAudioMixer (it doesn't)
+ mAudioMixer = NULL;
readOutputParameters();
mAudioMixer = new AudioMixer(mFrameCount, mSampleRate);
for (size_t i = 0; i < mTracks.size() ; i++) {
@@ -2611,7 +2615,7 @@
bool AudioFlinger::DirectOutputThread::threadLoop()
{
- uint32_t mixerStatus = MIXER_IDLE;
+ mixer_state mixerStatus = MIXER_IDLE;
sp<Track> trackToRemove;
sp<Track> activeTrack;
nsecs_t standbyTime = systemTime();
@@ -3008,7 +3012,7 @@
bool AudioFlinger::DuplicatingThread::threadLoop()
{
Vector< sp<Track> > tracksToRemove;
- uint32_t mixerStatus = MIXER_IDLE;
+ mixer_state mixerStatus = MIXER_IDLE;
nsecs_t standbyTime = systemTime();
size_t mixBufferSize = mFrameCount*mFrameSize;
SortedVector< sp<OutputTrack> > outputTracks;
@@ -3548,7 +3552,7 @@
sp<ThreadBase> thread = mThread.promote();
if (thread != 0) {
Mutex::Autolock _l(thread->mLock);
- int state = mState;
+ track_state state = mState;
// here the track could be either new, or restarted
// in both cases "unstop" the track
if (mState == PAUSED) {
@@ -3589,7 +3593,7 @@
sp<ThreadBase> thread = mThread.promote();
if (thread != 0) {
Mutex::Autolock _l(thread->mLock);
- int state = mState;
+ track_state state = mState;
if (mState > STOPPED) {
mState = STOPPED;
// If the track is not active (PAUSED and buffers full), flush buffers
@@ -3908,7 +3912,7 @@
if (mOutBuffer.frameCount == 0) {
mOutBuffer.frameCount = pInBuffer->frameCount;
nsecs_t startTime = systemTime();
- if (obtainBuffer(&mOutBuffer, waitTimeLeftMs) == (status_t)AudioTrack::NO_MORE_BUFFERS) {
+ if (obtainBuffer(&mOutBuffer, waitTimeLeftMs) == (status_t)NO_MORE_BUFFERS) {
ALOGV ("OutputTrack::write() %p thread %p no more output buffers", this, mThread.unsafe_get());
outputBufferFull = true;
break;
@@ -3999,11 +4003,11 @@
active = mActive;
if (CC_UNLIKELY(!active)) {
ALOGV("Not active and NO_MORE_BUFFERS");
- return AudioTrack::NO_MORE_BUFFERS;
+ return NO_MORE_BUFFERS;
}
result = cblk->cv.waitRelative(cblk->lock, milliseconds(waitTimeMs));
if (result != NO_ERROR) {
- return AudioTrack::NO_MORE_BUFFERS;
+ return NO_MORE_BUFFERS;
}
// read the server count again
start_loop_here:
@@ -4012,7 +4016,7 @@
}
// if (framesAvail < framesReq) {
-// return AudioTrack::NO_MORE_BUFFERS;
+// return NO_MORE_BUFFERS;
// }
if (framesReq > framesAvail) {
@@ -4062,7 +4066,7 @@
mAudioFlinger->removeClient_l(mPid);
}
-const sp<MemoryDealer>& AudioFlinger::Client::heap() const
+sp<MemoryDealer> AudioFlinger::Client::heap() const
{
return mMemoryDealer;
}
@@ -4105,6 +4109,10 @@
mTrack->destroy();
}
+sp<IMemory> AudioFlinger::TrackHandle::getCblk() const {
+ return mTrack->getCblk();
+}
+
status_t AudioFlinger::TrackHandle::start() {
return mTrack->start();
}
@@ -4125,10 +4133,6 @@
mTrack->pause();
}
-sp<IMemory> AudioFlinger::TrackHandle::getCblk() const {
- return mTrack->getCblk();
-}
-
status_t AudioFlinger::TrackHandle::attachAuxEffect(int EffectId)
{
return mTrack->attachAuxEffect(EffectId);
@@ -4235,6 +4239,10 @@
stop();
}
+sp<IMemory> AudioFlinger::RecordHandle::getCblk() const {
+ return mRecordTrack->getCblk();
+}
+
status_t AudioFlinger::RecordHandle::start() {
ALOGV("RecordHandle::start()");
return mRecordTrack->start();
@@ -4245,10 +4253,6 @@
mRecordTrack->stop();
}
-sp<IMemory> AudioFlinger::RecordHandle::getCblk() const {
- return mRecordTrack->getCblk();
-}
-
status_t AudioFlinger::RecordHandle::onTransact(
uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
{
@@ -4279,10 +4283,8 @@
AudioFlinger::RecordThread::~RecordThread()
{
delete[] mRsmpInBuffer;
- if (mResampler != NULL) {
- delete mResampler;
- delete[] mRsmpOutBuffer;
- }
+ delete mResampler;
+ delete[] mRsmpOutBuffer;
}
void AudioFlinger::RecordThread::onFirstRef()
@@ -4826,9 +4828,11 @@
void AudioFlinger::RecordThread::readInputParameters()
{
- if (mRsmpInBuffer) delete mRsmpInBuffer;
- if (mRsmpOutBuffer) delete mRsmpOutBuffer;
- if (mResampler) delete mResampler;
+ delete mRsmpInBuffer;
+ // mRsmpInBuffer is always assigned a new[] below
+ delete mRsmpOutBuffer;
+ mRsmpOutBuffer = NULL;
+ delete mResampler;
mResampler = NULL;
mSampleRate = mInput->stream->common.get_sample_rate(&mInput->stream->common);
@@ -4895,7 +4899,7 @@
return mTrack;
}
-AudioFlinger::AudioStreamIn* AudioFlinger::RecordThread::getInput()
+AudioFlinger::AudioStreamIn* AudioFlinger::RecordThread::getInput() const
{
Mutex::Autolock _l(mLock);
return mInput;
@@ -5043,6 +5047,7 @@
if (thread->type() != ThreadBase::DUPLICATING) {
AudioStreamOut *out = thread->clearOutput();
+ assert(out != NULL);
// from now on thread->mOutput is NULL
out->hwDev->close_output_stream(out->hwDev, out->stream);
delete out;
@@ -5184,6 +5189,7 @@
thread->exit();
AudioStreamIn *in = thread->clearInput();
+ assert(in != NULL);
// from now on thread->mInput is NULL
in->hwDev->close_input_stream(in->hwDev, in->stream);
delete in;
@@ -6174,7 +6180,7 @@
}
}
-status_t AudioFlinger::EffectModule::addHandle(sp<EffectHandle>& handle)
+status_t AudioFlinger::EffectModule::addHandle(const sp<EffectHandle>& handle)
{
status_t status;
diff --git a/services/audioflinger/AudioFlinger.h b/services/audioflinger/AudioFlinger.h
index d862c1d..ece4ba2 100644
--- a/services/audioflinger/AudioFlinger.h
+++ b/services/audioflinger/AudioFlinger.h
@@ -26,7 +26,7 @@
#include <media/IAudioFlingerClient.h>
#include <media/IAudioTrack.h>
#include <media/IAudioRecord.h>
-#include <media/AudioTrack.h>
+#include <media/AudioSystem.h>
#include <utils/Atomic.h>
#include <utils/Errors.h>
@@ -207,6 +207,7 @@
bool btNrecIsOff() { return mBtNrecIsOff; }
private:
+
AudioFlinger();
virtual ~AudioFlinger();
@@ -225,7 +226,7 @@
public:
Client(const sp<AudioFlinger>& audioFlinger, pid_t pid);
virtual ~Client();
- const sp<MemoryDealer>& heap() const;
+ sp<MemoryDealer> heap() const;
pid_t pid() const { return mPid; }
sp<AudioFlinger> audioFlinger() { return mAudioFlinger; }
@@ -374,7 +375,7 @@
void* mBufferEnd;
uint32_t mFrameCount;
// we don't really need a lock for these
- int mState;
+ track_state mState;
int mClientTid;
audio_format_t mFormat;
uint32_t mFlags;
@@ -674,6 +675,10 @@
private:
+ enum {
+ NO_MORE_BUFFERS = 0x80000001, // same in AudioTrack.h, ok to be different value
+ };
+
status_t obtainBuffer(AudioBufferProvider::Buffer* buffer, uint32_t waitTimeMs);
void clearBufferQueue();
@@ -722,7 +727,7 @@
int sessionId,
status_t *status);
- AudioStreamOut* getOutput();
+ AudioStreamOut* getOutput() const;
AudioStreamOut* clearOutput();
virtual audio_stream_t* stream();
@@ -799,7 +804,7 @@
SortedVector< sp<Track> > mTracks;
// mStreamTypes[] uses 1 additional stream type internally for the OutputTrack used by DuplicatingThread
stream_type_t mStreamTypes[AUDIO_STREAM_CNT + 1];
- AudioStreamOut* mOutput;
+ AudioStreamOut *mOutput;
float mMasterVolume;
nsecs_t mLastWriteTime;
int mNumWrites;
@@ -823,7 +828,7 @@
virtual status_t dumpInternals(int fd, const Vector<String16>& args);
protected:
- uint32_t prepareTracks_l(const SortedVector< wp<Track> >& activeTracks,
+ mixer_state prepareTracks_l(const SortedVector< wp<Track> >& activeTracks,
Vector< sp<Track> > *tracksToRemove);
virtual int getTrackName_l();
virtual void deleteTrackName_l(int name);
@@ -831,8 +836,7 @@
virtual uint32_t suspendSleepTimeUs();
AudioMixer* mAudioMixer;
- uint32_t mPrevMixerStatus; // previous status (mixer_state) returned by
- // prepareTracks_l()
+ mixer_state mPrevMixerStatus; // previous status returned by prepareTracks_l()
};
class DirectOutputThread : public PlaybackThread {
@@ -903,12 +907,12 @@
public:
TrackHandle(const sp<PlaybackThread::Track>& track);
virtual ~TrackHandle();
+ virtual sp<IMemory> getCblk() const;
virtual status_t start();
virtual void stop();
virtual void flush();
virtual void mute(bool);
virtual void pause();
- virtual sp<IMemory> getCblk() const;
virtual status_t attachAuxEffect(int effectId);
virtual status_t onTransact(
uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags);
@@ -989,7 +993,7 @@
status_t start(RecordTrack* recordTrack);
void stop(RecordTrack* recordTrack);
status_t dump(int fd, const Vector<String16>& args);
- AudioStreamIn* getInput();
+ AudioStreamIn* getInput() const;
AudioStreamIn* clearInput();
virtual audio_stream_t* stream();
@@ -1026,9 +1030,9 @@
public:
RecordHandle(const sp<RecordThread::RecordTrack>& recordTrack);
virtual ~RecordHandle();
+ virtual sp<IMemory> getCblk() const;
virtual status_t start();
virtual void stop();
- virtual sp<IMemory> getCblk() const;
virtual status_t onTransact(
uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags);
private:
@@ -1082,7 +1086,7 @@
void reset_l();
status_t configure();
status_t init();
- uint32_t state() {
+ effect_state state() const {
return mState;
}
uint32_t status() {
@@ -1103,7 +1107,7 @@
void setThread(const wp<ThreadBase>& thread) { mThread = thread; }
wp<ThreadBase>& thread() { return mThread; }
- status_t addHandle(sp<EffectHandle>& handle);
+ status_t addHandle(const sp<EffectHandle>& handle);
void disconnect(const wp<EffectHandle>& handle, bool unpiniflast);
size_t removeHandle (const wp<EffectHandle>& handle);
@@ -1147,8 +1151,8 @@
effect_descriptor_t mDescriptor;// effect descriptor received from effect engine
effect_config_t mConfig; // input and output audio configuration
effect_handle_t mEffectInterface; // Effect module C API
- status_t mStatus; // initialization status
- uint32_t mState; // current activation state (effect_state)
+ status_t mStatus; // initialization status
+ effect_state mState; // current activation state
Vector< wp<EffectHandle> > mHandles; // list of client handles
uint32_t mMaxDisableWaitCnt; // maximum grace period before forcing an effect off after
// sending disable command.
@@ -1352,17 +1356,21 @@
KeyedVector< int, sp<SuspendedEffectDesc> > mSuspendedEffects;
};
+ // AudioStreamOut and AudioStreamIn are immutable, so their fields are const.
+ // For emphasis, we could also make all pointers to them be "const *",
+ // but that would clutter the code unnecessarily.
+
struct AudioStreamOut {
- audio_hw_device_t *hwDev;
- audio_stream_out_t *stream;
+ audio_hw_device_t* const hwDev;
+ audio_stream_out_t* const stream;
AudioStreamOut(audio_hw_device_t *dev, audio_stream_out_t *out) :
hwDev(dev), stream(out) {}
};
struct AudioStreamIn {
- audio_hw_device_t *hwDev;
- audio_stream_in_t *stream;
+ audio_hw_device_t* const hwDev;
+ audio_stream_in_t* const stream;
AudioStreamIn(audio_hw_device_t *dev, audio_stream_in_t *in) :
hwDev(dev), stream(in) {}
diff --git a/services/audioflinger/AudioMixer.cpp b/services/audioflinger/AudioMixer.cpp
index a8102e5..a01c6a8 100644
--- a/services/audioflinger/AudioMixer.cpp
+++ b/services/audioflinger/AudioMixer.cpp
@@ -1127,9 +1127,7 @@
}
}
- if (buff != NULL) {
- delete [] buff;
- }
+ delete [] buff;
}
#endif
diff --git a/services/audioflinger/AudioPolicyService.cpp b/services/audioflinger/AudioPolicyService.cpp
index 28b1c89..7695d2b 100644
--- a/services/audioflinger/AudioPolicyService.cpp
+++ b/services/audioflinger/AudioPolicyService.cpp
@@ -287,7 +287,7 @@
mpAudioPolicy->release_output(mpAudioPolicy, output);
}
-audio_io_handle_t AudioPolicyService::getInput(int inputSource,
+audio_io_handle_t AudioPolicyService::getInput(audio_source_t inputSource,
uint32_t samplingRate,
audio_format_t format,
uint32_t channels,
@@ -297,6 +297,10 @@
if (mpAudioPolicy == NULL) {
return 0;
}
+ // already checked by client, but double-check in case the client wrapper is bypassed
+ if (uint32_t(inputSource) >= AUDIO_SOURCE_CNT) {
+ return 0;
+ }
Mutex::Autolock _l(mLock);
audio_io_handle_t input = mpAudioPolicy->get_input(mpAudioPolicy, inputSource, samplingRate,
format, channels, acoustics);
@@ -305,7 +309,7 @@
return input;
}
// create audio pre processors according to input source
- ssize_t index = mInputSources.indexOfKey((audio_source_t)inputSource);
+ ssize_t index = mInputSources.indexOfKey(inputSource);
if (index < 0) {
return input;
}
@@ -645,7 +649,7 @@
release_wake_lock(mName.string());
}
mAudioCommands.clear();
- if (mpToneGenerator != NULL) delete mpToneGenerator;
+ delete mpToneGenerator;
}
void AudioPolicyService::AudioCommandThread::onFirstRef()
@@ -678,8 +682,7 @@
ToneData *data = (ToneData *)command->mParam;
ALOGV("AudioCommandThread() processing start tone %d on stream %d",
data->mType, data->mStream);
- if (mpToneGenerator != NULL)
- delete mpToneGenerator;
+ delete mpToneGenerator;
mpToneGenerator = new ToneGenerator(data->mStream, 1.0);
mpToneGenerator->startTone(data->mType);
delete data;
diff --git a/services/audioflinger/AudioPolicyService.h b/services/audioflinger/AudioPolicyService.h
index 9811670..3c0f5ed 100644
--- a/services/audioflinger/AudioPolicyService.h
+++ b/services/audioflinger/AudioPolicyService.h
@@ -74,7 +74,7 @@
audio_stream_type_t stream,
int session = 0);
virtual void releaseOutput(audio_io_handle_t output);
- virtual audio_io_handle_t getInput(int inputSource,
+ virtual audio_io_handle_t getInput(audio_source_t inputSource,
uint32_t samplingRate = 0,
audio_format_t format = AUDIO_FORMAT_DEFAULT,
uint32_t channels = 0,
diff --git a/services/input/EventHub.cpp b/services/input/EventHub.cpp
index 1f8cf63..296c95e 100644
--- a/services/input/EventHub.cpp
+++ b/services/input/EventHub.cpp
@@ -831,7 +831,7 @@
ALOGV("Opening device: %s", devicePath);
- int fd = open(devicePath, O_RDWR);
+ int fd = open(devicePath, O_RDWR | O_CLOEXEC);
if(fd < 0) {
ALOGE("could not open %s, %s\n", devicePath, strerror(errno));
return -1;
@@ -1063,14 +1063,20 @@
return -1;
}
+ // Enable wake-lock behavior on kernels that support it.
+ // TODO: Only need this for devices that can really wake the system.
+ bool usingSuspendBlock = ioctl(fd, EVIOCSSUSPENDBLOCK, 1) == 0;
+
ALOGI("New device: id=%d, fd=%d, path='%s', name='%s', classes=0x%x, "
- "configuration='%s', keyLayout='%s', keyCharacterMap='%s', builtinKeyboard=%s",
+ "configuration='%s', keyLayout='%s', keyCharacterMap='%s', builtinKeyboard=%s, "
+ "usingSuspendBlock=%s",
deviceId, fd, devicePath, device->identifier.name.string(),
device->classes,
device->configurationFile.string(),
device->keyMap.keyLayoutFile.string(),
device->keyMap.keyCharacterMapFile.string(),
- toString(mBuiltInKeyboardId == deviceId));
+ toString(mBuiltInKeyboardId == deviceId),
+ toString(usingSuspendBlock));
mDevices.add(deviceId, device);
diff --git a/services/input/InputDispatcher.cpp b/services/input/InputDispatcher.cpp
index 9f09062..ad64ccd 100644
--- a/services/input/InputDispatcher.cpp
+++ b/services/input/InputDispatcher.cpp
@@ -238,6 +238,8 @@
nsecs_t nextWakeupTime = LONG_LONG_MAX;
{ // acquire lock
AutoMutex _l(mLock);
+ mDispatcherIsAliveCondition.broadcast();
+
dispatchOnceInnerLocked(&nextWakeupTime);
if (runCommandsLockedInterruptible()) {
@@ -4086,6 +4088,8 @@
void InputDispatcher::monitor() {
// Acquire and release the lock to ensure that the dispatcher has not deadlocked.
mLock.lock();
+ mLooper->wake();
+ mDispatcherIsAliveCondition.wait(mLock);
mLock.unlock();
}
diff --git a/services/input/InputDispatcher.h b/services/input/InputDispatcher.h
index 1478d67..a1d42e1 100644
--- a/services/input/InputDispatcher.h
+++ b/services/input/InputDispatcher.h
@@ -862,6 +862,8 @@
Mutex mLock;
+ Condition mDispatcherIsAliveCondition;
+
sp<Looper> mLooper;
EventEntry* mPendingEvent;
diff --git a/services/input/InputReader.cpp b/services/input/InputReader.cpp
index fa0b3d8..4be06e4 100644
--- a/services/input/InputReader.cpp
+++ b/services/input/InputReader.cpp
@@ -278,17 +278,20 @@
{ // acquire lock
AutoMutex _l(mLock);
+ mReaderIsAliveCondition.broadcast();
if (count) {
processEventsLocked(mEventBuffer, count);
}
if (!count || timeoutMillis == 0) {
nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
+ if (now >= mNextTimeout) {
#if DEBUG_RAW_EVENTS
- ALOGD("Timeout expired, latency=%0.3fms", (now - mNextTimeout) * 0.000001f);
+ ALOGD("Timeout expired, latency=%0.3fms", (now - mNextTimeout) * 0.000001f);
#endif
- mNextTimeout = LLONG_MAX;
- timeoutExpiredLocked(now);
+ mNextTimeout = LLONG_MAX;
+ timeoutExpiredLocked(now);
+ }
}
} // release lock
@@ -772,6 +775,8 @@
void InputReader::monitor() {
// Acquire and release the lock to ensure that the reader has not deadlocked.
mLock.lock();
+ mEventHub->wake();
+ mReaderIsAliveCondition.wait(mLock);
mLock.unlock();
// Check the EventHub
diff --git a/services/input/InputReader.h b/services/input/InputReader.h
index a122c97..ad89a22 100644
--- a/services/input/InputReader.h
+++ b/services/input/InputReader.h
@@ -363,6 +363,8 @@
private:
Mutex mLock;
+ Condition mReaderIsAliveCondition;
+
sp<EventHubInterface> mEventHub;
sp<InputReaderPolicyInterface> mPolicy;
sp<QueuedInputListener> mQueuedListener;
diff --git a/services/java/com/android/server/BackupManagerService.java b/services/java/com/android/server/BackupManagerService.java
index aebfd60..31515e1 100644
--- a/services/java/com/android/server/BackupManagerService.java
+++ b/services/java/com/android/server/BackupManagerService.java
@@ -140,6 +140,8 @@
static final int BACKUP_FILE_VERSION = 1;
static final boolean COMPRESS_FULL_BACKUPS = true; // should be true in production
+ static final String SHARED_BACKUP_AGENT_PACKAGE = "com.android.sharedstoragebackup";
+
// How often we perform a backup pass. Privileged external callers can
// trigger an immediate pass.
private static final long BACKUP_INTERVAL = AlarmManager.INTERVAL_HOUR;
@@ -2325,14 +2327,16 @@
ParcelFileDescriptor mPipe;
int mToken;
boolean mSendApk;
+ boolean mWriteManifest;
FullBackupRunner(PackageInfo pack, IBackupAgent agent, ParcelFileDescriptor pipe,
- int token, boolean sendApk) throws IOException {
+ int token, boolean sendApk, boolean writeManifest) throws IOException {
mPackage = pack;
mAgent = agent;
mPipe = ParcelFileDescriptor.dup(pipe.getFileDescriptor());
mToken = token;
mSendApk = sendApk;
+ mWriteManifest = writeManifest;
}
@Override
@@ -2341,12 +2345,14 @@
BackupDataOutput output = new BackupDataOutput(
mPipe.getFileDescriptor());
- if (MORE_DEBUG) Slog.d(TAG, "Writing manifest for " + mPackage.packageName);
- writeAppManifest(mPackage, mManifestFile, mSendApk);
- FullBackup.backupToTar(mPackage.packageName, null, null,
- mFilesDir.getAbsolutePath(),
- mManifestFile.getAbsolutePath(),
- output);
+ if (mWriteManifest) {
+ if (MORE_DEBUG) Slog.d(TAG, "Writing manifest for " + mPackage.packageName);
+ writeAppManifest(mPackage, mManifestFile, mSendApk);
+ FullBackup.backupToTar(mPackage.packageName, null, null,
+ mFilesDir.getAbsolutePath(),
+ mManifestFile.getAbsolutePath(),
+ output);
+ }
if (mSendApk) {
writeApkToBackup(mPackage, output);
@@ -2433,10 +2439,13 @@
}
}
- // Cull any packages that have indicated that backups are not permitted.
+ // Cull any packages that have indicated that backups are not permitted, as well
+ // as any explicit mention of the 'special' shared-storage agent package (we
+ // handle that one at the end).
for (int i = 0; i < packagesToBackup.size(); ) {
PackageInfo pkg = packagesToBackup.get(i);
- if ((pkg.applicationInfo.flags & ApplicationInfo.FLAG_ALLOW_BACKUP) == 0) {
+ if ((pkg.applicationInfo.flags & ApplicationInfo.FLAG_ALLOW_BACKUP) == 0
+ || pkg.packageName.equals(SHARED_BACKUP_AGENT_PACKAGE)) {
packagesToBackup.remove(i);
} else {
i++;
@@ -2516,6 +2525,16 @@
return;
}
+ // Shared storage if requested
+ if (mIncludeShared) {
+ try {
+ pkg = mPackageManager.getPackageInfo(SHARED_BACKUP_AGENT_PACKAGE, 0);
+ packagesToBackup.add(pkg);
+ } catch (NameNotFoundException e) {
+ Slog.e(TAG, "Unable to find shared-storage backup handler");
+ }
+ }
+
// Now back up the app data via the agent mechanism
int N = packagesToBackup.size();
for (int i = 0; i < N; i++) {
@@ -2523,11 +2542,6 @@
backupOnePackage(pkg, out);
}
- // Shared storage if requested
- if (mIncludeShared) {
- backupSharedStorage();
- }
-
// Done!
finalizeBackup(out);
} catch (RemoteException e) {
@@ -2633,19 +2647,21 @@
if (agent != null) {
ParcelFileDescriptor[] pipes = null;
try {
- pipes = ParcelFileDescriptor.createPipe();
+ pipes = ParcelFileDescriptor.createPipe();
ApplicationInfo app = pkg.applicationInfo;
+ final boolean isSharedStorage = pkg.packageName.equals(SHARED_BACKUP_AGENT_PACKAGE);
final boolean sendApk = mIncludeApks
+ && !isSharedStorage
&& ((app.flags & ApplicationInfo.FLAG_FORWARD_LOCK) == 0)
&& ((app.flags & ApplicationInfo.FLAG_SYSTEM) == 0 ||
(app.flags & ApplicationInfo.FLAG_UPDATED_SYSTEM_APP) != 0);
- sendOnBackupPackage(pkg.packageName);
+ sendOnBackupPackage(isSharedStorage ? "Shared storage" : pkg.packageName);
final int token = generateToken();
FullBackupRunner runner = new FullBackupRunner(pkg, agent, pipes[1],
- token, sendApk);
+ token, sendApk, !isSharedStorage);
pipes[1].close(); // the runner has dup'd it
pipes[1] = null;
Thread t = new Thread(runner);
@@ -2720,33 +2736,6 @@
}
}
- private void backupSharedStorage() throws RemoteException {
- PackageInfo pkg = null;
- try {
- pkg = mPackageManager.getPackageInfo("com.android.sharedstoragebackup", 0);
- IBackupAgent agent = bindToAgentSynchronous(pkg.applicationInfo,
- IApplicationThread.BACKUP_MODE_FULL);
- if (agent != null) {
- sendOnBackupPackage("Shared storage");
-
- final int token = generateToken();
- prepareOperationTimeout(token, TIMEOUT_SHARED_BACKUP_INTERVAL, null);
- agent.doFullBackup(mOutputFile, token, mBackupManagerBinder);
- if (!waitUntilOperationComplete(token)) {
- Slog.e(TAG, "Full backup failed on shared storage");
- } else {
- if (DEBUG) Slog.d(TAG, "Full shared storage backup success");
- }
- } else {
- Slog.e(TAG, "Could not bind to shared storage backup agent");
- }
- } catch (NameNotFoundException e) {
- Slog.e(TAG, "Shared storage backup package not found");
- } finally {
- tearDown(pkg);
- }
- }
-
private void finalizeBackup(OutputStream out) {
try {
// A standard 'tar' EOF sequence: two 512-byte blocks of all zeroes.
@@ -2972,7 +2961,7 @@
// Are we able to restore shared-storage data?
if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
- mPackagePolicies.put("com.android.sharedstoragebackup", RestorePolicy.ACCEPT);
+ mPackagePolicies.put(SHARED_BACKUP_AGENT_PACKAGE, RestorePolicy.ACCEPT);
}
FileInputStream rawInStream = null;
@@ -3850,7 +3839,7 @@
info.path, 0, FullBackup.SHARED_PREFIX.length())) {
// File in shared storage. !!! TODO: implement this.
info.path = info.path.substring(FullBackup.SHARED_PREFIX.length());
- info.packageName = "com.android.sharedstoragebackup";
+ info.packageName = SHARED_BACKUP_AGENT_PACKAGE;
info.domain = FullBackup.SHARED_STORAGE_TOKEN;
if (DEBUG) Slog.i(TAG, "File in shared storage: " + info.path);
} else if (FullBackup.APPS_PREFIX.regionMatches(0,
diff --git a/services/java/com/android/server/ConnectivityService.java b/services/java/com/android/server/ConnectivityService.java
index b7dc4a2..a372fb8 100644
--- a/services/java/com/android/server/ConnectivityService.java
+++ b/services/java/com/android/server/ConnectivityService.java
@@ -992,11 +992,15 @@
NetworkInfo ni = network.getNetworkInfo();
if (ni.isAvailable() == false) {
- if (DBG) log("special network not available");
if (!TextUtils.equals(feature,Phone.FEATURE_ENABLE_DUN_ALWAYS)) {
+ if (DBG) log("special network not available ni=" + ni.getTypeName());
return Phone.APN_TYPE_NOT_AVAILABLE;
} else {
// else make the attempt anyway - probably giving REQUEST_STARTED below
+ if (DBG) {
+ log("special network not available, but try anyway ni=" +
+ ni.getTypeName());
+ }
}
}
diff --git a/services/java/com/android/server/DevicePolicyManagerService.java b/services/java/com/android/server/DevicePolicyManagerService.java
index e8ca3ce..d8e3d59 100644
--- a/services/java/com/android/server/DevicePolicyManagerService.java
+++ b/services/java/com/android/server/DevicePolicyManagerService.java
@@ -60,6 +60,7 @@
import android.util.Printer;
import android.util.Slog;
import android.util.Xml;
+import android.view.IWindowManager;
import android.view.WindowManagerPolicy;
import java.io.File;
@@ -96,6 +97,7 @@
final PowerManager.WakeLock mWakeLock;
IPowerManager mIPowerManager;
+ IWindowManager mIWindowManager;
int mActivePasswordQuality = DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED;
int mActivePasswordLength = 0;
@@ -506,6 +508,14 @@
return mIPowerManager;
}
+ private IWindowManager getWindowManager() {
+ if (mIWindowManager == null) {
+ IBinder b = ServiceManager.getService(Context.WINDOW_SERVICE);
+ mIWindowManager = IWindowManager.Stub.asInterface(b);
+ }
+ return mIWindowManager;
+ }
+
ActiveAdmin getActiveAdminUncheckedLocked(ComponentName who) {
ActiveAdmin admin = mAdminMap.get(who);
if (admin != null
@@ -1649,8 +1659,11 @@
DeviceAdminInfo.USES_POLICY_FORCE_LOCK);
long ident = Binder.clearCallingIdentity();
try {
+ // Power off the display
mIPowerManager.goToSleepWithReason(SystemClock.uptimeMillis(),
WindowManagerPolicy.OFF_BECAUSE_OF_ADMIN);
+ // Ensure the device is locked
+ getWindowManager().lockNow();
} catch (RemoteException e) {
} finally {
Binder.restoreCallingIdentity(ident);
diff --git a/services/java/com/android/server/EventLogTags.logtags b/services/java/com/android/server/EventLogTags.logtags
index 4dad209..0bcec2e 100644
--- a/services/java/com/android/server/EventLogTags.logtags
+++ b/services/java/com/android/server/EventLogTags.logtags
@@ -142,5 +142,5 @@
# ---------------------------
# NetworkStatsService.java
# ---------------------------
-51100 netstats_mobile_sample (dev_rx_bytes|2|2),(dev_tx_bytes|2|2),(dev_rx_pkts|2|1),(dev_tx_pkts|2|1),(xt_rx_bytes|2|2),(xt_tx_bytes|2|2),(xt_rx_pkts|2|1),(xt_tx_pkts|2|1),(uid_rx_bytes|2|2),(uid_tx_bytes|2|2),(uid_rx_pkts|2|1),(uid_tx_pkts|2|1),(trusted_time|2|3),(dev_history_start|2|3)
-51101 netstats_wifi_sample (dev_rx_bytes|2|2),(dev_tx_bytes|2|2),(dev_rx_pkts|2|1),(dev_tx_pkts|2|1),(xt_rx_bytes|2|2),(xt_tx_bytes|2|2),(xt_rx_pkts|2|1),(xt_tx_pkts|2|1),(uid_rx_bytes|2|2),(uid_tx_bytes|2|2),(uid_rx_pkts|2|1),(uid_tx_pkts|2|1),(trusted_time|2|3),(dev_history_start|2|3)
+51100 netstats_mobile_sample (dev_rx_bytes|2|2),(dev_tx_bytes|2|2),(dev_rx_pkts|2|1),(dev_tx_pkts|2|1),(xt_rx_bytes|2|2),(xt_tx_bytes|2|2),(xt_rx_pkts|2|1),(xt_tx_pkts|2|1),(uid_rx_bytes|2|2),(uid_tx_bytes|2|2),(uid_rx_pkts|2|1),(uid_tx_pkts|2|1),(trusted_time|2|3)
+51101 netstats_wifi_sample (dev_rx_bytes|2|2),(dev_tx_bytes|2|2),(dev_rx_pkts|2|1),(dev_tx_pkts|2|1),(xt_rx_bytes|2|2),(xt_tx_bytes|2|2),(xt_rx_pkts|2|1),(xt_tx_pkts|2|1),(uid_rx_bytes|2|2),(uid_tx_bytes|2|2),(uid_rx_pkts|2|1),(uid_tx_pkts|2|1),(trusted_time|2|3)
diff --git a/services/java/com/android/server/LocationManagerService.java b/services/java/com/android/server/LocationManagerService.java
index 56afe7f..8cb9d99b 100644
--- a/services/java/com/android/server/LocationManagerService.java
+++ b/services/java/com/android/server/LocationManagerService.java
@@ -1962,8 +1962,10 @@
} else {
mNetworkState = LocationProvider.TEMPORARILY_UNAVAILABLE;
}
- NetworkInfo info =
- (NetworkInfo)intent.getExtra(ConnectivityManager.EXTRA_NETWORK_INFO);
+
+ final ConnectivityManager connManager = (ConnectivityManager) context
+ .getSystemService(Context.CONNECTIVITY_SERVICE);
+ final NetworkInfo info = connManager.getActiveNetworkInfo();
// Notify location providers of current network state
synchronized (mLock) {
diff --git a/services/java/com/android/server/NetworkTimeUpdateService.java b/services/java/com/android/server/NetworkTimeUpdateService.java
index f7fe39e..a7d1992 100644
--- a/services/java/com/android/server/NetworkTimeUpdateService.java
+++ b/services/java/com/android/server/NetworkTimeUpdateService.java
@@ -234,8 +234,9 @@
String action = intent.getAction();
if (ConnectivityManager.CONNECTIVITY_ACTION.equals(action)) {
// There is connectivity
- NetworkInfo netInfo = (NetworkInfo)intent.getParcelableExtra(
- ConnectivityManager.EXTRA_NETWORK_INFO);
+ final ConnectivityManager connManager = (ConnectivityManager) context
+ .getSystemService(Context.CONNECTIVITY_SERVICE);
+ final NetworkInfo netInfo = connManager.getActiveNetworkInfo();
if (netInfo != null) {
// Verify that it's a WIFI connection
if (netInfo.getState() == NetworkInfo.State.CONNECTED &&
diff --git a/services/java/com/android/server/PowerManagerService.java b/services/java/com/android/server/PowerManagerService.java
index 774495a..bb0ac3e 100644
--- a/services/java/com/android/server/PowerManagerService.java
+++ b/services/java/com/android/server/PowerManagerService.java
@@ -51,7 +51,6 @@
import android.os.RemoteException;
import android.os.SystemClock;
import android.os.WorkSource;
-import android.provider.Settings.SettingNotFoundException;
import android.provider.Settings;
import android.util.EventLog;
import android.util.Log;
@@ -60,6 +59,7 @@
import static android.provider.Settings.System.DIM_SCREEN;
import static android.provider.Settings.System.SCREEN_BRIGHTNESS;
import static android.provider.Settings.System.SCREEN_BRIGHTNESS_MODE;
+import static android.provider.Settings.System.SCREEN_AUTO_BRIGHTNESS_ADJ;
import static android.provider.Settings.System.SCREEN_BRIGHTNESS_MODE_AUTOMATIC;
import static android.provider.Settings.System.SCREEN_OFF_TIMEOUT;
import static android.provider.Settings.System.STAY_ON_WHILE_PLUGGED_IN;
@@ -106,6 +106,14 @@
// light sensor events rate in microseconds
private static final int LIGHT_SENSOR_RATE = 1000000;
+ // Expansion of range of light values when applying scale from light
+ // sensor brightness setting, in the [0..255] brightness range.
+ private static final int LIGHT_SENSOR_RANGE_EXPANSION = 20;
+
+ // Scaling factor of the light sensor brightness setting when applying
+ // it to the final brightness.
+ private static final int LIGHT_SENSOR_OFFSET_SCALE = 8;
+
// For debouncing the proximity sensor in milliseconds
private static final int PROXIMITY_SENSOR_DELAY = 1000;
@@ -118,6 +126,9 @@
// Default timeout for screen off, if not found in settings database = 15 seconds.
private static final int DEFAULT_SCREEN_OFF_TIMEOUT = 15000;
+ // Screen brightness should always have a value, but just in case...
+ private static final int DEFAULT_SCREEN_BRIGHTNESS = 192;
+
// flags for setPowerState
private static final int SCREEN_ON_BIT = 0x00000001;
private static final int SCREEN_BRIGHT_BIT = 0x00000002;
@@ -150,6 +161,8 @@
static final int ANIM_STEPS = 60/4;
// Slower animation for autobrightness changes
static final int AUTOBRIGHTNESS_ANIM_STEPS = 60;
+ // Number of steps when performing a more immediate brightness change.
+ static final int IMMEDIATE_ANIM_STEPS = 4;
// These magic numbers are the initial state of the LEDs at boot. Ideally
// we should read them from the driver, but our current hardware returns 0
@@ -227,6 +240,7 @@
private boolean mLightSensorPendingDecrease = false;
private boolean mLightSensorPendingIncrease = false;
private float mLightSensorPendingValue = -1;
+ private float mLightSensorAdjustSetting = 0;
private int mLightSensorScreenBrightness = -1;
private int mLightSensorButtonBrightness = -1;
private int mLightSensorKeyboardBrightness = -1;
@@ -240,6 +254,7 @@
// mLastScreenOnTime is the time the screen was last turned on
private long mLastScreenOnTime;
private boolean mPreventScreenOn;
+ private int mScreenBrightnessSetting = DEFAULT_SCREEN_BRIGHTNESS;
private int mScreenBrightnessOverride = -1;
private int mButtonBrightnessOverride = -1;
private int mScreenBrightnessDim;
@@ -460,6 +475,9 @@
// DIM_SCREEN
//mDimScreen = getInt(DIM_SCREEN) != 0;
+ mScreenBrightnessSetting = getInt(SCREEN_BRIGHTNESS, DEFAULT_SCREEN_BRIGHTNESS);
+ mLightSensorAdjustSetting = getFloat(SCREEN_AUTO_BRIGHTNESS_ADJ, 0);
+
// SCREEN_BRIGHTNESS_MODE, default to manual
setScreenBrightnessMode(getInt(SCREEN_BRIGHTNESS_MODE,
Settings.System.SCREEN_BRIGHTNESS_MODE_MANUAL));
@@ -624,9 +642,12 @@
+ Settings.System.NAME + "=?) or ("
+ Settings.System.NAME + "=?) or ("
+ Settings.System.NAME + "=?) or ("
+ + Settings.System.NAME + "=?) or ("
+ + Settings.System.NAME + "=?) or ("
+ Settings.System.NAME + "=?)",
- new String[]{STAY_ON_WHILE_PLUGGED_IN, SCREEN_OFF_TIMEOUT, DIM_SCREEN,
- SCREEN_BRIGHTNESS_MODE, WINDOW_ANIMATION_SCALE, TRANSITION_ANIMATION_SCALE},
+ new String[]{STAY_ON_WHILE_PLUGGED_IN, SCREEN_OFF_TIMEOUT, DIM_SCREEN, SCREEN_BRIGHTNESS,
+ SCREEN_BRIGHTNESS_MODE, SCREEN_AUTO_BRIGHTNESS_ADJ,
+ WINDOW_ANIMATION_SCALE, TRANSITION_ANIMATION_SCALE},
null);
mSettings = new ContentQueryMap(settingsCursor, Settings.System.NAME, true, mHandler);
SettingsObserver settingsObserver = new SettingsObserver();
@@ -1163,7 +1184,8 @@
pw.println(" mProximitySensorActive=" + mProximitySensorActive);
pw.println(" mProximityPendingValue=" + mProximityPendingValue);
pw.println(" mLastProximityEventTime=" + mLastProximityEventTime);
- pw.println(" mLightSensorEnabled=" + mLightSensorEnabled);
+ pw.println(" mLightSensorEnabled=" + mLightSensorEnabled
+ + " mLightSensorAdjustSetting=" + mLightSensorAdjustSetting);
pw.println(" mLightSensorValue=" + mLightSensorValue
+ " mLightSensorPendingValue=" + mLightSensorPendingValue);
pw.println(" mLightSensorPendingDecrease=" + mLightSensorPendingDecrease
@@ -2230,20 +2252,15 @@
}
private int getPreferredBrightness() {
- try {
- if (mScreenBrightnessOverride >= 0) {
- return mScreenBrightnessOverride;
- } else if (mLightSensorScreenBrightness >= 0 && mUseSoftwareAutoBrightness
- && mAutoBrightessEnabled) {
- return mLightSensorScreenBrightness;
- }
- final int brightness = Settings.System.getInt(mContext.getContentResolver(),
- SCREEN_BRIGHTNESS);
- // Don't let applications turn the screen all the way off
- return Math.max(brightness, mScreenBrightnessDim);
- } catch (SettingNotFoundException snfe) {
- return Power.BRIGHTNESS_ON;
+ if (mScreenBrightnessOverride >= 0) {
+ return mScreenBrightnessOverride;
+ } else if (mLightSensorScreenBrightness >= 0 && mUseSoftwareAutoBrightness
+ && mAutoBrightessEnabled) {
+ return mLightSensorScreenBrightness;
}
+ final int brightness = mScreenBrightnessSetting;
+ // Don't let applications turn the screen all the way off
+ return Math.max(brightness, mScreenBrightnessDim);
}
private int applyButtonState(int state) {
@@ -2439,7 +2456,34 @@
break;
}
}
- return values[i];
+ // This is the range of brightness values that we can use.
+ final int minval = values[0];
+ final int maxval = values[mAutoBrightnessLevels.length];
+ // This is the range we will be scaling. We put some padding
+ // at the low and high end to give the adjustment a little better
+ // impact on the actual observed value.
+ final int range = (maxval-minval) + LIGHT_SENSOR_RANGE_EXPANSION;
+ // This is the desired brightness value from 0.0 to 1.0.
+ float valf = ((values[i]-minval+(LIGHT_SENSOR_RANGE_EXPANSION/2))/(float)range);
+ // Apply a scaling to the value based on the adjustment.
+ if (mLightSensorAdjustSetting > 0 && mLightSensorAdjustSetting <= 1) {
+ float adj = (float)Math.sqrt(1.0f-mLightSensorAdjustSetting);
+ if (adj <= .00001) {
+ valf = 1;
+ } else {
+ valf /= adj;
+ }
+ } else if (mLightSensorAdjustSetting < 0 && mLightSensorAdjustSetting >= -1) {
+ float adj = (float)Math.sqrt(1.0f+mLightSensorAdjustSetting);
+ valf *= adj;
+ }
+ // Apply an additional offset to the value based on the adjustment.
+ valf += mLightSensorAdjustSetting/LIGHT_SENSOR_OFFSET_SCALE;
+ // Convert the 0.0-1.0 value back to a brightness integer.
+ int val = (int)((valf*range)+minval) - (LIGHT_SENSOR_RANGE_EXPANSION/2);
+ if (val < minval) val = minval;
+ else if (val > maxval) val = maxval;
+ return val;
} catch (Exception e) {
// guard against null pointer or index out of bounds errors
Slog.e(TAG, "getAutoBrightnessValue", e);
@@ -2468,7 +2512,7 @@
int value = (int)mLightSensorPendingValue;
mLightSensorPendingDecrease = false;
mLightSensorPendingIncrease = false;
- lightSensorChangedLocked(value);
+ lightSensorChangedLocked(value, false);
}
}
}
@@ -2485,12 +2529,12 @@
// force lights recalculation
int value = (int)mLightSensorValue;
mLightSensorValue = -1;
- lightSensorChangedLocked(value);
+ lightSensorChangedLocked(value, false);
}
}
}
- private void lightSensorChangedLocked(int value) {
+ private void lightSensorChangedLocked(int value, boolean immediate) {
if (mDebugLightSensor) {
Slog.d(TAG, "lightSensorChangedLocked " + value);
}
@@ -2536,7 +2580,8 @@
if (mAutoBrightessEnabled && mScreenBrightnessOverride < 0) {
if (!mSkippedScreenOn) {
- mScreenBrightness.setTargetLocked(lcdValue, AUTOBRIGHTNESS_ANIM_STEPS,
+ mScreenBrightness.setTargetLocked(lcdValue,
+ immediate ? IMMEDIATE_ANIM_STEPS : AUTOBRIGHTNESS_ANIM_STEPS,
INITIAL_SCREEN_BRIGHTNESS, (int)mScreenBrightness.curValue);
}
}
@@ -2684,7 +2729,7 @@
if (mLightSensorValue >= 0) {
int value = (int)mLightSensorValue;
mLightSensorValue = -1;
- lightSensorChangedLocked(value);
+ lightSensorChangedLocked(value, false);
}
}
userActivity(SystemClock.uptimeMillis(), false, BUTTON_EVENT, true);
@@ -2944,10 +2989,28 @@
Binder.restoreCallingIdentity(identity);
}
- // update our animation state
- synchronized (mLocks) {
- mScreenBrightness.targetValue = brightness;
- mScreenBrightness.jumpToTargetLocked();
+ mScreenBrightness.targetValue = brightness;
+ mScreenBrightness.jumpToTargetLocked();
+ }
+ }
+
+ public void setAutoBrightnessAdjustment(float adj) {
+ mContext.enforceCallingOrSelfPermission(android.Manifest.permission.DEVICE_POWER, null);
+ synchronized (mLocks) {
+ mLightSensorAdjustSetting = adj;
+ if (mSensorManager != null && mLightSensorEnabled) {
+ // clear calling identity so sensor manager battery stats are accurate
+ long identity = Binder.clearCallingIdentity();
+ try {
+ // force recompute of backlight values
+ if (mLightSensorValue >= 0) {
+ int value = (int)mLightSensorValue;
+ mLightSensorValue = -1;
+ handleLightSensorValue(value, true);
+ }
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
}
}
}
@@ -3062,7 +3125,7 @@
if (mLightSensorValue >= 0) {
int value = (int)mLightSensorValue;
mLightSensorValue = -1;
- handleLightSensorValue(value);
+ handleLightSensorValue(value, true);
}
mSensorManager.registerListener(mLightListener, mLightSensor,
LIGHT_SENSOR_RATE);
@@ -3122,7 +3185,7 @@
}
};
- private void handleLightSensorValue(int value) {
+ private void handleLightSensorValue(int value, boolean immediate) {
long milliseconds = SystemClock.elapsedRealtime();
if (mLightSensorValue == -1 ||
milliseconds < mLastScreenOnTime + mLightSensorWarmupTime) {
@@ -3130,7 +3193,7 @@
mHandler.removeCallbacks(mAutoBrightnessTask);
mLightSensorPendingDecrease = false;
mLightSensorPendingIncrease = false;
- lightSensorChangedLocked(value);
+ lightSensorChangedLocked(value, immediate);
} else {
if ((value > mLightSensorValue && mLightSensorPendingDecrease) ||
(value < mLightSensorValue && mLightSensorPendingIncrease) ||
@@ -3160,7 +3223,7 @@
if (isScreenTurningOffLocked()) {
return;
}
- handleLightSensorValue((int)event.values[0]);
+ handleLightSensorValue((int)event.values[0], false);
}
}
diff --git a/services/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/java/com/android/server/accessibility/AccessibilityManagerService.java
index 23fa94a..8bda755 100644
--- a/services/java/com/android/server/accessibility/AccessibilityManagerService.java
+++ b/services/java/com/android/server/accessibility/AccessibilityManagerService.java
@@ -46,7 +46,6 @@
import android.util.Slog;
import android.util.SparseArray;
import android.view.IWindow;
-import android.view.View;
import android.view.accessibility.AccessibilityEvent;
import android.view.accessibility.AccessibilityManager;
import android.view.accessibility.AccessibilityNodeInfo;
@@ -96,6 +95,10 @@
private static final int DO_SET_SERVICE_INFO = 10;
+ public static final int ACTIVE_WINDOW_ID = -1;
+
+ public static final long ROOT_NODE_ID = -1;
+
private static int sNextWindowId;
final HandlerCaller mCaller;
@@ -467,7 +470,8 @@
}
}
- public void registerEventListener(IEventListener listener) {
+ public void registerUiTestAutomationService(IEventListener listener,
+ AccessibilityServiceInfo accessibilityServiceInfo) {
mSecurityPolicy.enforceCallingPermission(Manifest.permission.RETRIEVE_WINDOW_CONTENT,
FUNCTION_REGISTER_EVENT_LISTENER);
ComponentName componentName = new ComponentName("foo.bar",
@@ -490,13 +494,23 @@
}
}
// Hook the automation service up.
- AccessibilityServiceInfo accessibilityServiceInfo = new AccessibilityServiceInfo();
- accessibilityServiceInfo.eventTypes = AccessibilityEvent.TYPES_ALL_MASK;
- accessibilityServiceInfo.feedbackType = AccessibilityServiceInfo.FEEDBACK_GENERIC;
Service service = new Service(componentName, accessibilityServiceInfo, true);
service.onServiceConnected(componentName, listener.asBinder());
}
+ public void unregisterUiTestAutomationService(IEventListener listener) {
+ synchronized (mLock) {
+ final int serviceCount = mServices.size();
+ for (int i = 0; i < serviceCount; i++) {
+ Service service = mServices.get(i);
+ if (service.mServiceInterface == listener && service.mIsAutomation) {
+ // Automation service is not bound, so pretend it died to perform clean up.
+ service.binderDied();
+ }
+ }
+ }
+ }
+
/**
* Removes an AccessibilityInteractionConnection.
*
@@ -1070,10 +1084,11 @@
}
}
- public float findAccessibilityNodeInfoByViewIdInActiveWindow(int viewId,
- int interactionId, IAccessibilityInteractionConnectionCallback callback,
- long interrogatingTid)
+ public float findAccessibilityNodeInfoByViewId(int accessibilityWindowId,
+ long accessibilityNodeId, int viewId, int interactionId,
+ IAccessibilityInteractionConnectionCallback callback, long interrogatingTid)
throws RemoteException {
+ final int resolvedWindowId = resolveAccessibilityWindowId(accessibilityWindowId);
IAccessibilityInteractionConnection connection = null;
synchronized (mLock) {
mSecurityPolicy.enforceCanRetrieveWindowContent(this);
@@ -1081,12 +1096,8 @@
if (!permissionGranted) {
return 0;
} else {
- connection = getConnectionToRetrievalAllowingWindowLocked();
+ connection = getConnectionLocked(resolvedWindowId);
if (connection == null) {
- if (DEBUG) {
- Slog.e(LOG_TAG, "No interaction connection to a retrieve "
- + "allowing window.");
- }
return 0;
}
}
@@ -1094,44 +1105,33 @@
final int interrogatingPid = Binder.getCallingPid();
final long identityToken = Binder.clearCallingIdentity();
try {
- connection.findAccessibilityNodeInfoByViewId(viewId, interactionId, callback,
- interrogatingPid, interrogatingTid);
+ connection.findAccessibilityNodeInfoByViewId(accessibilityNodeId, viewId,
+ interactionId, callback, interrogatingPid, interrogatingTid);
} catch (RemoteException re) {
if (DEBUG) {
- Slog.e(LOG_TAG, "Error finding node.");
+ Slog.e(LOG_TAG, "Error findAccessibilityNodeInfoByViewId().");
}
} finally {
Binder.restoreCallingIdentity(identityToken);
}
- return getCompatibilityScale(mSecurityPolicy.getRetrievalAllowingWindowLocked());
+ return getCompatibilityScale(resolvedWindowId);
}
- public float findAccessibilityNodeInfosByTextInActiveWindow(
- String text, int interactionId,
- IAccessibilityInteractionConnectionCallback callback, long threadId)
- throws RemoteException {
- return findAccessibilityNodeInfosByText(text,
- mSecurityPolicy.mRetrievalAlowingWindowId, View.NO_ID, interactionId, callback,
- threadId);
- }
-
- public float findAccessibilityNodeInfosByText(String text,
- int accessibilityWindowId, long accessibilityNodeId, int interactionId,
+ public float findAccessibilityNodeInfosByText(int accessibilityWindowId,
+ long accessibilityNodeId, String text, int interactionId,
IAccessibilityInteractionConnectionCallback callback, long interrogatingTid)
throws RemoteException {
+ final int resolvedWindowId = resolveAccessibilityWindowId(accessibilityWindowId);
IAccessibilityInteractionConnection connection = null;
synchronized (mLock) {
mSecurityPolicy.enforceCanRetrieveWindowContent(this);
final boolean permissionGranted =
- mSecurityPolicy.canGetAccessibilityNodeInfoLocked(this, accessibilityWindowId);
+ mSecurityPolicy.canGetAccessibilityNodeInfoLocked(this, resolvedWindowId);
if (!permissionGranted) {
return 0;
} else {
- connection = getConnectionToRetrievalAllowingWindowLocked();
+ connection = getConnectionLocked(resolvedWindowId);
if (connection == null) {
- if (DEBUG) {
- Slog.e(LOG_TAG, "No interaction connection to focused window.");
- }
return 0;
}
}
@@ -1139,40 +1139,35 @@
final int interrogatingPid = Binder.getCallingPid();
final long identityToken = Binder.clearCallingIdentity();
try {
- connection.findAccessibilityNodeInfosByText(text, accessibilityNodeId,
+ connection.findAccessibilityNodeInfosByText(accessibilityNodeId, text,
interactionId, callback, interrogatingPid, interrogatingTid);
} catch (RemoteException re) {
if (DEBUG) {
- Slog.e(LOG_TAG, "Error finding node.");
+ Slog.e(LOG_TAG, "Error calling findAccessibilityNodeInfosByText()");
}
} finally {
Binder.restoreCallingIdentity(identityToken);
}
- return getCompatibilityScale(accessibilityWindowId);
+ return getCompatibilityScale(resolvedWindowId);
}
public float findAccessibilityNodeInfoByAccessibilityId(int accessibilityWindowId,
long accessibilityNodeId, int interactionId,
IAccessibilityInteractionConnectionCallback callback, long interrogatingTid)
throws RemoteException {
+ final int resolvedWindowId = resolveAccessibilityWindowId(accessibilityWindowId);
IAccessibilityInteractionConnection connection = null;
synchronized (mLock) {
mSecurityPolicy.enforceCanRetrieveWindowContent(this);
final boolean permissionGranted =
- mSecurityPolicy.canGetAccessibilityNodeInfoLocked(this, accessibilityWindowId);
+ mSecurityPolicy.canGetAccessibilityNodeInfoLocked(this, resolvedWindowId);
if (!permissionGranted) {
return 0;
} else {
- AccessibilityConnectionWrapper wrapper =
- mWindowIdToInteractionConnectionWrapperMap.get(accessibilityWindowId);
- if (wrapper == null) {
- if (DEBUG) {
- Slog.e(LOG_TAG, "No interaction connection to window: "
- + accessibilityWindowId);
- }
+ connection = getConnectionLocked(resolvedWindowId);
+ if (connection == null) {
return 0;
}
- connection = wrapper.mConnection;
}
}
final int interrogatingPid = Binder.getCallingPid();
@@ -1182,35 +1177,29 @@
interactionId, callback, interrogatingPid, interrogatingTid);
} catch (RemoteException re) {
if (DEBUG) {
- Slog.e(LOG_TAG, "Error requesting node with accessibilityNodeId: "
- + accessibilityNodeId);
+ Slog.e(LOG_TAG, "Error calling findAccessibilityNodeInfoByAccessibilityId()");
}
} finally {
Binder.restoreCallingIdentity(identityToken);
}
- return getCompatibilityScale(accessibilityWindowId);
+ return getCompatibilityScale(resolvedWindowId);
}
public boolean performAccessibilityAction(int accessibilityWindowId,
long accessibilityNodeId, int action, int interactionId,
IAccessibilityInteractionConnectionCallback callback, long interrogatingTid) {
+ final int resolvedWindowId = resolveAccessibilityWindowId(accessibilityWindowId);
IAccessibilityInteractionConnection connection = null;
synchronized (mLock) {
final boolean permissionGranted = mSecurityPolicy.canPerformActionLocked(this,
- accessibilityWindowId, action);
+ resolvedWindowId, action);
if (!permissionGranted) {
return false;
} else {
- AccessibilityConnectionWrapper wrapper =
- mWindowIdToInteractionConnectionWrapperMap.get(accessibilityWindowId);
- if (wrapper == null) {
- if (DEBUG) {
- Slog.e(LOG_TAG, "No interaction connection to window: "
- + accessibilityWindowId);
- }
+ connection = getConnectionLocked(resolvedWindowId);
+ if (connection == null) {
return false;
}
- connection = wrapper.mConnection;
}
}
final int interrogatingPid = Binder.getCallingPid();
@@ -1220,8 +1209,7 @@
callback, interrogatingPid, interrogatingTid);
} catch (RemoteException re) {
if (DEBUG) {
- Slog.e(LOG_TAG, "Error requesting node with accessibilityNodeId: "
- + accessibilityNodeId);
+ Slog.e(LOG_TAG, "Error calling performAccessibilityAction()");
}
} finally {
Binder.restoreCallingIdentity(identityToken);
@@ -1265,14 +1253,26 @@
}
}
- private IAccessibilityInteractionConnection getConnectionToRetrievalAllowingWindowLocked() {
- final int windowId = mSecurityPolicy.getRetrievalAllowingWindowLocked();
+ private IAccessibilityInteractionConnection getConnectionLocked(int windowId) {
if (DEBUG) {
Slog.i(LOG_TAG, "Trying to get interaction connection to windowId: " + windowId);
}
- AccessibilityConnectionWrapper wrapper =
- mWindowIdToInteractionConnectionWrapperMap.get(windowId);
- return (wrapper != null) ? wrapper.mConnection : null;
+ AccessibilityConnectionWrapper wrapper = mWindowIdToInteractionConnectionWrapperMap.get(
+ windowId);
+ if (wrapper != null && wrapper.mConnection != null) {
+ return wrapper.mConnection;
+ }
+ if (DEBUG) {
+ Slog.e(LOG_TAG, "No interaction connection to window: " + windowId);
+ }
+ return null;
+ }
+
+ private int resolveAccessibilityWindowId(int accessibilityWindowId) {
+ if (accessibilityWindowId == ACTIVE_WINDOW_ID) {
+ return mSecurityPolicy.mRetrievalAlowingWindowId;
+ }
+ return accessibilityWindowId;
}
private float getCompatibilityScale(int windowId) {
diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java
index db0a736..3a6a3de 100644
--- a/services/java/com/android/server/am/ActivityManagerService.java
+++ b/services/java/com/android/server/am/ActivityManagerService.java
@@ -158,6 +158,7 @@
static final boolean DEBUG_OOM_ADJ = localLOGV || false;
static final boolean DEBUG_TRANSITION = localLOGV || false;
static final boolean DEBUG_BROADCAST = localLOGV || false;
+ static final boolean DEBUG_BACKGROUND_BROADCAST = DEBUG_BROADCAST || false;
static final boolean DEBUG_BROADCAST_LIGHT = DEBUG_BROADCAST || false;
static final boolean DEBUG_SERVICE = localLOGV || false;
static final boolean DEBUG_SERVICE_EXECUTING = localLOGV || false;
@@ -221,7 +222,8 @@
static final int CPU_MIN_CHECK_DURATION = (DEBUG_POWER_QUICK ? 1 : 5) * 60*1000;
// How long we allow a receiver to run before giving up on it.
- static final int BROADCAST_TIMEOUT = 10*1000;
+ static final int BROADCAST_FG_TIMEOUT = 10*1000;
+ static final int BROADCAST_BG_TIMEOUT = 60*1000;
// How long we wait for a service to finish executing.
static final int SERVICE_TIMEOUT = 20*1000;
@@ -276,33 +278,823 @@
= new ArrayList<PendingActivityLaunch>();
/**
- * List of all active broadcasts that are to be executed immediately
- * (without waiting for another broadcast to finish). Currently this only
- * contains broadcasts to registered receivers, to avoid spinning up
- * a bunch of processes to execute IntentReceiver components.
+ * BROADCASTS
+ *
+ * We keep two broadcast queues and associated bookkeeping, one for those at
+ * foreground priority, and one for normal (background-priority) broadcasts.
*/
- final ArrayList<BroadcastRecord> mParallelBroadcasts
- = new ArrayList<BroadcastRecord>();
+ public class BroadcastQueue {
+ static final String TAG = "BroadcastQueue";
- /**
- * List of all active broadcasts that are to be executed one at a time.
- * The object at the top of the list is the currently activity broadcasts;
- * those after it are waiting for the top to finish..
- */
- final ArrayList<BroadcastRecord> mOrderedBroadcasts
- = new ArrayList<BroadcastRecord>();
+ static final int MAX_BROADCAST_HISTORY = 25;
- /**
- * Historical data of past broadcasts, for debugging.
- */
- static final int MAX_BROADCAST_HISTORY = 25;
- final BroadcastRecord[] mBroadcastHistory
- = new BroadcastRecord[MAX_BROADCAST_HISTORY];
+ /**
+ * Recognizable moniker for this queue
+ */
+ String mQueueName;
- /**
- * Set when we current have a BROADCAST_INTENT_MSG in flight.
- */
- boolean mBroadcastsScheduled = false;
+ /**
+ * Timeout period for this queue's broadcasts
+ */
+ long mTimeoutPeriod;
+
+ /**
+ * Lists of all active broadcasts that are to be executed immediately
+ * (without waiting for another broadcast to finish). Currently this only
+ * contains broadcasts to registered receivers, to avoid spinning up
+ * a bunch of processes to execute IntentReceiver components. Background-
+ * and foreground-priority broadcasts are queued separately.
+ */
+ final ArrayList<BroadcastRecord> mParallelBroadcasts
+ = new ArrayList<BroadcastRecord>();
+ /**
+ * List of all active broadcasts that are to be executed one at a time.
+ * The object at the top of the list is the currently activity broadcasts;
+ * those after it are waiting for the top to finish. As with parallel
+ * broadcasts, separate background- and foreground-priority queues are
+ * maintained.
+ */
+ final ArrayList<BroadcastRecord> mOrderedBroadcasts
+ = new ArrayList<BroadcastRecord>();
+
+ /**
+ * Historical data of past broadcasts, for debugging.
+ */
+ final BroadcastRecord[] mBroadcastHistory
+ = new BroadcastRecord[MAX_BROADCAST_HISTORY];
+
+ /**
+ * Set when we current have a BROADCAST_INTENT_MSG in flight.
+ */
+ boolean mBroadcastsScheduled = false;
+
+ /**
+ * True if we have a pending unexpired BROADCAST_TIMEOUT_MSG posted to our handler.
+ */
+ boolean mPendingBroadcastTimeoutMessage;
+
+ /**
+ * Intent broadcasts that we have tried to start, but are
+ * waiting for the application's process to be created. We only
+ * need one per scheduling class (instead of a list) because we always
+ * process broadcasts one at a time, so no others can be started while
+ * waiting for this one.
+ */
+ BroadcastRecord mPendingBroadcast = null;
+
+ /**
+ * The receiver index that is pending, to restart the broadcast if needed.
+ */
+ int mPendingBroadcastRecvIndex;
+
+ BroadcastQueue(String name, long timeoutPeriod) {
+ mQueueName = name;
+ mTimeoutPeriod = timeoutPeriod;
+ }
+
+ public boolean isPendingBroadcastProcessLocked(int pid) {
+ return mPendingBroadcast != null && mPendingBroadcast.curApp.pid == pid;
+ }
+
+ public void enqueueParallelBroadcastLocked(BroadcastRecord r) {
+ mParallelBroadcasts.add(r);
+ }
+
+ public void enqueueOrderedBroadcastLocked(BroadcastRecord r) {
+ mOrderedBroadcasts.add(r);
+ }
+
+ public final boolean replaceParallelBroadcastLocked(BroadcastRecord r) {
+ for (int i=mParallelBroadcasts.size()-1; i>=0; i--) {
+ if (r.intent.filterEquals(mParallelBroadcasts.get(i).intent)) {
+ if (DEBUG_BROADCAST) Slog.v(TAG,
+ "***** DROPPING PARALLEL ["
+ + mQueueName + "]: " + r.intent);
+ mParallelBroadcasts.set(i, r);
+ return true;
+ }
+ }
+ return false;
+ }
+
+ public final boolean replaceOrderedBroadcastLocked(BroadcastRecord r) {
+ for (int i=mOrderedBroadcasts.size()-1; i>0; i--) {
+ if (r.intent.filterEquals(mOrderedBroadcasts.get(i).intent)) {
+ if (DEBUG_BROADCAST) Slog.v(TAG,
+ "***** DROPPING ORDERED ["
+ + mQueueName + "]: " + r.intent);
+ mOrderedBroadcasts.set(i, r);
+ return true;
+ }
+ }
+ return false;
+ }
+
+ public boolean sendPendingBroadcastsLocked(ProcessRecord app) {
+ boolean didSomething = false;
+ final BroadcastRecord br = mPendingBroadcast;
+ if (br != null && br.curApp.pid == app.pid) {
+ try {
+ mPendingBroadcast = null;
+ processCurBroadcastLocked(br, app);
+ didSomething = true;
+ } catch (Exception e) {
+ Slog.w(TAG, "Exception in new application when starting receiver "
+ + br.curComponent.flattenToShortString(), e);
+ logBroadcastReceiverDiscardLocked(br);
+ finishReceiverLocked(br, br.resultCode, br.resultData,
+ br.resultExtras, br.resultAbort, true);
+ scheduleBroadcastsLocked();
+ // We need to reset the state if we fails to start the receiver.
+ br.state = BroadcastRecord.IDLE;
+ throw new RuntimeException(e.getMessage());
+ }
+ }
+ return didSomething;
+ }
+
+ public void skipPendingBroadcastLocked(int pid) {
+ final BroadcastRecord br = mPendingBroadcast;
+ if (br != null && br.curApp.pid == pid) {
+ br.state = BroadcastRecord.IDLE;
+ br.nextReceiver = mPendingBroadcastRecvIndex;
+ mPendingBroadcast = null;
+ scheduleBroadcastsLocked();
+ }
+ }
+
+ public void skipCurrentReceiverLocked(ProcessRecord app) {
+ boolean reschedule = false;
+ BroadcastRecord r = app.curReceiver;
+ if (r != null) {
+ // The current broadcast is waiting for this app's receiver
+ // to be finished. Looks like that's not going to happen, so
+ // let the broadcast continue.
+ logBroadcastReceiverDiscardLocked(r);
+ finishReceiverLocked(r, r.resultCode, r.resultData,
+ r.resultExtras, r.resultAbort, true);
+ reschedule = true;
+ }
+
+ r = mPendingBroadcast;
+ if (r != null && r.curApp == app) {
+ if (DEBUG_BROADCAST) Slog.v(TAG,
+ "[" + mQueueName + "] skip & discard pending app " + r);
+ logBroadcastReceiverDiscardLocked(r);
+ finishReceiverLocked(r, r.resultCode, r.resultData,
+ r.resultExtras, r.resultAbort, true);
+ reschedule = true;
+ }
+ if (reschedule) {
+ scheduleBroadcastsLocked();
+ }
+ }
+
+ public void scheduleBroadcastsLocked() {
+ if (DEBUG_BROADCAST) Slog.v(TAG, "Schedule broadcasts ["
+ + mQueueName + "]: current="
+ + mBroadcastsScheduled);
+
+ if (mBroadcastsScheduled) {
+ return;
+ }
+ mHandler.sendMessage(mHandler.obtainMessage(BROADCAST_INTENT_MSG, this));
+ mBroadcastsScheduled = true;
+ }
+
+ public BroadcastRecord getMatchingOrderedReceiver(IBinder receiver) {
+ if (mOrderedBroadcasts.size() > 0) {
+ final BroadcastRecord r = mOrderedBroadcasts.get(0);
+ if (r != null && r.receiver == receiver) {
+ return r;
+ }
+ }
+ return null;
+ }
+
+ public boolean finishReceiverLocked(BroadcastRecord r, int resultCode,
+ String resultData, Bundle resultExtras, boolean resultAbort,
+ boolean explicit) {
+ int state = r.state;
+ r.state = BroadcastRecord.IDLE;
+ if (state == BroadcastRecord.IDLE) {
+ if (explicit) {
+ Slog.w(TAG, "finishReceiver [" + mQueueName + "] called but state is IDLE");
+ }
+ }
+ r.receiver = null;
+ r.intent.setComponent(null);
+ if (r.curApp != null) {
+ r.curApp.curReceiver = null;
+ }
+ if (r.curFilter != null) {
+ r.curFilter.receiverList.curBroadcast = null;
+ }
+ r.curFilter = null;
+ r.curApp = null;
+ r.curComponent = null;
+ r.curReceiver = null;
+ mPendingBroadcast = null;
+
+ r.resultCode = resultCode;
+ r.resultData = resultData;
+ r.resultExtras = resultExtras;
+ r.resultAbort = resultAbort;
+
+ // We will process the next receiver right now if this is finishing
+ // an app receiver (which is always asynchronous) or after we have
+ // come back from calling a receiver.
+ return state == BroadcastRecord.APP_RECEIVE
+ || state == BroadcastRecord.CALL_DONE_RECEIVE;
+ }
+
+ private final void processNextBroadcast(boolean fromMsg) {
+ synchronized(ActivityManagerService.this) {
+ BroadcastRecord r;
+
+ if (DEBUG_BROADCAST) Slog.v(TAG, "processNextBroadcast ["
+ + mQueueName + "]: "
+ + mParallelBroadcasts.size() + " broadcasts, "
+ + mOrderedBroadcasts.size() + " ordered broadcasts");
+
+ updateCpuStats();
+
+ if (fromMsg) {
+ mBroadcastsScheduled = false;
+ }
+
+ // First, deliver any non-serialized broadcasts right away.
+ while (mParallelBroadcasts.size() > 0) {
+ r = mParallelBroadcasts.remove(0);
+ r.dispatchTime = SystemClock.uptimeMillis();
+ r.dispatchClockTime = System.currentTimeMillis();
+ final int N = r.receivers.size();
+ if (DEBUG_BROADCAST_LIGHT) Slog.v(TAG, "Processing parallel broadcast ["
+ + mQueueName + "] " + r);
+ for (int i=0; i<N; i++) {
+ Object target = r.receivers.get(i);
+ if (DEBUG_BROADCAST) Slog.v(TAG,
+ "Delivering non-ordered on [" + mQueueName + "] to registered "
+ + target + ": " + r);
+ deliverToRegisteredReceiverLocked(r, (BroadcastFilter)target, false);
+ }
+ addBroadcastToHistoryLocked(r);
+ if (DEBUG_BROADCAST_LIGHT) Slog.v(TAG, "Done with parallel broadcast ["
+ + mQueueName + "] " + r);
+ }
+
+ // Now take care of the next serialized one...
+
+ // If we are waiting for a process to come up to handle the next
+ // broadcast, then do nothing at this point. Just in case, we
+ // check that the process we're waiting for still exists.
+ if (mPendingBroadcast != null) {
+ if (DEBUG_BROADCAST_LIGHT) {
+ Slog.v(TAG, "processNextBroadcast ["
+ + mQueueName + "]: waiting for "
+ + mPendingBroadcast.curApp);
+ }
+
+ boolean isDead;
+ synchronized (mPidsSelfLocked) {
+ isDead = (mPidsSelfLocked.get(mPendingBroadcast.curApp.pid) == null);
+ }
+ if (!isDead) {
+ // It's still alive, so keep waiting
+ return;
+ } else {
+ Slog.w(TAG, "pending app ["
+ + mQueueName + "]" + mPendingBroadcast.curApp
+ + " died before responding to broadcast");
+ mPendingBroadcast.state = BroadcastRecord.IDLE;
+ mPendingBroadcast.nextReceiver = mPendingBroadcastRecvIndex;
+ mPendingBroadcast = null;
+ }
+ }
+
+ boolean looped = false;
+
+ do {
+ if (mOrderedBroadcasts.size() == 0) {
+ // No more broadcasts pending, so all done!
+ scheduleAppGcsLocked();
+ if (looped) {
+ // If we had finished the last ordered broadcast, then
+ // make sure all processes have correct oom and sched
+ // adjustments.
+ updateOomAdjLocked();
+ }
+ return;
+ }
+ r = mOrderedBroadcasts.get(0);
+ boolean forceReceive = false;
+
+ // Ensure that even if something goes awry with the timeout
+ // detection, we catch "hung" broadcasts here, discard them,
+ // and continue to make progress.
+ //
+ // This is only done if the system is ready so that PRE_BOOT_COMPLETED
+ // receivers don't get executed with timeouts. They're intended for
+ // one time heavy lifting after system upgrades and can take
+ // significant amounts of time.
+ int numReceivers = (r.receivers != null) ? r.receivers.size() : 0;
+ if (mProcessesReady && r.dispatchTime > 0) {
+ long now = SystemClock.uptimeMillis();
+ if ((numReceivers > 0) &&
+ (now > r.dispatchTime + (2*mTimeoutPeriod*numReceivers))) {
+ Slog.w(TAG, "Hung broadcast ["
+ + mQueueName + "] discarded after timeout failure:"
+ + " now=" + now
+ + " dispatchTime=" + r.dispatchTime
+ + " startTime=" + r.receiverTime
+ + " intent=" + r.intent
+ + " numReceivers=" + numReceivers
+ + " nextReceiver=" + r.nextReceiver
+ + " state=" + r.state);
+ broadcastTimeoutLocked(false); // forcibly finish this broadcast
+ forceReceive = true;
+ r.state = BroadcastRecord.IDLE;
+ }
+ }
+
+ if (r.state != BroadcastRecord.IDLE) {
+ if (DEBUG_BROADCAST) Slog.d(TAG,
+ "processNextBroadcast("
+ + mQueueName + ") called when not idle (state="
+ + r.state + ")");
+ return;
+ }
+
+ if (r.receivers == null || r.nextReceiver >= numReceivers
+ || r.resultAbort || forceReceive) {
+ // No more receivers for this broadcast! Send the final
+ // result if requested...
+ if (r.resultTo != null) {
+ try {
+ if (DEBUG_BROADCAST) {
+ int seq = r.intent.getIntExtra("seq", -1);
+ Slog.i(TAG, "Finishing broadcast ["
+ + mQueueName + "] " + r.intent.getAction()
+ + " seq=" + seq + " app=" + r.callerApp);
+ }
+ performReceiveLocked(r.callerApp, r.resultTo,
+ new Intent(r.intent), r.resultCode,
+ r.resultData, r.resultExtras, false, false);
+ // Set this to null so that the reference
+ // (local and remote) isnt kept in the mBroadcastHistory.
+ r.resultTo = null;
+ } catch (RemoteException e) {
+ Slog.w(TAG, "Failure ["
+ + mQueueName + "] sending broadcast result of "
+ + r.intent, e);
+ }
+ }
+
+ if (DEBUG_BROADCAST) Slog.v(TAG, "Cancelling BROADCAST_TIMEOUT_MSG");
+ cancelBroadcastTimeoutLocked();
+
+ if (DEBUG_BROADCAST_LIGHT) Slog.v(TAG, "Finished with ordered broadcast "
+ + r);
+
+ // ... and on to the next...
+ addBroadcastToHistoryLocked(r);
+ mOrderedBroadcasts.remove(0);
+ r = null;
+ looped = true;
+ continue;
+ }
+ } while (r == null);
+
+ // Get the next receiver...
+ int recIdx = r.nextReceiver++;
+
+ // Keep track of when this receiver started, and make sure there
+ // is a timeout message pending to kill it if need be.
+ r.receiverTime = SystemClock.uptimeMillis();
+ if (recIdx == 0) {
+ r.dispatchTime = r.receiverTime;
+ r.dispatchClockTime = System.currentTimeMillis();
+ if (DEBUG_BROADCAST_LIGHT) Slog.v(TAG, "Processing ordered broadcast ["
+ + mQueueName + "] " + r);
+ }
+ if (! mPendingBroadcastTimeoutMessage) {
+ long timeoutTime = r.receiverTime + mTimeoutPeriod;
+ if (DEBUG_BROADCAST) Slog.v(TAG,
+ "Submitting BROADCAST_TIMEOUT_MSG ["
+ + mQueueName + "] for " + r + " at " + timeoutTime);
+ setBroadcastTimeoutLocked(timeoutTime);
+ }
+
+ Object nextReceiver = r.receivers.get(recIdx);
+ if (nextReceiver instanceof BroadcastFilter) {
+ // Simple case: this is a registered receiver who gets
+ // a direct call.
+ BroadcastFilter filter = (BroadcastFilter)nextReceiver;
+ if (DEBUG_BROADCAST) Slog.v(TAG,
+ "Delivering ordered ["
+ + mQueueName + "] to registered "
+ + filter + ": " + r);
+ deliverToRegisteredReceiverLocked(r, filter, r.ordered);
+ if (r.receiver == null || !r.ordered) {
+ // The receiver has already finished, so schedule to
+ // process the next one.
+ if (DEBUG_BROADCAST) Slog.v(TAG, "Quick finishing ["
+ + mQueueName + "]: ordered="
+ + r.ordered + " receiver=" + r.receiver);
+ r.state = BroadcastRecord.IDLE;
+ scheduleBroadcastsLocked();
+ }
+ return;
+ }
+
+ // Hard case: need to instantiate the receiver, possibly
+ // starting its application process to host it.
+
+ ResolveInfo info =
+ (ResolveInfo)nextReceiver;
+
+ boolean skip = false;
+ int perm = checkComponentPermission(info.activityInfo.permission,
+ r.callingPid, r.callingUid, info.activityInfo.applicationInfo.uid,
+ info.activityInfo.exported);
+ if (perm != PackageManager.PERMISSION_GRANTED) {
+ if (!info.activityInfo.exported) {
+ Slog.w(TAG, "Permission Denial: broadcasting "
+ + r.intent.toString()
+ + " from " + r.callerPackage + " (pid=" + r.callingPid
+ + ", uid=" + r.callingUid + ")"
+ + " is not exported from uid " + info.activityInfo.applicationInfo.uid
+ + " due to receiver " + info.activityInfo.packageName
+ + "/" + info.activityInfo.name);
+ } else {
+ Slog.w(TAG, "Permission Denial: broadcasting "
+ + r.intent.toString()
+ + " from " + r.callerPackage + " (pid=" + r.callingPid
+ + ", uid=" + r.callingUid + ")"
+ + " requires " + info.activityInfo.permission
+ + " due to receiver " + info.activityInfo.packageName
+ + "/" + info.activityInfo.name);
+ }
+ skip = true;
+ }
+ if (info.activityInfo.applicationInfo.uid != Process.SYSTEM_UID &&
+ r.requiredPermission != null) {
+ try {
+ perm = AppGlobals.getPackageManager().
+ checkPermission(r.requiredPermission,
+ info.activityInfo.applicationInfo.packageName);
+ } catch (RemoteException e) {
+ perm = PackageManager.PERMISSION_DENIED;
+ }
+ if (perm != PackageManager.PERMISSION_GRANTED) {
+ Slog.w(TAG, "Permission Denial: receiving "
+ + r.intent + " to "
+ + info.activityInfo.applicationInfo.packageName
+ + " requires " + r.requiredPermission
+ + " due to sender " + r.callerPackage
+ + " (uid " + r.callingUid + ")");
+ skip = true;
+ }
+ }
+ if (r.curApp != null && r.curApp.crashing) {
+ // If the target process is crashing, just skip it.
+ if (DEBUG_BROADCAST) Slog.v(TAG,
+ "Skipping deliver ordered ["
+ + mQueueName + "] " + r + " to " + r.curApp
+ + ": process crashing");
+ skip = true;
+ }
+
+ if (skip) {
+ if (DEBUG_BROADCAST) Slog.v(TAG,
+ "Skipping delivery of ordered ["
+ + mQueueName + "] " + r + " for whatever reason");
+ r.receiver = null;
+ r.curFilter = null;
+ r.state = BroadcastRecord.IDLE;
+ scheduleBroadcastsLocked();
+ return;
+ }
+
+ r.state = BroadcastRecord.APP_RECEIVE;
+ String targetProcess = info.activityInfo.processName;
+ r.curComponent = new ComponentName(
+ info.activityInfo.applicationInfo.packageName,
+ info.activityInfo.name);
+ r.curReceiver = info.activityInfo;
+
+ // Broadcast is being executed, its package can't be stopped.
+ try {
+ AppGlobals.getPackageManager().setPackageStoppedState(
+ r.curComponent.getPackageName(), false);
+ } catch (RemoteException e) {
+ } catch (IllegalArgumentException e) {
+ Slog.w(TAG, "Failed trying to unstop package "
+ + r.curComponent.getPackageName() + ": " + e);
+ }
+
+ // Is this receiver's application already running?
+ ProcessRecord app = getProcessRecordLocked(targetProcess,
+ info.activityInfo.applicationInfo.uid);
+ if (app != null && app.thread != null) {
+ try {
+ app.addPackage(info.activityInfo.packageName);
+ processCurBroadcastLocked(r, app);
+ return;
+ } catch (RemoteException e) {
+ Slog.w(TAG, "Exception when sending broadcast to "
+ + r.curComponent, e);
+ }
+
+ // If a dead object exception was thrown -- fall through to
+ // restart the application.
+ }
+
+ // Not running -- get it started, to be executed when the app comes up.
+ if (DEBUG_BROADCAST) Slog.v(TAG,
+ "Need to start app ["
+ + mQueueName + "] " + targetProcess + " for broadcast " + r);
+ if ((r.curApp=startProcessLocked(targetProcess,
+ info.activityInfo.applicationInfo, true,
+ r.intent.getFlags() | Intent.FLAG_FROM_BACKGROUND,
+ "broadcast", r.curComponent,
+ (r.intent.getFlags()&Intent.FLAG_RECEIVER_BOOT_UPGRADE) != 0))
+ == null) {
+ // Ah, this recipient is unavailable. Finish it if necessary,
+ // and mark the broadcast record as ready for the next.
+ Slog.w(TAG, "Unable to launch app "
+ + info.activityInfo.applicationInfo.packageName + "/"
+ + info.activityInfo.applicationInfo.uid + " for broadcast "
+ + r.intent + ": process is bad");
+ logBroadcastReceiverDiscardLocked(r);
+ finishReceiverLocked(r, r.resultCode, r.resultData,
+ r.resultExtras, r.resultAbort, true);
+ scheduleBroadcastsLocked();
+ r.state = BroadcastRecord.IDLE;
+ return;
+ }
+
+ mPendingBroadcast = r;
+ mPendingBroadcastRecvIndex = recIdx;
+ }
+ }
+
+ final void setBroadcastTimeoutLocked(long timeoutTime) {
+ if (! mPendingBroadcastTimeoutMessage) {
+ Message msg = mHandler.obtainMessage(BROADCAST_TIMEOUT_MSG, this);
+ mHandler.sendMessageAtTime(msg, timeoutTime);
+ mPendingBroadcastTimeoutMessage = true;
+ }
+ }
+
+ final void cancelBroadcastTimeoutLocked() {
+ if (mPendingBroadcastTimeoutMessage) {
+ mHandler.removeMessages(BROADCAST_TIMEOUT_MSG, this);
+ mPendingBroadcastTimeoutMessage = false;
+ }
+ }
+
+ final void broadcastTimeoutLocked(boolean fromMsg) {
+ if (fromMsg) {
+ mPendingBroadcastTimeoutMessage = false;
+ }
+
+ if (mOrderedBroadcasts.size() == 0) {
+ return;
+ }
+
+ long now = SystemClock.uptimeMillis();
+ BroadcastRecord r = mOrderedBroadcasts.get(0);
+ if (fromMsg) {
+ if (mDidDexOpt) {
+ // Delay timeouts until dexopt finishes.
+ mDidDexOpt = false;
+ long timeoutTime = SystemClock.uptimeMillis() + mTimeoutPeriod;
+ setBroadcastTimeoutLocked(timeoutTime);
+ return;
+ }
+ if (! mProcessesReady) {
+ // Only process broadcast timeouts if the system is ready. That way
+ // PRE_BOOT_COMPLETED broadcasts can't timeout as they are intended
+ // to do heavy lifting for system up.
+ return;
+ }
+
+ long timeoutTime = r.receiverTime + mTimeoutPeriod;
+ if (timeoutTime > now) {
+ // We can observe premature timeouts because we do not cancel and reset the
+ // broadcast timeout message after each receiver finishes. Instead, we set up
+ // an initial timeout then kick it down the road a little further as needed
+ // when it expires.
+ if (DEBUG_BROADCAST) Slog.v(TAG,
+ "Premature timeout ["
+ + mQueueName + "] @ " + now + ": resetting BROADCAST_TIMEOUT_MSG for "
+ + timeoutTime);
+ setBroadcastTimeoutLocked(timeoutTime);
+ return;
+ }
+ }
+
+ Slog.w(TAG, "Timeout of broadcast " + r + " - receiver=" + r.receiver
+ + ", started " + (now - r.receiverTime) + "ms ago");
+ r.receiverTime = now;
+ r.anrCount++;
+
+ // Current receiver has passed its expiration date.
+ if (r.nextReceiver <= 0) {
+ Slog.w(TAG, "Timeout on receiver with nextReceiver <= 0");
+ return;
+ }
+
+ ProcessRecord app = null;
+ String anrMessage = null;
+
+ Object curReceiver = r.receivers.get(r.nextReceiver-1);
+ Slog.w(TAG, "Receiver during timeout: " + curReceiver);
+ logBroadcastReceiverDiscardLocked(r);
+ if (curReceiver instanceof BroadcastFilter) {
+ BroadcastFilter bf = (BroadcastFilter)curReceiver;
+ if (bf.receiverList.pid != 0
+ && bf.receiverList.pid != MY_PID) {
+ synchronized (ActivityManagerService.this.mPidsSelfLocked) {
+ app = ActivityManagerService.this.mPidsSelfLocked.get(
+ bf.receiverList.pid);
+ }
+ }
+ } else {
+ app = r.curApp;
+ }
+
+ if (app != null) {
+ anrMessage = "Broadcast of " + r.intent.toString();
+ }
+
+ if (mPendingBroadcast == r) {
+ mPendingBroadcast = null;
+ }
+
+ // Move on to the next receiver.
+ finishReceiverLocked(r, r.resultCode, r.resultData,
+ r.resultExtras, r.resultAbort, true);
+ scheduleBroadcastsLocked();
+
+ if (anrMessage != null) {
+ // Post the ANR to the handler since we do not want to process ANRs while
+ // potentially holding our lock.
+ mHandler.post(new AppNotResponding(app, anrMessage));
+ }
+ }
+
+ private final void addBroadcastToHistoryLocked(BroadcastRecord r) {
+ if (r.callingUid < 0) {
+ // This was from a registerReceiver() call; ignore it.
+ return;
+ }
+ System.arraycopy(mBroadcastHistory, 0, mBroadcastHistory, 1,
+ MAX_BROADCAST_HISTORY-1);
+ r.finishTime = SystemClock.uptimeMillis();
+ mBroadcastHistory[0] = r;
+ }
+
+ final void logBroadcastReceiverDiscardLocked(BroadcastRecord r) {
+ if (r.nextReceiver > 0) {
+ Object curReceiver = r.receivers.get(r.nextReceiver-1);
+ if (curReceiver instanceof BroadcastFilter) {
+ BroadcastFilter bf = (BroadcastFilter) curReceiver;
+ EventLog.writeEvent(EventLogTags.AM_BROADCAST_DISCARD_FILTER,
+ System.identityHashCode(r),
+ r.intent.getAction(),
+ r.nextReceiver - 1,
+ System.identityHashCode(bf));
+ } else {
+ EventLog.writeEvent(EventLogTags.AM_BROADCAST_DISCARD_APP,
+ System.identityHashCode(r),
+ r.intent.getAction(),
+ r.nextReceiver - 1,
+ ((ResolveInfo)curReceiver).toString());
+ }
+ } else {
+ Slog.w(TAG, "Discarding broadcast before first receiver is invoked: "
+ + r);
+ EventLog.writeEvent(EventLogTags.AM_BROADCAST_DISCARD_APP,
+ System.identityHashCode(r),
+ r.intent.getAction(),
+ r.nextReceiver,
+ "NONE");
+ }
+ }
+
+ final boolean dumpLocked(FileDescriptor fd, PrintWriter pw, String[] args,
+ int opti, boolean dumpAll, String dumpPackage, boolean needSep) {
+ if (mParallelBroadcasts.size() > 0 || mOrderedBroadcasts.size() > 0
+ || mPendingBroadcast != null) {
+ boolean printed = false;
+ for (int i=mParallelBroadcasts.size()-1; i>=0; i--) {
+ BroadcastRecord br = mParallelBroadcasts.get(i);
+ if (dumpPackage != null && !dumpPackage.equals(br.callerPackage)) {
+ continue;
+ }
+ if (!printed) {
+ if (needSep) {
+ pw.println();
+ needSep = false;
+ }
+ printed = true;
+ pw.println(" Active broadcasts [" + mQueueName + "]:");
+ }
+ pw.println(" Broadcast #" + i + ":");
+ br.dump(pw, " ");
+ }
+ printed = false;
+ needSep = true;
+ for (int i=mOrderedBroadcasts.size()-1; i>=0; i--) {
+ BroadcastRecord br = mOrderedBroadcasts.get(i);
+ if (dumpPackage != null && !dumpPackage.equals(br.callerPackage)) {
+ continue;
+ }
+ if (!printed) {
+ if (needSep) {
+ pw.println();
+ }
+ needSep = true;
+ pw.println(" Active ordered broadcasts [" + mQueueName + "]:");
+ }
+ pw.println(" Ordered Broadcast #" + i + ":");
+ mOrderedBroadcasts.get(i).dump(pw, " ");
+ }
+ if (dumpPackage == null || (mPendingBroadcast != null
+ && dumpPackage.equals(mPendingBroadcast.callerPackage))) {
+ if (needSep) {
+ pw.println();
+ }
+ pw.println(" Pending broadcast [" + mQueueName + "]:");
+ if (mPendingBroadcast != null) {
+ mPendingBroadcast.dump(pw, " ");
+ } else {
+ pw.println(" (null)");
+ }
+ needSep = true;
+ }
+ }
+
+ boolean printed = false;
+ for (int i=0; i<MAX_BROADCAST_HISTORY; i++) {
+ BroadcastRecord r = mBroadcastHistory[i];
+ if (r == null) {
+ break;
+ }
+ if (dumpPackage != null && !dumpPackage.equals(r.callerPackage)) {
+ continue;
+ }
+ if (!printed) {
+ if (needSep) {
+ pw.println();
+ }
+ needSep = true;
+ pw.println(" Historical broadcasts [" + mQueueName + "]:");
+ printed = true;
+ }
+ if (dumpAll) {
+ pw.print(" Historical Broadcast #"); pw.print(i); pw.println(":");
+ r.dump(pw, " ");
+ } else {
+ if (i >= 50) {
+ pw.println(" ...");
+ break;
+ }
+ pw.print(" #"); pw.print(i); pw.print(": "); pw.println(r);
+ }
+ }
+
+ return needSep;
+ }
+ }
+
+ final BroadcastQueue mFgBroadcastQueue = new BroadcastQueue("foreground", BROADCAST_FG_TIMEOUT);
+ final BroadcastQueue mBgBroadcastQueue = new BroadcastQueue("background", BROADCAST_BG_TIMEOUT);
+ // Convenient for easy iteration over the queues. Foreground is first
+ // so that dispatch of foreground broadcasts gets precedence.
+ final BroadcastQueue[] mBroadcastQueues = { mFgBroadcastQueue, mBgBroadcastQueue };
+
+ BroadcastQueue broadcastQueueForIntent(Intent intent) {
+ final boolean isFg = (intent.getFlags() & Intent.FLAG_RECEIVER_FOREGROUND) != 0;
+ if (DEBUG_BACKGROUND_BROADCAST) {
+ Slog.i(TAG, "Broadcast intent " + intent + " on "
+ + (isFg ? "foreground" : "background")
+ + " queue");
+ }
+ return (isFg) ? mFgBroadcastQueue : mBgBroadcastQueue;
+ }
+
+ BroadcastRecord broadcastRecordForReceiverLocked(IBinder receiver) {
+ for (BroadcastQueue queue : mBroadcastQueues) {
+ BroadcastRecord r = queue.getMatchingOrderedReceiver(receiver);
+ if (r != null) {
+ return r;
+ }
+ }
+ return null;
+ }
/**
* Activity we have told the window manager to have key focus.
@@ -456,25 +1248,6 @@
private final StringBuilder mStrictModeBuffer = new StringBuilder();
/**
- * True if we have a pending unexpired BROADCAST_TIMEOUT_MSG posted to our handler.
- */
- private boolean mPendingBroadcastTimeoutMessage;
-
- /**
- * Intent broadcast that we have tried to start, but are
- * waiting for its application's process to be created. We only
- * need one (instead of a list) because we always process broadcasts
- * one at a time, so no others can be started while waiting for this
- * one.
- */
- BroadcastRecord mPendingBroadcast = null;
-
- /**
- * The receiver index that is pending, to restart the broadcast if needed.
- */
- int mPendingBroadcastRecvIndex;
-
- /**
* Keeps track of all IIntentReceivers that have been registered for
* broadcasts. Hash keys are the receiver IBinder, hash value is
* a ReceiverList.
@@ -910,7 +1683,8 @@
Intent intent = new Intent("android.intent.action.ANR");
if (!mProcessesReady) {
- intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
+ intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY
+ | Intent.FLAG_RECEIVER_FOREGROUND);
}
broadcastIntentLocked(null, null, intent,
null, null, 0, null, null, null,
@@ -987,11 +1761,13 @@
case BROADCAST_INTENT_MSG: {
if (DEBUG_BROADCAST) Slog.v(
TAG, "Received BROADCAST_INTENT_MSG");
- processNextBroadcast(true);
+ BroadcastQueue queue = (BroadcastQueue) msg.obj;
+ queue.processNextBroadcast(true);
} break;
case BROADCAST_TIMEOUT_MSG: {
+ final BroadcastQueue queue = (BroadcastQueue) msg.obj;
synchronized (ActivityManagerService.this) {
- broadcastTimeoutLocked(true);
+ queue.broadcastTimeoutLocked(true);
}
} break;
case SERVICE_TIMEOUT_MSG: {
@@ -3708,12 +4484,9 @@
// Can't happen; the backup manager is local
}
}
- if (mPendingBroadcast != null && mPendingBroadcast.curApp.pid == pid) {
+ if (isPendingBroadcastProcessLocked(pid)) {
Slog.w(TAG, "Unattached app died before broadcast acknowledged, skipping");
- mPendingBroadcast.state = BroadcastRecord.IDLE;
- mPendingBroadcast.nextReceiver = mPendingBroadcastRecvIndex;
- mPendingBroadcast = null;
- scheduleBroadcastsLocked();
+ skipPendingBroadcastLocked(pid);
}
} else {
Slog.w(TAG, "Spurious process start timeout - pid not known for " + app);
@@ -3912,23 +4685,13 @@
}
}
- // Check if the next broadcast receiver is in this process...
- BroadcastRecord br = mPendingBroadcast;
- if (!badApp && br != null && br.curApp == app) {
+ // Check if a next-broadcast receiver is in this process...
+ if (!badApp && isPendingBroadcastProcessLocked(pid)) {
try {
- mPendingBroadcast = null;
- processCurBroadcastLocked(br, app);
- didSomething = true;
+ didSomething = sendPendingBroadcastsLocked(app);
} catch (Exception e) {
- Slog.w(TAG, "Exception in new application when starting receiver "
- + br.curComponent.flattenToShortString(), e);
+ // If the app died trying to launch the receiver we declare it 'bad'
badApp = true;
- logBroadcastReceiverDiscardLocked(br);
- finishReceiverLocked(br.receiver, br.resultCode, br.resultData,
- br.resultExtras, br.resultAbort, true);
- scheduleBroadcastsLocked();
- // We need to reset the state if we fails to start the receiver.
- br.state = BroadcastRecord.IDLE;
}
}
@@ -7227,28 +7990,8 @@
}
void skipCurrentReceiverLocked(ProcessRecord app) {
- boolean reschedule = false;
- BroadcastRecord r = app.curReceiver;
- if (r != null) {
- // The current broadcast is waiting for this app's receiver
- // to be finished. Looks like that's not going to happen, so
- // let the broadcast continue.
- logBroadcastReceiverDiscardLocked(r);
- finishReceiverLocked(r.receiver, r.resultCode, r.resultData,
- r.resultExtras, r.resultAbort, true);
- reschedule = true;
- }
- r = mPendingBroadcast;
- if (r != null && r.curApp == app) {
- if (DEBUG_BROADCAST) Slog.v(TAG,
- "skip & discard pending app " + r);
- logBroadcastReceiverDiscardLocked(r);
- finishReceiverLocked(r.receiver, r.resultCode, r.resultData,
- r.resultExtras, r.resultAbort, true);
- reschedule = true;
- }
- if (reschedule) {
- scheduleBroadcastsLocked();
+ for (BroadcastQueue queue : mBroadcastQueues) {
+ queue.skipCurrentReceiverLocked(app);
}
}
@@ -8971,84 +9714,11 @@
needSep = true;
}
}
-
- if (mParallelBroadcasts.size() > 0 || mOrderedBroadcasts.size() > 0
- || mPendingBroadcast != null) {
- boolean printed = false;
- for (int i=mParallelBroadcasts.size()-1; i>=0; i--) {
- BroadcastRecord br = mParallelBroadcasts.get(i);
- if (dumpPackage != null && !dumpPackage.equals(br.callerPackage)) {
- continue;
- }
- if (!printed) {
- if (needSep) {
- pw.println();
- }
- needSep = true;
- pw.println(" Active broadcasts:");
- }
- pw.println(" Broadcast #" + i + ":");
- br.dump(pw, " ");
- }
- printed = false;
- for (int i=mOrderedBroadcasts.size()-1; i>=0; i--) {
- BroadcastRecord br = mOrderedBroadcasts.get(i);
- if (dumpPackage != null && !dumpPackage.equals(br.callerPackage)) {
- continue;
- }
- if (!printed) {
- if (needSep) {
- pw.println();
- }
- needSep = true;
- pw.println(" Active ordered broadcasts:");
- }
- pw.println(" Ordered Broadcast #" + i + ":");
- mOrderedBroadcasts.get(i).dump(pw, " ");
- }
- if (dumpPackage == null || (mPendingBroadcast != null
- && dumpPackage.equals(mPendingBroadcast.callerPackage))) {
- if (needSep) {
- pw.println();
- }
- pw.println(" Pending broadcast:");
- if (mPendingBroadcast != null) {
- mPendingBroadcast.dump(pw, " ");
- } else {
- pw.println(" (null)");
- }
- needSep = true;
- }
+
+ for (BroadcastQueue q : mBroadcastQueues) {
+ needSep = q.dumpLocked(fd, pw, args, opti, dumpAll, dumpPackage, needSep);
}
- boolean printed = false;
- for (int i=0; i<MAX_BROADCAST_HISTORY; i++) {
- BroadcastRecord r = mBroadcastHistory[i];
- if (r == null) {
- break;
- }
- if (dumpPackage != null && !dumpPackage.equals(r.callerPackage)) {
- continue;
- }
- if (!printed) {
- if (needSep) {
- pw.println();
- }
- needSep = true;
- pw.println(" Historical broadcasts:");
- printed = true;
- }
- if (dumpAll) {
- pw.print(" Historical Broadcast #"); pw.print(i); pw.println(":");
- r.dump(pw, " ");
- } else {
- if (i >= 50) {
- pw.println(" ...");
- break;
- }
- pw.print(" #"); pw.print(i); pw.print(": "); pw.println(r);
- }
- }
needSep = true;
if (mStickyBroadcasts != null && dumpPackage == null) {
@@ -9085,7 +9755,10 @@
if (dumpAll) {
pw.println();
- pw.println(" mBroadcastsScheduled=" + mBroadcastsScheduled);
+ for (BroadcastQueue queue : mBroadcastQueues) {
+ pw.println(" mBroadcastsScheduled [" + queue.mQueueName + "]="
+ + queue.mBroadcastsScheduled);
+ }
pw.println(" mHandler:");
mHandler.dump(new PrintWriterPrinter(pw), " ");
needSep = true;
@@ -12072,15 +12745,25 @@
return cur;
}
- private final void scheduleBroadcastsLocked() {
- if (DEBUG_BROADCAST) Slog.v(TAG, "Schedule broadcasts: current="
- + mBroadcastsScheduled);
+ boolean isPendingBroadcastProcessLocked(int pid) {
+ return mFgBroadcastQueue.isPendingBroadcastProcessLocked(pid)
+ || mBgBroadcastQueue.isPendingBroadcastProcessLocked(pid);
+ }
- if (mBroadcastsScheduled) {
- return;
+ void skipPendingBroadcastLocked(int pid) {
+ Slog.w(TAG, "Unattached app died before broadcast acknowledged, skipping");
+ for (BroadcastQueue queue : mBroadcastQueues) {
+ queue.skipPendingBroadcastLocked(pid);
+ }
+ }
+
+ // The app just attached; send any pending broadcasts that it should receive
+ boolean sendPendingBroadcastsLocked(ProcessRecord app) {
+ boolean didSomething = false;
+ for (BroadcastQueue queue : mBroadcastQueues) {
+ didSomething |= queue.sendPendingBroadcastsLocked(app);
}
- mHandler.sendEmptyMessage(BROADCAST_INTENT_MSG);
- mBroadcastsScheduled = true;
+ return didSomething;
}
public Intent registerReceiver(IApplicationThread caller, String callerPackage,
@@ -12162,13 +12845,12 @@
int N = allSticky.size();
for (int i=0; i<N; i++) {
Intent intent = (Intent)allSticky.get(i);
- BroadcastRecord r = new BroadcastRecord(intent, null,
+ BroadcastQueue queue = broadcastQueueForIntent(intent);
+ BroadcastRecord r = new BroadcastRecord(queue, intent, null,
null, -1, -1, null, receivers, null, 0, null, null,
false, true, true);
- if (mParallelBroadcasts.size() == 0) {
- scheduleBroadcastsLocked();
- }
- mParallelBroadcasts.add(r);
+ queue.enqueueParallelBroadcastLocked(r);
+ queue.scheduleBroadcastsLocked();
}
}
@@ -12179,38 +12861,46 @@
public void unregisterReceiver(IIntentReceiver receiver) {
if (DEBUG_BROADCAST) Slog.v(TAG, "Unregister receiver: " + receiver);
- boolean doNext = false;
+ final long origId = Binder.clearCallingIdentity();
+ try {
+ boolean doTrim = false;
- synchronized(this) {
- ReceiverList rl
+ synchronized(this) {
+ ReceiverList rl
= (ReceiverList)mRegisteredReceivers.get(receiver.asBinder());
- if (rl != null) {
- if (rl.curBroadcast != null) {
- BroadcastRecord r = rl.curBroadcast;
- doNext = finishReceiverLocked(
- receiver.asBinder(), r.resultCode, r.resultData,
- r.resultExtras, r.resultAbort, true);
- }
+ if (rl != null) {
+ if (rl.curBroadcast != null) {
+ BroadcastRecord r = rl.curBroadcast;
+ final boolean doNext = finishReceiverLocked(
+ receiver.asBinder(), r.resultCode, r.resultData,
+ r.resultExtras, r.resultAbort, true);
+ if (doNext) {
+ doTrim = true;
+ r.queue.processNextBroadcast(false);
+ }
+ }
- if (rl.app != null) {
- rl.app.receivers.remove(rl);
- }
- removeReceiverLocked(rl);
- if (rl.linkedToDeath) {
- rl.linkedToDeath = false;
- rl.receiver.asBinder().unlinkToDeath(rl, 0);
+ if (rl.app != null) {
+ rl.app.receivers.remove(rl);
+ }
+ removeReceiverLocked(rl);
+ if (rl.linkedToDeath) {
+ rl.linkedToDeath = false;
+ rl.receiver.asBinder().unlinkToDeath(rl, 0);
+ }
}
}
- }
- if (!doNext) {
- return;
+ // If we actually concluded any broadcasts, we might now be able
+ // to trim the recipients' apps from our working set
+ if (doTrim) {
+ trimApplications();
+ return;
+ }
+
+ } finally {
+ Binder.restoreCallingIdentity(origId);
}
-
- final long origId = Binder.clearCallingIdentity();
- processNextBroadcast(false);
- trimApplications();
- Binder.restoreCallingIdentity(origId);
}
void removeReceiverLocked(ReceiverList rl) {
@@ -12440,28 +13130,17 @@
// If we are not serializing this broadcast, then send the
// registered receivers separately so they don't wait for the
// components to be launched.
- BroadcastRecord r = new BroadcastRecord(intent, callerApp,
+ final BroadcastQueue queue = broadcastQueueForIntent(intent);
+ BroadcastRecord r = new BroadcastRecord(queue, intent, callerApp,
callerPackage, callingPid, callingUid, requiredPermission,
registeredReceivers, resultTo, resultCode, resultData, map,
ordered, sticky, false);
if (DEBUG_BROADCAST) Slog.v(
- TAG, "Enqueueing parallel broadcast " + r
- + ": prev had " + mParallelBroadcasts.size());
- boolean replaced = false;
- if (replacePending) {
- for (int i=mParallelBroadcasts.size()-1; i>=0; i--) {
- if (intent.filterEquals(mParallelBroadcasts.get(i).intent)) {
- if (DEBUG_BROADCAST) Slog.v(TAG,
- "***** DROPPING PARALLEL: " + intent);
- mParallelBroadcasts.set(i, r);
- replaced = true;
- break;
- }
- }
- }
+ TAG, "Enqueueing parallel broadcast " + r);
+ final boolean replaced = replacePending && queue.replaceParallelBroadcastLocked(r);
if (!replaced) {
- mParallelBroadcasts.add(r);
- scheduleBroadcastsLocked();
+ queue.enqueueParallelBroadcastLocked(r);
+ queue.scheduleBroadcastsLocked();
}
registeredReceivers = null;
NR = 0;
@@ -12541,32 +13220,22 @@
if ((receivers != null && receivers.size() > 0)
|| resultTo != null) {
- BroadcastRecord r = new BroadcastRecord(intent, callerApp,
+ BroadcastQueue queue = broadcastQueueForIntent(intent);
+ BroadcastRecord r = new BroadcastRecord(queue, intent, callerApp,
callerPackage, callingPid, callingUid, requiredPermission,
receivers, resultTo, resultCode, resultData, map, ordered,
sticky, false);
if (DEBUG_BROADCAST) Slog.v(
TAG, "Enqueueing ordered broadcast " + r
- + ": prev had " + mOrderedBroadcasts.size());
+ + ": prev had " + queue.mOrderedBroadcasts.size());
if (DEBUG_BROADCAST) {
int seq = r.intent.getIntExtra("seq", -1);
Slog.i(TAG, "Enqueueing broadcast " + r.intent.getAction() + " seq=" + seq);
}
- boolean replaced = false;
- if (replacePending) {
- for (int i=mOrderedBroadcasts.size()-1; i>0; i--) {
- if (intent.filterEquals(mOrderedBroadcasts.get(i).intent)) {
- if (DEBUG_BROADCAST) Slog.v(TAG,
- "***** DROPPING ORDERED: " + intent);
- mOrderedBroadcasts.set(i, r);
- replaced = true;
- break;
- }
- }
- }
+ boolean replaced = replacePending && queue.replaceOrderedBroadcastLocked(r);
if (!replaced) {
- mOrderedBroadcasts.add(r);
- scheduleBroadcastsLocked();
+ queue.enqueueOrderedBroadcastLocked(r);
+ queue.scheduleBroadcastsLocked();
}
}
@@ -12673,54 +13342,14 @@
private final boolean finishReceiverLocked(IBinder receiver, int resultCode,
String resultData, Bundle resultExtras, boolean resultAbort,
boolean explicit) {
- if (mOrderedBroadcasts.size() == 0) {
- if (explicit) {
- Slog.w(TAG, "finishReceiver called but no pending broadcasts");
- }
+ final BroadcastRecord r = broadcastRecordForReceiverLocked(receiver);
+ if (r == null) {
+ Slog.w(TAG, "finishReceiver called but not found on queue");
return false;
}
- BroadcastRecord r = mOrderedBroadcasts.get(0);
- if (r.receiver == null) {
- if (explicit) {
- Slog.w(TAG, "finishReceiver called but none active");
- }
- return false;
- }
- if (r.receiver != receiver) {
- Slog.w(TAG, "finishReceiver called but active receiver is different");
- return false;
- }
- int state = r.state;
- r.state = BroadcastRecord.IDLE;
- if (state == BroadcastRecord.IDLE) {
- if (explicit) {
- Slog.w(TAG, "finishReceiver called but state is IDLE");
- }
- }
- r.receiver = null;
- r.intent.setComponent(null);
- if (r.curApp != null) {
- r.curApp.curReceiver = null;
- }
- if (r.curFilter != null) {
- r.curFilter.receiverList.curBroadcast = null;
- }
- r.curFilter = null;
- r.curApp = null;
- r.curComponent = null;
- r.curReceiver = null;
- mPendingBroadcast = null;
- r.resultCode = resultCode;
- r.resultData = resultData;
- r.resultExtras = resultExtras;
- r.resultAbort = resultAbort;
-
- // We will process the next receiver right now if this is finishing
- // an app receiver (which is always asynchronous) or after we have
- // come back from calling a receiver.
- return state == BroadcastRecord.APP_RECEIVE
- || state == BroadcastRecord.CALL_DONE_RECEIVE;
+ return r.queue.finishReceiverLocked(r, resultCode, resultData, resultExtras, resultAbort,
+ explicit);
}
public void finishReceiver(IBinder who, int resultCode, String resultData,
@@ -12732,153 +13361,25 @@
throw new IllegalArgumentException("File descriptors passed in Bundle");
}
- boolean doNext;
-
final long origId = Binder.clearCallingIdentity();
+ try {
+ boolean doNext = false;
+ BroadcastRecord r = null;
- synchronized(this) {
- doNext = finishReceiverLocked(
- who, resultCode, resultData, resultExtras, resultAbort, true);
- }
-
- if (doNext) {
- processNextBroadcast(false);
- }
- trimApplications();
-
- Binder.restoreCallingIdentity(origId);
- }
-
- private final void logBroadcastReceiverDiscardLocked(BroadcastRecord r) {
- if (r.nextReceiver > 0) {
- Object curReceiver = r.receivers.get(r.nextReceiver-1);
- if (curReceiver instanceof BroadcastFilter) {
- BroadcastFilter bf = (BroadcastFilter) curReceiver;
- EventLog.writeEvent(EventLogTags.AM_BROADCAST_DISCARD_FILTER,
- System.identityHashCode(r),
- r.intent.getAction(),
- r.nextReceiver - 1,
- System.identityHashCode(bf));
- } else {
- EventLog.writeEvent(EventLogTags.AM_BROADCAST_DISCARD_APP,
- System.identityHashCode(r),
- r.intent.getAction(),
- r.nextReceiver - 1,
- ((ResolveInfo)curReceiver).toString());
- }
- } else {
- Slog.w(TAG, "Discarding broadcast before first receiver is invoked: "
- + r);
- EventLog.writeEvent(EventLogTags.AM_BROADCAST_DISCARD_APP,
- System.identityHashCode(r),
- r.intent.getAction(),
- r.nextReceiver,
- "NONE");
- }
- }
-
- private final void setBroadcastTimeoutLocked(long timeoutTime) {
- if (! mPendingBroadcastTimeoutMessage) {
- Message msg = mHandler.obtainMessage(BROADCAST_TIMEOUT_MSG);
- mHandler.sendMessageAtTime(msg, timeoutTime);
- mPendingBroadcastTimeoutMessage = true;
- }
- }
-
- private final void cancelBroadcastTimeoutLocked() {
- if (mPendingBroadcastTimeoutMessage) {
- mHandler.removeMessages(BROADCAST_TIMEOUT_MSG);
- mPendingBroadcastTimeoutMessage = false;
- }
- }
-
- private final void broadcastTimeoutLocked(boolean fromMsg) {
- if (fromMsg) {
- mPendingBroadcastTimeoutMessage = false;
- }
-
- if (mOrderedBroadcasts.size() == 0) {
- return;
- }
-
- long now = SystemClock.uptimeMillis();
- BroadcastRecord r = mOrderedBroadcasts.get(0);
- if (fromMsg) {
- if (mDidDexOpt) {
- // Delay timeouts until dexopt finishes.
- mDidDexOpt = false;
- long timeoutTime = SystemClock.uptimeMillis() + BROADCAST_TIMEOUT;
- setBroadcastTimeoutLocked(timeoutTime);
- return;
- }
- if (! mProcessesReady) {
- // Only process broadcast timeouts if the system is ready. That way
- // PRE_BOOT_COMPLETED broadcasts can't timeout as they are intended
- // to do heavy lifting for system up.
- return;
- }
-
- long timeoutTime = r.receiverTime + BROADCAST_TIMEOUT;
- if (timeoutTime > now) {
- // We can observe premature timeouts because we do not cancel and reset the
- // broadcast timeout message after each receiver finishes. Instead, we set up
- // an initial timeout then kick it down the road a little further as needed
- // when it expires.
- if (DEBUG_BROADCAST) Slog.v(TAG,
- "Premature timeout @ " + now + ": resetting BROADCAST_TIMEOUT_MSG for "
- + timeoutTime);
- setBroadcastTimeoutLocked(timeoutTime);
- return;
- }
- }
-
- Slog.w(TAG, "Timeout of broadcast " + r + " - receiver=" + r.receiver
- + ", started " + (now - r.receiverTime) + "ms ago");
- r.receiverTime = now;
- r.anrCount++;
-
- // Current receiver has passed its expiration date.
- if (r.nextReceiver <= 0) {
- Slog.w(TAG, "Timeout on receiver with nextReceiver <= 0");
- return;
- }
-
- ProcessRecord app = null;
- String anrMessage = null;
-
- Object curReceiver = r.receivers.get(r.nextReceiver-1);
- Slog.w(TAG, "Receiver during timeout: " + curReceiver);
- logBroadcastReceiverDiscardLocked(r);
- if (curReceiver instanceof BroadcastFilter) {
- BroadcastFilter bf = (BroadcastFilter)curReceiver;
- if (bf.receiverList.pid != 0
- && bf.receiverList.pid != MY_PID) {
- synchronized (this.mPidsSelfLocked) {
- app = this.mPidsSelfLocked.get(
- bf.receiverList.pid);
+ synchronized(this) {
+ r = broadcastRecordForReceiverLocked(who);
+ if (r != null) {
+ doNext = r.queue.finishReceiverLocked(r, resultCode,
+ resultData, resultExtras, resultAbort, true);
}
}
- } else {
- app = r.curApp;
- }
-
- if (app != null) {
- anrMessage = "Broadcast of " + r.intent.toString();
- }
- if (mPendingBroadcast == r) {
- mPendingBroadcast = null;
- }
-
- // Move on to the next receiver.
- finishReceiverLocked(r.receiver, r.resultCode, r.resultData,
- r.resultExtras, r.resultAbort, true);
- scheduleBroadcastsLocked();
-
- if (anrMessage != null) {
- // Post the ANR to the handler since we do not want to process ANRs while
- // potentially holding our lock.
- mHandler.post(new AppNotResponding(app, anrMessage));
+ if (doNext) {
+ r.queue.processNextBroadcast(false);
+ }
+ trimApplications();
+ } finally {
+ Binder.restoreCallingIdentity(origId);
}
}
@@ -13013,333 +13514,6 @@
}
}
- private final void addBroadcastToHistoryLocked(BroadcastRecord r) {
- if (r.callingUid < 0) {
- // This was from a registerReceiver() call; ignore it.
- return;
- }
- System.arraycopy(mBroadcastHistory, 0, mBroadcastHistory, 1,
- MAX_BROADCAST_HISTORY-1);
- r.finishTime = SystemClock.uptimeMillis();
- mBroadcastHistory[0] = r;
- }
-
- private final void processNextBroadcast(boolean fromMsg) {
- synchronized(this) {
- BroadcastRecord r;
-
- if (DEBUG_BROADCAST) Slog.v(TAG, "processNextBroadcast: "
- + mParallelBroadcasts.size() + " broadcasts, "
- + mOrderedBroadcasts.size() + " ordered broadcasts");
-
- updateCpuStats();
-
- if (fromMsg) {
- mBroadcastsScheduled = false;
- }
-
- // First, deliver any non-serialized broadcasts right away.
- while (mParallelBroadcasts.size() > 0) {
- r = mParallelBroadcasts.remove(0);
- r.dispatchTime = SystemClock.uptimeMillis();
- r.dispatchClockTime = System.currentTimeMillis();
- final int N = r.receivers.size();
- if (DEBUG_BROADCAST_LIGHT) Slog.v(TAG, "Processing parallel broadcast "
- + r);
- for (int i=0; i<N; i++) {
- Object target = r.receivers.get(i);
- if (DEBUG_BROADCAST) Slog.v(TAG,
- "Delivering non-ordered to registered "
- + target + ": " + r);
- deliverToRegisteredReceiverLocked(r, (BroadcastFilter)target, false);
- }
- addBroadcastToHistoryLocked(r);
- if (DEBUG_BROADCAST_LIGHT) Slog.v(TAG, "Done with parallel broadcast "
- + r);
- }
-
- // Now take care of the next serialized one...
-
- // If we are waiting for a process to come up to handle the next
- // broadcast, then do nothing at this point. Just in case, we
- // check that the process we're waiting for still exists.
- if (mPendingBroadcast != null) {
- if (DEBUG_BROADCAST_LIGHT) {
- Slog.v(TAG, "processNextBroadcast: waiting for "
- + mPendingBroadcast.curApp);
- }
-
- boolean isDead;
- synchronized (mPidsSelfLocked) {
- isDead = (mPidsSelfLocked.get(mPendingBroadcast.curApp.pid) == null);
- }
- if (!isDead) {
- // It's still alive, so keep waiting
- return;
- } else {
- Slog.w(TAG, "pending app " + mPendingBroadcast.curApp
- + " died before responding to broadcast");
- mPendingBroadcast.state = BroadcastRecord.IDLE;
- mPendingBroadcast.nextReceiver = mPendingBroadcastRecvIndex;
- mPendingBroadcast = null;
- }
- }
-
- boolean looped = false;
-
- do {
- if (mOrderedBroadcasts.size() == 0) {
- // No more broadcasts pending, so all done!
- scheduleAppGcsLocked();
- if (looped) {
- // If we had finished the last ordered broadcast, then
- // make sure all processes have correct oom and sched
- // adjustments.
- updateOomAdjLocked();
- }
- return;
- }
- r = mOrderedBroadcasts.get(0);
- boolean forceReceive = false;
-
- // Ensure that even if something goes awry with the timeout
- // detection, we catch "hung" broadcasts here, discard them,
- // and continue to make progress.
- //
- // This is only done if the system is ready so that PRE_BOOT_COMPLETED
- // receivers don't get executed with timeouts. They're intended for
- // one time heavy lifting after system upgrades and can take
- // significant amounts of time.
- int numReceivers = (r.receivers != null) ? r.receivers.size() : 0;
- if (mProcessesReady && r.dispatchTime > 0) {
- long now = SystemClock.uptimeMillis();
- if ((numReceivers > 0) &&
- (now > r.dispatchTime + (2*BROADCAST_TIMEOUT*numReceivers))) {
- Slog.w(TAG, "Hung broadcast discarded after timeout failure:"
- + " now=" + now
- + " dispatchTime=" + r.dispatchTime
- + " startTime=" + r.receiverTime
- + " intent=" + r.intent
- + " numReceivers=" + numReceivers
- + " nextReceiver=" + r.nextReceiver
- + " state=" + r.state);
- broadcastTimeoutLocked(false); // forcibly finish this broadcast
- forceReceive = true;
- r.state = BroadcastRecord.IDLE;
- }
- }
-
- if (r.state != BroadcastRecord.IDLE) {
- if (DEBUG_BROADCAST) Slog.d(TAG,
- "processNextBroadcast() called when not idle (state="
- + r.state + ")");
- return;
- }
-
- if (r.receivers == null || r.nextReceiver >= numReceivers
- || r.resultAbort || forceReceive) {
- // No more receivers for this broadcast! Send the final
- // result if requested...
- if (r.resultTo != null) {
- try {
- if (DEBUG_BROADCAST) {
- int seq = r.intent.getIntExtra("seq", -1);
- Slog.i(TAG, "Finishing broadcast " + r.intent.getAction()
- + " seq=" + seq + " app=" + r.callerApp);
- }
- performReceiveLocked(r.callerApp, r.resultTo,
- new Intent(r.intent), r.resultCode,
- r.resultData, r.resultExtras, false, false);
- // Set this to null so that the reference
- // (local and remote) isnt kept in the mBroadcastHistory.
- r.resultTo = null;
- } catch (RemoteException e) {
- Slog.w(TAG, "Failure sending broadcast result of " + r.intent, e);
- }
- }
-
- if (DEBUG_BROADCAST) Slog.v(TAG, "Cancelling BROADCAST_TIMEOUT_MSG");
- cancelBroadcastTimeoutLocked();
-
- if (DEBUG_BROADCAST_LIGHT) Slog.v(TAG, "Finished with ordered broadcast "
- + r);
-
- // ... and on to the next...
- addBroadcastToHistoryLocked(r);
- mOrderedBroadcasts.remove(0);
- r = null;
- looped = true;
- continue;
- }
- } while (r == null);
-
- // Get the next receiver...
- int recIdx = r.nextReceiver++;
-
- // Keep track of when this receiver started, and make sure there
- // is a timeout message pending to kill it if need be.
- r.receiverTime = SystemClock.uptimeMillis();
- if (recIdx == 0) {
- r.dispatchTime = r.receiverTime;
- r.dispatchClockTime = System.currentTimeMillis();
- if (DEBUG_BROADCAST_LIGHT) Slog.v(TAG, "Processing ordered broadcast "
- + r);
- }
- if (! mPendingBroadcastTimeoutMessage) {
- long timeoutTime = r.receiverTime + BROADCAST_TIMEOUT;
- if (DEBUG_BROADCAST) Slog.v(TAG,
- "Submitting BROADCAST_TIMEOUT_MSG for " + r + " at " + timeoutTime);
- setBroadcastTimeoutLocked(timeoutTime);
- }
-
- Object nextReceiver = r.receivers.get(recIdx);
- if (nextReceiver instanceof BroadcastFilter) {
- // Simple case: this is a registered receiver who gets
- // a direct call.
- BroadcastFilter filter = (BroadcastFilter)nextReceiver;
- if (DEBUG_BROADCAST) Slog.v(TAG,
- "Delivering ordered to registered "
- + filter + ": " + r);
- deliverToRegisteredReceiverLocked(r, filter, r.ordered);
- if (r.receiver == null || !r.ordered) {
- // The receiver has already finished, so schedule to
- // process the next one.
- if (DEBUG_BROADCAST) Slog.v(TAG, "Quick finishing: ordered="
- + r.ordered + " receiver=" + r.receiver);
- r.state = BroadcastRecord.IDLE;
- scheduleBroadcastsLocked();
- }
- return;
- }
-
- // Hard case: need to instantiate the receiver, possibly
- // starting its application process to host it.
-
- ResolveInfo info =
- (ResolveInfo)nextReceiver;
-
- boolean skip = false;
- int perm = checkComponentPermission(info.activityInfo.permission,
- r.callingPid, r.callingUid, info.activityInfo.applicationInfo.uid,
- info.activityInfo.exported);
- if (perm != PackageManager.PERMISSION_GRANTED) {
- if (!info.activityInfo.exported) {
- Slog.w(TAG, "Permission Denial: broadcasting "
- + r.intent.toString()
- + " from " + r.callerPackage + " (pid=" + r.callingPid
- + ", uid=" + r.callingUid + ")"
- + " is not exported from uid " + info.activityInfo.applicationInfo.uid
- + " due to receiver " + info.activityInfo.packageName
- + "/" + info.activityInfo.name);
- } else {
- Slog.w(TAG, "Permission Denial: broadcasting "
- + r.intent.toString()
- + " from " + r.callerPackage + " (pid=" + r.callingPid
- + ", uid=" + r.callingUid + ")"
- + " requires " + info.activityInfo.permission
- + " due to receiver " + info.activityInfo.packageName
- + "/" + info.activityInfo.name);
- }
- skip = true;
- }
- if (info.activityInfo.applicationInfo.uid != Process.SYSTEM_UID &&
- r.requiredPermission != null) {
- try {
- perm = AppGlobals.getPackageManager().
- checkPermission(r.requiredPermission,
- info.activityInfo.applicationInfo.packageName);
- } catch (RemoteException e) {
- perm = PackageManager.PERMISSION_DENIED;
- }
- if (perm != PackageManager.PERMISSION_GRANTED) {
- Slog.w(TAG, "Permission Denial: receiving "
- + r.intent + " to "
- + info.activityInfo.applicationInfo.packageName
- + " requires " + r.requiredPermission
- + " due to sender " + r.callerPackage
- + " (uid " + r.callingUid + ")");
- skip = true;
- }
- }
- if (r.curApp != null && r.curApp.crashing) {
- // If the target process is crashing, just skip it.
- if (DEBUG_BROADCAST) Slog.v(TAG,
- "Skipping deliver ordered " + r + " to " + r.curApp
- + ": process crashing");
- skip = true;
- }
-
- if (skip) {
- if (DEBUG_BROADCAST) Slog.v(TAG,
- "Skipping delivery of ordered " + r + " for whatever reason");
- r.receiver = null;
- r.curFilter = null;
- r.state = BroadcastRecord.IDLE;
- scheduleBroadcastsLocked();
- return;
- }
-
- r.state = BroadcastRecord.APP_RECEIVE;
- String targetProcess = info.activityInfo.processName;
- r.curComponent = new ComponentName(
- info.activityInfo.applicationInfo.packageName,
- info.activityInfo.name);
- r.curReceiver = info.activityInfo;
-
- // Broadcast is being executed, its package can't be stopped.
- try {
- AppGlobals.getPackageManager().setPackageStoppedState(
- r.curComponent.getPackageName(), false);
- } catch (RemoteException e) {
- } catch (IllegalArgumentException e) {
- Slog.w(TAG, "Failed trying to unstop package "
- + r.curComponent.getPackageName() + ": " + e);
- }
-
- // Is this receiver's application already running?
- ProcessRecord app = getProcessRecordLocked(targetProcess,
- info.activityInfo.applicationInfo.uid);
- if (app != null && app.thread != null) {
- try {
- app.addPackage(info.activityInfo.packageName);
- processCurBroadcastLocked(r, app);
- return;
- } catch (RemoteException e) {
- Slog.w(TAG, "Exception when sending broadcast to "
- + r.curComponent, e);
- }
-
- // If a dead object exception was thrown -- fall through to
- // restart the application.
- }
-
- // Not running -- get it started, to be executed when the app comes up.
- if (DEBUG_BROADCAST) Slog.v(TAG,
- "Need to start app " + targetProcess + " for broadcast " + r);
- if ((r.curApp=startProcessLocked(targetProcess,
- info.activityInfo.applicationInfo, true,
- r.intent.getFlags() | Intent.FLAG_FROM_BACKGROUND,
- "broadcast", r.curComponent,
- (r.intent.getFlags()&Intent.FLAG_RECEIVER_BOOT_UPGRADE) != 0))
- == null) {
- // Ah, this recipient is unavailable. Finish it if necessary,
- // and mark the broadcast record as ready for the next.
- Slog.w(TAG, "Unable to launch app "
- + info.activityInfo.applicationInfo.packageName + "/"
- + info.activityInfo.applicationInfo.uid + " for broadcast "
- + r.intent + ": process is bad");
- logBroadcastReceiverDiscardLocked(r);
- finishReceiverLocked(r.receiver, r.resultCode, r.resultData,
- r.resultExtras, r.resultAbort, true);
- scheduleBroadcastsLocked();
- r.state = BroadcastRecord.IDLE;
- return;
- }
-
- mPendingBroadcast = r;
- mPendingBroadcastRecvIndex = recIdx;
- }
- }
// =========================================================
// INSTRUMENTATION
@@ -13663,6 +13837,28 @@
// LIFETIME MANAGEMENT
// =========================================================
+ // Returns which broadcast queue the app is the current [or imminent] receiver
+ // on, or 'null' if the app is not an active broadcast recipient.
+ private BroadcastQueue isReceivingBroadcast(ProcessRecord app) {
+ BroadcastRecord r = app.curReceiver;
+ if (r != null) {
+ return r.queue;
+ }
+
+ // It's not the current receiver, but it might be starting up to become one
+ synchronized (this) {
+ for (BroadcastQueue queue : mBroadcastQueues) {
+ r = queue.mPendingBroadcast;
+ if (r != null && r.curApp == app) {
+ // found it; report which queue it's in
+ return queue;
+ }
+ }
+ }
+
+ return null;
+ }
+
private final int computeOomAdjLocked(ProcessRecord app, int hiddenAdj,
ProcessRecord TOP_APP, boolean recursed, boolean doingAll) {
if (mAdjSeq == app.adjSeq) {
@@ -13728,6 +13924,7 @@
// important to least, and assign an appropriate OOM adjustment.
int adj;
int schedGroup;
+ BroadcastQueue queue;
if (app == TOP_APP) {
// The last app on the list is the foreground app.
adj = ProcessList.FOREGROUND_APP_ADJ;
@@ -13739,12 +13936,14 @@
adj = ProcessList.FOREGROUND_APP_ADJ;
schedGroup = Process.THREAD_GROUP_DEFAULT;
app.adjType = "instrumentation";
- } else if (app.curReceiver != null ||
- (mPendingBroadcast != null && mPendingBroadcast.curApp == app)) {
+ } else if ((queue = isReceivingBroadcast(app)) != null) {
// An app that is currently receiving a broadcast also
- // counts as being in the foreground.
+ // counts as being in the foreground for OOM killer purposes.
+ // It's placed in a sched group based on the nature of the
+ // broadcast as reflected by which queue it's active in.
adj = ProcessList.FOREGROUND_APP_ADJ;
- schedGroup = Process.THREAD_GROUP_DEFAULT;
+ schedGroup = (queue == mFgBroadcastQueue)
+ ? Process.THREAD_GROUP_DEFAULT : Process.THREAD_GROUP_BG_NONINTERACTIVE;
app.adjType = "broadcast";
} else if (app.executingServices.size() > 0) {
// An app that is currently executing a service callback also
@@ -14185,8 +14384,13 @@
* Returns true if things are idle enough to perform GCs.
*/
private final boolean canGcNowLocked() {
- return mParallelBroadcasts.size() == 0
- && mOrderedBroadcasts.size() == 0
+ boolean processingBroadcasts = false;
+ for (BroadcastQueue q : mBroadcastQueues) {
+ if (q.mParallelBroadcasts.size() != 0 || q.mOrderedBroadcasts.size() != 0) {
+ processingBroadcasts = true;
+ }
+ }
+ return !processingBroadcasts
&& (mSleeping || (mMainStack.mResumedActivity != null &&
mMainStack.mResumedActivity.idle));
}
diff --git a/services/java/com/android/server/am/BroadcastRecord.java b/services/java/com/android/server/am/BroadcastRecord.java
index bcb0134..6738e4f 100644
--- a/services/java/com/android/server/am/BroadcastRecord.java
+++ b/services/java/com/android/server/am/BroadcastRecord.java
@@ -59,6 +59,7 @@
IBinder receiver; // who is currently running, null if none.
int state;
int anrCount; // has this broadcast record hit any ANRs?
+ ActivityManagerService.BroadcastQueue queue; // the outbound queue handling this broadcast
static final int IDLE = 0;
static final int APP_RECEIVE = 1;
@@ -161,11 +162,13 @@
}
}
- BroadcastRecord(Intent _intent, ProcessRecord _callerApp, String _callerPackage,
+ BroadcastRecord(ActivityManagerService.BroadcastQueue _queue,
+ Intent _intent, ProcessRecord _callerApp, String _callerPackage,
int _callingPid, int _callingUid, String _requiredPermission,
List _receivers, IIntentReceiver _resultTo, int _resultCode,
String _resultData, Bundle _resultExtras, boolean _serialized,
boolean _sticky, boolean _initialSticky) {
+ queue = _queue;
intent = _intent;
callerApp = _callerApp;
callerPackage = _callerPackage;
diff --git a/services/java/com/android/server/net/NetworkPolicyManagerService.java b/services/java/com/android/server/net/NetworkPolicyManagerService.java
index 51adebe..5c9396f 100644
--- a/services/java/com/android/server/net/NetworkPolicyManagerService.java
+++ b/services/java/com/android/server/net/NetworkPolicyManagerService.java
@@ -154,6 +154,7 @@
private static final int VERSION_ADDED_SNOOZE = 2;
private static final int VERSION_ADDED_RESTRICT_BACKGROUND = 3;
private static final int VERSION_ADDED_METERED = 4;
+ private static final int VERSION_SPLIT_SNOOZE = 5;
private static final long KB_IN_BYTES = 1024;
private static final long MB_IN_BYTES = KB_IN_BYTES * 1024;
@@ -176,6 +177,8 @@
private static final String ATTR_WARNING_BYTES = "warningBytes";
private static final String ATTR_LIMIT_BYTES = "limitBytes";
private static final String ATTR_LAST_SNOOZE = "lastSnooze";
+ private static final String ATTR_LAST_WARNING_SNOOZE = "lastWarningSnooze";
+ private static final String ATTR_LAST_LIMIT_SNOOZE = "lastLimitSnooze";
private static final String ATTR_METERED = "metered";
private static final String ATTR_UID = "uid";
private static final String ATTR_POLICY = "policy";
@@ -184,7 +187,9 @@
// @VisibleForTesting
public static final String ACTION_ALLOW_BACKGROUND =
- "com.android.server.action.ACTION_ALLOW_BACKGROUND";
+ "com.android.server.net.action.ALLOW_BACKGROUND";
+ public static final String ACTION_SNOOZE_WARNING =
+ "com.android.server.net.action.SNOOZE_WARNING";
private static final long TIME_CACHE_MAX_AGE = DAY_IN_MILLIS;
@@ -333,6 +338,11 @@
final IntentFilter allowFilter = new IntentFilter(ACTION_ALLOW_BACKGROUND);
mContext.registerReceiver(mAllowReceiver, allowFilter, MANAGE_NETWORK_POLICY, mHandler);
+ // listen for snooze warning from notifications
+ final IntentFilter snoozeWarningFilter = new IntentFilter(ACTION_SNOOZE_WARNING);
+ mContext.registerReceiver(mSnoozeWarningReceiver, snoozeWarningFilter,
+ MANAGE_NETWORK_POLICY, mHandler);
+
}
private IProcessObserver mProcessObserver = new IProcessObserver.Stub() {
@@ -418,6 +428,21 @@
};
/**
+ * Receiver that watches for {@link Notification} control of
+ * {@link NetworkPolicy#lastWarningSnooze}.
+ */
+ private BroadcastReceiver mSnoozeWarningReceiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ // on background handler thread, and verified MANAGE_NETWORK_POLICY
+ // permission above.
+
+ final NetworkTemplate template = intent.getParcelableExtra(EXTRA_NETWORK_TEMPLATE);
+ performSnooze(template, TYPE_WARNING);
+ }
+ };
+
+ /**
* Observer that watches for {@link INetworkManagementService} alerts.
*/
private INetworkManagementEventObserver mAlertObserver = new NetworkAlertObserver() {
@@ -458,7 +483,7 @@
final long totalBytes = getTotalBytes(policy.template, start, end);
if (policy.isOverLimit(totalBytes)) {
- if (policy.lastSnooze >= start) {
+ if (policy.lastLimitSnooze >= start) {
enqueueNotification(policy, TYPE_LIMIT_SNOOZED, totalBytes);
} else {
enqueueNotification(policy, TYPE_LIMIT, totalBytes);
@@ -468,7 +493,7 @@
} else {
notifyUnderLimitLocked(policy.template);
- if (policy.warningBytes != WARNING_DISABLED && totalBytes >= policy.warningBytes) {
+ if (policy.isOverWarning(totalBytes) && policy.lastWarningSnooze < start) {
enqueueNotification(policy, TYPE_WARNING, totalBytes);
}
}
@@ -534,7 +559,7 @@
final String tag = buildNotificationTag(policy, type);
final Notification.Builder builder = new Notification.Builder(mContext);
builder.setOnlyAlertOnce(true);
- builder.setOngoing(true);
+ builder.setWhen(0L);
final Resources res = mContext.getResources();
switch (type) {
@@ -547,9 +572,14 @@
builder.setContentTitle(title);
builder.setContentText(body);
- final Intent intent = buildViewDataUsageIntent(policy.template);
+ final Intent snoozeIntent = buildSnoozeWarningIntent(policy.template);
+ builder.setDeleteIntent(PendingIntent.getBroadcast(
+ mContext, 0, snoozeIntent, PendingIntent.FLAG_UPDATE_CURRENT));
+
+ final Intent viewIntent = buildViewDataUsageIntent(policy.template);
builder.setContentIntent(PendingIntent.getActivity(
- mContext, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT));
+ mContext, 0, viewIntent, PendingIntent.FLAG_UPDATE_CURRENT));
+
break;
}
case TYPE_LIMIT: {
@@ -574,6 +604,7 @@
break;
}
+ builder.setOngoing(true);
builder.setSmallIcon(R.drawable.stat_notify_disabled);
builder.setTicker(title);
builder.setContentTitle(title);
@@ -608,6 +639,7 @@
break;
}
+ builder.setOngoing(true);
builder.setSmallIcon(R.drawable.stat_notify_error);
builder.setTicker(title);
builder.setContentTitle(title);
@@ -720,10 +752,11 @@
final long totalBytes = getTotalBytes(policy.template, start, end);
// disable data connection when over limit and not snoozed
- final boolean overLimit = policy.isOverLimit(totalBytes) && policy.lastSnooze < start;
- final boolean enabled = !overLimit;
+ final boolean overLimitWithoutSnooze = policy.isOverLimit(totalBytes)
+ && policy.lastLimitSnooze < start;
+ final boolean networkEnabled = !overLimitWithoutSnooze;
- setNetworkTemplateEnabled(policy.template, enabled);
+ setNetworkTemplateEnabled(policy.template, networkEnabled);
}
}
@@ -827,7 +860,7 @@
// metered network, but no policy limit; we still need to
// restrict apps, so push really high quota.
quotaBytes = Long.MAX_VALUE;
- } else if (policy.lastSnooze >= start) {
+ } else if (policy.lastLimitSnooze >= start) {
// snoozing past quota, but we still need to restrict apps,
// so push really high quota.
quotaBytes = Long.MAX_VALUE;
@@ -896,8 +929,8 @@
final int cycleDay = time.monthDay;
final NetworkTemplate template = buildTemplateMobileAll(subscriberId);
- mNetworkPolicy.put(template, new NetworkPolicy(
- template, cycleDay, warningBytes, LIMIT_DISABLED, SNOOZE_NEVER, true));
+ mNetworkPolicy.put(template, new NetworkPolicy(template, cycleDay, warningBytes,
+ LIMIT_DISABLED, SNOOZE_NEVER, SNOOZE_NEVER, true));
writePolicyLocked();
}
}
@@ -935,11 +968,13 @@
final int cycleDay = readIntAttribute(in, ATTR_CYCLE_DAY);
final long warningBytes = readLongAttribute(in, ATTR_WARNING_BYTES);
final long limitBytes = readLongAttribute(in, ATTR_LIMIT_BYTES);
- final long lastSnooze;
- if (version >= VERSION_ADDED_SNOOZE) {
- lastSnooze = readLongAttribute(in, ATTR_LAST_SNOOZE);
+ final long lastLimitSnooze;
+ if (version >= VERSION_SPLIT_SNOOZE) {
+ lastLimitSnooze = readLongAttribute(in, ATTR_LAST_LIMIT_SNOOZE);
+ } else if (version >= VERSION_ADDED_SNOOZE) {
+ lastLimitSnooze = readLongAttribute(in, ATTR_LAST_SNOOZE);
} else {
- lastSnooze = SNOOZE_NEVER;
+ lastLimitSnooze = SNOOZE_NEVER;
}
final boolean metered;
if (version >= VERSION_ADDED_METERED) {
@@ -955,11 +990,18 @@
metered = false;
}
}
+ final long lastWarningSnooze;
+ if (version >= VERSION_SPLIT_SNOOZE) {
+ lastWarningSnooze = readLongAttribute(in, ATTR_LAST_WARNING_SNOOZE);
+ } else {
+ lastWarningSnooze = SNOOZE_NEVER;
+ }
final NetworkTemplate template = new NetworkTemplate(
networkTemplate, subscriberId);
- mNetworkPolicy.put(template, new NetworkPolicy(
- template, cycleDay, warningBytes, limitBytes, lastSnooze, metered));
+ mNetworkPolicy.put(template, new NetworkPolicy(template, cycleDay,
+ warningBytes, limitBytes, lastWarningSnooze, lastLimitSnooze,
+ metered));
} else if (TAG_UID_POLICY.equals(tag)) {
final int uid = readIntAttribute(in, ATTR_UID);
@@ -1014,7 +1056,7 @@
out.startDocument(null, true);
out.startTag(null, TAG_POLICY_LIST);
- writeIntAttribute(out, ATTR_VERSION, VERSION_ADDED_METERED);
+ writeIntAttribute(out, ATTR_VERSION, VERSION_SPLIT_SNOOZE);
writeBooleanAttribute(out, ATTR_RESTRICT_BACKGROUND, mRestrictBackground);
// write all known network policies
@@ -1030,7 +1072,8 @@
writeIntAttribute(out, ATTR_CYCLE_DAY, policy.cycleDay);
writeLongAttribute(out, ATTR_WARNING_BYTES, policy.warningBytes);
writeLongAttribute(out, ATTR_LIMIT_BYTES, policy.limitBytes);
- writeLongAttribute(out, ATTR_LAST_SNOOZE, policy.lastSnooze);
+ writeLongAttribute(out, ATTR_LAST_WARNING_SNOOZE, policy.lastWarningSnooze);
+ writeLongAttribute(out, ATTR_LAST_LIMIT_SNOOZE, policy.lastLimitSnooze);
writeBooleanAttribute(out, ATTR_METERED, policy.metered);
out.endTag(null, TAG_NETWORK_POLICY);
}
@@ -1141,9 +1184,12 @@
}
@Override
- public void snoozePolicy(NetworkTemplate template) {
+ public void snoozeLimit(NetworkTemplate template) {
mContext.enforceCallingOrSelfPermission(MANAGE_NETWORK_POLICY, TAG);
+ performSnooze(template, TYPE_LIMIT);
+ }
+ private void performSnooze(NetworkTemplate template, int type) {
maybeRefreshTrustedTime();
final long currentTime = currentTimeMillis();
synchronized (mRulesLock) {
@@ -1153,7 +1199,16 @@
throw new IllegalArgumentException("unable to find policy for " + template);
}
- policy.lastSnooze = currentTime;
+ switch (type) {
+ case TYPE_WARNING:
+ policy.lastWarningSnooze = currentTime;
+ break;
+ case TYPE_LIMIT:
+ policy.lastLimitSnooze = currentTime;
+ break;
+ default:
+ throw new IllegalArgumentException("unexpected type");
+ }
updateNetworkEnabledLocked();
updateNetworkRulesLocked();
@@ -1246,12 +1301,17 @@
}
synchronized (mRulesLock) {
- if (argSet.contains("unsnooze")) {
+ if (argSet.contains("--unsnooze")) {
for (NetworkPolicy policy : mNetworkPolicy.values()) {
- policy.lastSnooze = SNOOZE_NEVER;
+ policy.clearSnooze();
}
+
+ updateNetworkEnabledLocked();
+ updateNetworkRulesLocked();
+ updateNotificationsLocked();
writePolicyLocked();
- fout.println("Wiped snooze timestamps");
+
+ fout.println("Cleared snooze timestamps");
return;
}
@@ -1573,6 +1633,9 @@
private long getTotalBytes(NetworkTemplate template, long start, long end) {
try {
return mNetworkStats.getSummaryForNetwork(template, start, end).getTotalBytes();
+ } catch (RuntimeException e) {
+ Slog.w(TAG, "problem reading network stats: " + e);
+ return 0;
} catch (RemoteException e) {
// ignored; service lives in system_server
return 0;
@@ -1596,6 +1659,12 @@
return new Intent(ACTION_ALLOW_BACKGROUND);
}
+ private static Intent buildSnoozeWarningIntent(NetworkTemplate template) {
+ final Intent intent = new Intent(ACTION_SNOOZE_WARNING);
+ intent.putExtra(EXTRA_NETWORK_TEMPLATE, template);
+ return intent;
+ }
+
private static Intent buildNetworkOverLimitIntent(NetworkTemplate template) {
final Intent intent = new Intent();
intent.setComponent(new ComponentName(
diff --git a/services/java/com/android/server/net/NetworkStatsCollection.java b/services/java/com/android/server/net/NetworkStatsCollection.java
new file mode 100644
index 0000000..70038d9
--- /dev/null
+++ b/services/java/com/android/server/net/NetworkStatsCollection.java
@@ -0,0 +1,510 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.net;
+
+import static android.net.NetworkStats.IFACE_ALL;
+import static android.net.NetworkStats.SET_ALL;
+import static android.net.NetworkStats.SET_DEFAULT;
+import static android.net.NetworkStats.TAG_NONE;
+import static android.net.NetworkStats.UID_ALL;
+import static android.net.TrafficStats.UID_REMOVED;
+
+import android.net.NetworkIdentity;
+import android.net.NetworkStats;
+import android.net.NetworkStatsHistory;
+import android.net.NetworkTemplate;
+import android.net.TrafficStats;
+import android.text.format.DateUtils;
+
+import com.android.internal.os.AtomicFile;
+import com.android.internal.util.FileRotator;
+import com.android.internal.util.IndentingPrintWriter;
+import com.android.internal.util.Objects;
+import com.google.android.collect.Lists;
+import com.google.android.collect.Maps;
+
+import java.io.BufferedInputStream;
+import java.io.DataInputStream;
+import java.io.DataOutputStream;
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.ProtocolException;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+
+import libcore.io.IoUtils;
+
+/**
+ * Collection of {@link NetworkStatsHistory}, stored based on combined key of
+ * {@link NetworkIdentitySet}, UID, set, and tag. Knows how to persist itself.
+ */
+public class NetworkStatsCollection implements FileRotator.Reader {
+ private static final String TAG = "NetworkStatsCollection";
+
+ /** File header magic number: "ANET" */
+ private static final int FILE_MAGIC = 0x414E4554;
+
+ private static final int VERSION_NETWORK_INIT = 1;
+
+ private static final int VERSION_UID_INIT = 1;
+ private static final int VERSION_UID_WITH_IDENT = 2;
+ private static final int VERSION_UID_WITH_TAG = 3;
+ private static final int VERSION_UID_WITH_SET = 4;
+
+ private static final int VERSION_UNIFIED_INIT = 16;
+
+ private HashMap<Key, NetworkStatsHistory> mStats = Maps.newHashMap();
+
+ private long mBucketDuration;
+
+ private long mStartMillis;
+ private long mEndMillis;
+ private long mTotalBytes;
+ private boolean mDirty;
+
+ public NetworkStatsCollection(long bucketDuration) {
+ mBucketDuration = bucketDuration;
+ reset();
+ }
+
+ public void reset() {
+ mStats.clear();
+ mStartMillis = Long.MAX_VALUE;
+ mEndMillis = Long.MIN_VALUE;
+ mTotalBytes = 0;
+ mDirty = false;
+ }
+
+ public long getStartMillis() {
+ return mStartMillis;
+ }
+
+ public long getEndMillis() {
+ return mEndMillis;
+ }
+
+ public long getTotalBytes() {
+ return mTotalBytes;
+ }
+
+ public boolean isDirty() {
+ return mDirty;
+ }
+
+ public void clearDirty() {
+ mDirty = false;
+ }
+
+ public boolean isEmpty() {
+ return mStartMillis == Long.MAX_VALUE && mEndMillis == Long.MIN_VALUE;
+ }
+
+ /**
+ * Combine all {@link NetworkStatsHistory} in this collection which match
+ * the requested parameters.
+ */
+ public NetworkStatsHistory getHistory(
+ NetworkTemplate template, int uid, int set, int tag, int fields) {
+ final NetworkStatsHistory combined = new NetworkStatsHistory(
+ mBucketDuration, estimateBuckets(), fields);
+ for (Map.Entry<Key, NetworkStatsHistory> entry : mStats.entrySet()) {
+ final Key key = entry.getKey();
+ final boolean setMatches = set == SET_ALL || key.set == set;
+ if (key.uid == uid && setMatches && key.tag == tag
+ && templateMatches(template, key.ident)) {
+ combined.recordEntireHistory(entry.getValue());
+ }
+ }
+ return combined;
+ }
+
+ /**
+ * Summarize all {@link NetworkStatsHistory} in this collection which match
+ * the requested parameters.
+ */
+ public NetworkStats getSummary(NetworkTemplate template, long start, long end) {
+ final long now = System.currentTimeMillis();
+
+ final NetworkStats stats = new NetworkStats(end - start, 24);
+ final NetworkStats.Entry entry = new NetworkStats.Entry();
+ NetworkStatsHistory.Entry historyEntry = null;
+
+ for (Map.Entry<Key, NetworkStatsHistory> mapEntry : mStats.entrySet()) {
+ final Key key = mapEntry.getKey();
+ if (templateMatches(template, key.ident)) {
+ final NetworkStatsHistory history = mapEntry.getValue();
+ historyEntry = history.getValues(start, end, now, historyEntry);
+
+ entry.iface = IFACE_ALL;
+ entry.uid = key.uid;
+ entry.set = key.set;
+ entry.tag = key.tag;
+ entry.rxBytes = historyEntry.rxBytes;
+ entry.rxPackets = historyEntry.rxPackets;
+ entry.txBytes = historyEntry.txBytes;
+ entry.txPackets = historyEntry.txPackets;
+ entry.operations = historyEntry.operations;
+
+ if (!entry.isEmpty()) {
+ stats.combineValues(entry);
+ }
+ }
+ }
+
+ return stats;
+ }
+
+ /**
+ * Record given {@link NetworkStats.Entry} into this collection.
+ */
+ public void recordData(NetworkIdentitySet ident, int uid, int set, int tag, long start,
+ long end, NetworkStats.Entry entry) {
+ noteRecordedHistory(start, end, entry.rxBytes + entry.txBytes);
+ findOrCreateHistory(ident, uid, set, tag).recordData(start, end, entry);
+ }
+
+ /**
+ * Record given {@link NetworkStatsHistory} into this collection.
+ */
+ private void recordHistory(Key key, NetworkStatsHistory history) {
+ if (history.size() == 0) return;
+ noteRecordedHistory(history.getStart(), history.getEnd(), history.getTotalBytes());
+
+ final NetworkStatsHistory existing = mStats.get(key);
+ if (existing != null) {
+ existing.recordEntireHistory(history);
+ } else {
+ mStats.put(key, history);
+ }
+ }
+
+ /**
+ * Record all {@link NetworkStatsHistory} contained in the given collection
+ * into this collection.
+ */
+ public void recordCollection(NetworkStatsCollection another) {
+ for (Map.Entry<Key, NetworkStatsHistory> entry : another.mStats.entrySet()) {
+ recordHistory(entry.getKey(), entry.getValue());
+ }
+ }
+
+ private NetworkStatsHistory findOrCreateHistory(
+ NetworkIdentitySet ident, int uid, int set, int tag) {
+ final Key key = new Key(ident, uid, set, tag);
+ final NetworkStatsHistory existing = mStats.get(key);
+
+ // update when no existing, or when bucket duration changed
+ NetworkStatsHistory updated = null;
+ if (existing == null) {
+ updated = new NetworkStatsHistory(mBucketDuration, 10);
+ } else if (existing.getBucketDuration() != mBucketDuration) {
+ updated = new NetworkStatsHistory(existing, mBucketDuration);
+ }
+
+ if (updated != null) {
+ mStats.put(key, updated);
+ return updated;
+ } else {
+ return existing;
+ }
+ }
+
+ /** {@inheritDoc} */
+ public void read(InputStream in) throws IOException {
+ read(new DataInputStream(in));
+ }
+
+ public void read(DataInputStream in) throws IOException {
+ // verify file magic header intact
+ final int magic = in.readInt();
+ if (magic != FILE_MAGIC) {
+ throw new ProtocolException("unexpected magic: " + magic);
+ }
+
+ final int version = in.readInt();
+ switch (version) {
+ case VERSION_UNIFIED_INIT: {
+ // uid := size *(NetworkIdentitySet size *(uid set tag NetworkStatsHistory))
+ final int identSize = in.readInt();
+ for (int i = 0; i < identSize; i++) {
+ final NetworkIdentitySet ident = new NetworkIdentitySet(in);
+
+ final int size = in.readInt();
+ for (int j = 0; j < size; j++) {
+ final int uid = in.readInt();
+ final int set = in.readInt();
+ final int tag = in.readInt();
+
+ final Key key = new Key(ident, uid, set, tag);
+ final NetworkStatsHistory history = new NetworkStatsHistory(in);
+ recordHistory(key, history);
+ }
+ }
+ break;
+ }
+ default: {
+ throw new ProtocolException("unexpected version: " + version);
+ }
+ }
+ }
+
+ public void write(DataOutputStream out) throws IOException {
+ // cluster key lists grouped by ident
+ final HashMap<NetworkIdentitySet, ArrayList<Key>> keysByIdent = Maps.newHashMap();
+ for (Key key : mStats.keySet()) {
+ ArrayList<Key> keys = keysByIdent.get(key.ident);
+ if (keys == null) {
+ keys = Lists.newArrayList();
+ keysByIdent.put(key.ident, keys);
+ }
+ keys.add(key);
+ }
+
+ out.writeInt(FILE_MAGIC);
+ out.writeInt(VERSION_UNIFIED_INIT);
+
+ out.writeInt(keysByIdent.size());
+ for (NetworkIdentitySet ident : keysByIdent.keySet()) {
+ final ArrayList<Key> keys = keysByIdent.get(ident);
+ ident.writeToStream(out);
+
+ out.writeInt(keys.size());
+ for (Key key : keys) {
+ final NetworkStatsHistory history = mStats.get(key);
+ out.writeInt(key.uid);
+ out.writeInt(key.set);
+ out.writeInt(key.tag);
+ history.writeToStream(out);
+ }
+ }
+
+ out.flush();
+ }
+
+ @Deprecated
+ public void readLegacyNetwork(File file) throws IOException {
+ final AtomicFile inputFile = new AtomicFile(file);
+
+ DataInputStream in = null;
+ try {
+ in = new DataInputStream(new BufferedInputStream(inputFile.openRead()));
+
+ // verify file magic header intact
+ final int magic = in.readInt();
+ if (magic != FILE_MAGIC) {
+ throw new ProtocolException("unexpected magic: " + magic);
+ }
+
+ final int version = in.readInt();
+ switch (version) {
+ case VERSION_NETWORK_INIT: {
+ // network := size *(NetworkIdentitySet NetworkStatsHistory)
+ final int size = in.readInt();
+ for (int i = 0; i < size; i++) {
+ final NetworkIdentitySet ident = new NetworkIdentitySet(in);
+ final NetworkStatsHistory history = new NetworkStatsHistory(in);
+
+ final Key key = new Key(ident, UID_ALL, SET_ALL, TAG_NONE);
+ recordHistory(key, history);
+ }
+ break;
+ }
+ default: {
+ throw new ProtocolException("unexpected version: " + version);
+ }
+ }
+ } catch (FileNotFoundException e) {
+ // missing stats is okay, probably first boot
+ } finally {
+ IoUtils.closeQuietly(in);
+ }
+ }
+
+ @Deprecated
+ public void readLegacyUid(File file, boolean onlyTags) throws IOException {
+ final AtomicFile inputFile = new AtomicFile(file);
+
+ DataInputStream in = null;
+ try {
+ in = new DataInputStream(new BufferedInputStream(inputFile.openRead()));
+
+ // verify file magic header intact
+ final int magic = in.readInt();
+ if (magic != FILE_MAGIC) {
+ throw new ProtocolException("unexpected magic: " + magic);
+ }
+
+ final int version = in.readInt();
+ switch (version) {
+ case VERSION_UID_INIT: {
+ // uid := size *(UID NetworkStatsHistory)
+
+ // drop this data version, since we don't have a good
+ // mapping into NetworkIdentitySet.
+ break;
+ }
+ case VERSION_UID_WITH_IDENT: {
+ // uid := size *(NetworkIdentitySet size *(UID NetworkStatsHistory))
+
+ // drop this data version, since this version only existed
+ // for a short time.
+ break;
+ }
+ case VERSION_UID_WITH_TAG:
+ case VERSION_UID_WITH_SET: {
+ // uid := size *(NetworkIdentitySet size *(uid set tag NetworkStatsHistory))
+ final int identSize = in.readInt();
+ for (int i = 0; i < identSize; i++) {
+ final NetworkIdentitySet ident = new NetworkIdentitySet(in);
+
+ final int size = in.readInt();
+ for (int j = 0; j < size; j++) {
+ final int uid = in.readInt();
+ final int set = (version >= VERSION_UID_WITH_SET) ? in.readInt()
+ : SET_DEFAULT;
+ final int tag = in.readInt();
+
+ final Key key = new Key(ident, uid, set, tag);
+ final NetworkStatsHistory history = new NetworkStatsHistory(in);
+
+ if ((tag == TAG_NONE) != onlyTags) {
+ recordHistory(key, history);
+ }
+ }
+ }
+ break;
+ }
+ default: {
+ throw new ProtocolException("unexpected version: " + version);
+ }
+ }
+ } catch (FileNotFoundException e) {
+ // missing stats is okay, probably first boot
+ } finally {
+ IoUtils.closeQuietly(in);
+ }
+ }
+
+ /**
+ * Remove any {@link NetworkStatsHistory} attributed to the requested UID,
+ * moving any {@link NetworkStats#TAG_NONE} series to
+ * {@link TrafficStats#UID_REMOVED}.
+ */
+ public void removeUid(int uid) {
+ final ArrayList<Key> knownKeys = Lists.newArrayList();
+ knownKeys.addAll(mStats.keySet());
+
+ // migrate all UID stats into special "removed" bucket
+ for (Key key : knownKeys) {
+ if (key.uid == uid) {
+ // only migrate combined TAG_NONE history
+ if (key.tag == TAG_NONE) {
+ final NetworkStatsHistory uidHistory = mStats.get(key);
+ final NetworkStatsHistory removedHistory = findOrCreateHistory(
+ key.ident, UID_REMOVED, SET_DEFAULT, TAG_NONE);
+ removedHistory.recordEntireHistory(uidHistory);
+ }
+ mStats.remove(key);
+ mDirty = true;
+ }
+ }
+ }
+
+ private void noteRecordedHistory(long startMillis, long endMillis, long totalBytes) {
+ if (startMillis < mStartMillis) mStartMillis = startMillis;
+ if (endMillis > mEndMillis) mEndMillis = endMillis;
+ mTotalBytes += totalBytes;
+ mDirty = true;
+ }
+
+ private int estimateBuckets() {
+ return (int) (Math.min(mEndMillis - mStartMillis, DateUtils.WEEK_IN_MILLIS * 5)
+ / mBucketDuration);
+ }
+
+ public void dump(IndentingPrintWriter pw) {
+ final ArrayList<Key> keys = Lists.newArrayList();
+ keys.addAll(mStats.keySet());
+ Collections.sort(keys);
+
+ for (Key key : keys) {
+ pw.print("ident="); pw.print(key.ident.toString());
+ pw.print(" uid="); pw.print(key.uid);
+ pw.print(" set="); pw.print(NetworkStats.setToString(key.set));
+ pw.print(" tag="); pw.println(NetworkStats.tagToString(key.tag));
+
+ final NetworkStatsHistory history = mStats.get(key);
+ pw.increaseIndent();
+ history.dump(pw, true);
+ pw.decreaseIndent();
+ }
+ }
+
+ /**
+ * Test if given {@link NetworkTemplate} matches any {@link NetworkIdentity}
+ * in the given {@link NetworkIdentitySet}.
+ */
+ private static boolean templateMatches(NetworkTemplate template, NetworkIdentitySet identSet) {
+ for (NetworkIdentity ident : identSet) {
+ if (template.matches(ident)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ private static class Key implements Comparable<Key> {
+ public final NetworkIdentitySet ident;
+ public final int uid;
+ public final int set;
+ public final int tag;
+
+ private final int hashCode;
+
+ public Key(NetworkIdentitySet ident, int uid, int set, int tag) {
+ this.ident = ident;
+ this.uid = uid;
+ this.set = set;
+ this.tag = tag;
+ hashCode = Objects.hashCode(ident, uid, set, tag);
+ }
+
+ @Override
+ public int hashCode() {
+ return hashCode;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (obj instanceof Key) {
+ final Key key = (Key) obj;
+ return uid == key.uid && set == key.set && tag == key.tag
+ && Objects.equal(ident, key.ident);
+ }
+ return false;
+ }
+
+ /** {@inheritDoc} */
+ public int compareTo(Key another) {
+ return Integer.compare(uid, another.uid);
+ }
+ }
+}
diff --git a/services/java/com/android/server/net/NetworkStatsRecorder.java b/services/java/com/android/server/net/NetworkStatsRecorder.java
new file mode 100644
index 0000000..e7ba358
--- /dev/null
+++ b/services/java/com/android/server/net/NetworkStatsRecorder.java
@@ -0,0 +1,341 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.net;
+
+import static android.net.NetworkStats.TAG_NONE;
+import static com.android.internal.util.Preconditions.checkNotNull;
+
+import android.net.NetworkStats;
+import android.net.NetworkStats.NonMonotonicObserver;
+import android.net.NetworkStatsHistory;
+import android.net.NetworkTemplate;
+import android.net.TrafficStats;
+import android.util.Log;
+import android.util.Slog;
+
+import com.android.internal.util.FileRotator;
+import com.android.internal.util.IndentingPrintWriter;
+import com.google.android.collect.Sets;
+
+import java.io.DataOutputStream;
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.lang.ref.WeakReference;
+import java.util.HashSet;
+import java.util.Map;
+
+/**
+ * Logic to record deltas between periodic {@link NetworkStats} snapshots into
+ * {@link NetworkStatsHistory} that belong to {@link NetworkStatsCollection}.
+ * Keeps pending changes in memory until they pass a specific threshold, in
+ * bytes. Uses {@link FileRotator} for persistence logic.
+ * <p>
+ * Not inherently thread safe.
+ */
+public class NetworkStatsRecorder {
+ private static final String TAG = "NetworkStatsRecorder";
+ private static final boolean LOGD = true;
+
+ private final FileRotator mRotator;
+ private final NonMonotonicObserver<String> mObserver;
+ private final String mCookie;
+
+ private final long mBucketDuration;
+ private final long mPersistThresholdBytes;
+ private final boolean mOnlyTags;
+
+ private NetworkStats mLastSnapshot;
+
+ private final NetworkStatsCollection mPending;
+ private final NetworkStatsCollection mSinceBoot;
+
+ private final CombiningRewriter mPendingRewriter;
+
+ private WeakReference<NetworkStatsCollection> mComplete;
+
+ public NetworkStatsRecorder(FileRotator rotator, NonMonotonicObserver<String> observer,
+ String cookie, long bucketDuration, long persistThresholdBytes, boolean onlyTags) {
+ mRotator = checkNotNull(rotator, "missing FileRotator");
+ mObserver = checkNotNull(observer, "missing NonMonotonicObserver");
+ mCookie = cookie;
+
+ mBucketDuration = bucketDuration;
+ mPersistThresholdBytes = persistThresholdBytes;
+ mOnlyTags = onlyTags;
+
+ mPending = new NetworkStatsCollection(bucketDuration);
+ mSinceBoot = new NetworkStatsCollection(bucketDuration);
+
+ mPendingRewriter = new CombiningRewriter(mPending);
+ }
+
+ public void resetLocked() {
+ mLastSnapshot = null;
+ mPending.reset();
+ mSinceBoot.reset();
+ mComplete.clear();
+ }
+
+ public NetworkStats.Entry getTotalSinceBootLocked(NetworkTemplate template) {
+ return mSinceBoot.getSummary(template, Long.MIN_VALUE, Long.MAX_VALUE).getTotal(null);
+ }
+
+ /**
+ * Load complete history represented by {@link FileRotator}. Caches
+ * internally as a {@link WeakReference}, and updated with future
+ * {@link #recordSnapshotLocked(NetworkStats, Map, long)} snapshots as long
+ * as reference is valid.
+ */
+ public NetworkStatsCollection getOrLoadCompleteLocked() {
+ NetworkStatsCollection complete = mComplete != null ? mComplete.get() : null;
+ if (complete == null) {
+ if (LOGD) Slog.d(TAG, "getOrLoadCompleteLocked() reading from disk for " + mCookie);
+ try {
+ complete = new NetworkStatsCollection(mBucketDuration);
+ mRotator.readMatching(complete, Long.MIN_VALUE, Long.MAX_VALUE);
+ complete.recordCollection(mPending);
+ mComplete = new WeakReference<NetworkStatsCollection>(complete);
+ } catch (IOException e) {
+ Log.wtf(TAG, "problem completely reading network stats", e);
+ }
+ }
+ return complete;
+ }
+
+ /**
+ * Record any delta that occurred since last {@link NetworkStats} snapshot,
+ * using the given {@link Map} to identify network interfaces. First
+ * snapshot is considered bootstrap, and is not counted as delta.
+ */
+ public void recordSnapshotLocked(NetworkStats snapshot,
+ Map<String, NetworkIdentitySet> ifaceIdent, long currentTimeMillis) {
+ final HashSet<String> unknownIfaces = Sets.newHashSet();
+
+ // assume first snapshot is bootstrap and don't record
+ if (mLastSnapshot == null) {
+ mLastSnapshot = snapshot;
+ return;
+ }
+
+ final NetworkStatsCollection complete = mComplete != null ? mComplete.get() : null;
+
+ final NetworkStats delta = NetworkStats.subtract(
+ snapshot, mLastSnapshot, mObserver, mCookie);
+ final long end = currentTimeMillis;
+ final long start = end - delta.getElapsedRealtime();
+
+ NetworkStats.Entry entry = null;
+ for (int i = 0; i < delta.size(); i++) {
+ entry = delta.getValues(i, entry);
+ final NetworkIdentitySet ident = ifaceIdent.get(entry.iface);
+ if (ident == null) {
+ unknownIfaces.add(entry.iface);
+ continue;
+ }
+
+ // skip when no delta occured
+ if (entry.isEmpty()) continue;
+
+ // only record tag data when requested
+ if ((entry.tag == TAG_NONE) != mOnlyTags) {
+ mPending.recordData(ident, entry.uid, entry.set, entry.tag, start, end, entry);
+
+ // also record against boot stats when present
+ if (mSinceBoot != null) {
+ mSinceBoot.recordData(ident, entry.uid, entry.set, entry.tag, start, end, entry);
+ }
+
+ // also record against complete dataset when present
+ if (complete != null) {
+ complete.recordData(ident, entry.uid, entry.set, entry.tag, start, end, entry);
+ }
+ }
+ }
+
+ mLastSnapshot = snapshot;
+
+ if (LOGD && unknownIfaces.size() > 0) {
+ Slog.w(TAG, "unknown interfaces " + unknownIfaces + ", ignoring those stats");
+ }
+ }
+
+ /**
+ * Consider persisting any pending deltas, if they are beyond
+ * {@link #mPersistThresholdBytes}.
+ */
+ public void maybePersistLocked(long currentTimeMillis) {
+ final long pendingBytes = mPending.getTotalBytes();
+ if (pendingBytes >= mPersistThresholdBytes) {
+ forcePersistLocked(currentTimeMillis);
+ } else {
+ mRotator.maybeRotate(currentTimeMillis);
+ }
+ }
+
+ /**
+ * Force persisting any pending deltas.
+ */
+ public void forcePersistLocked(long currentTimeMillis) {
+ if (mPending.isDirty()) {
+ if (LOGD) Slog.d(TAG, "forcePersistLocked() writing for " + mCookie);
+ try {
+ mRotator.rewriteActive(mPendingRewriter, currentTimeMillis);
+ mRotator.maybeRotate(currentTimeMillis);
+ mPending.reset();
+ } catch (IOException e) {
+ Log.wtf(TAG, "problem persisting pending stats", e);
+ }
+ }
+ }
+
+ /**
+ * Remove the given UID from all {@link FileRotator} history, migrating it
+ * to {@link TrafficStats#UID_REMOVED}.
+ */
+ public void removeUidLocked(int uid) {
+ try {
+ // process all existing data to migrate uid
+ mRotator.rewriteAll(new RemoveUidRewriter(mBucketDuration, uid));
+ } catch (IOException e) {
+ Log.wtf(TAG, "problem removing UID " + uid, e);
+ }
+
+ // clear UID from current stats snapshot
+ if (mLastSnapshot != null) {
+ mLastSnapshot = mLastSnapshot.withoutUid(uid);
+ }
+ }
+
+ /**
+ * Rewriter that will combine current {@link NetworkStatsCollection} values
+ * with anything read from disk, and write combined set to disk. Clears the
+ * original {@link NetworkStatsCollection} when finished writing.
+ */
+ private static class CombiningRewriter implements FileRotator.Rewriter {
+ private final NetworkStatsCollection mCollection;
+
+ public CombiningRewriter(NetworkStatsCollection collection) {
+ mCollection = checkNotNull(collection, "missing NetworkStatsCollection");
+ }
+
+ /** {@inheritDoc} */
+ public void reset() {
+ // ignored
+ }
+
+ /** {@inheritDoc} */
+ public void read(InputStream in) throws IOException {
+ mCollection.read(in);
+ }
+
+ /** {@inheritDoc} */
+ public boolean shouldWrite() {
+ return true;
+ }
+
+ /** {@inheritDoc} */
+ public void write(OutputStream out) throws IOException {
+ mCollection.write(new DataOutputStream(out));
+ mCollection.reset();
+ }
+ }
+
+ /**
+ * Rewriter that will remove any {@link NetworkStatsHistory} attributed to
+ * the requested UID, only writing data back when modified.
+ */
+ public static class RemoveUidRewriter implements FileRotator.Rewriter {
+ private final NetworkStatsCollection mTemp;
+ private final int mUid;
+
+ public RemoveUidRewriter(long bucketDuration, int uid) {
+ mTemp = new NetworkStatsCollection(bucketDuration);
+ mUid = uid;
+ }
+
+ /** {@inheritDoc} */
+ public void reset() {
+ mTemp.reset();
+ }
+
+ /** {@inheritDoc} */
+ public void read(InputStream in) throws IOException {
+ mTemp.read(in);
+ mTemp.clearDirty();
+ mTemp.removeUid(mUid);
+ }
+
+ /** {@inheritDoc} */
+ public boolean shouldWrite() {
+ return mTemp.isDirty();
+ }
+
+ /** {@inheritDoc} */
+ public void write(OutputStream out) throws IOException {
+ mTemp.write(new DataOutputStream(out));
+ }
+ }
+
+ public void importLegacyNetworkLocked(File file) throws IOException {
+ // legacy file still exists; start empty to avoid double importing
+ mRotator.deleteAll();
+
+ final NetworkStatsCollection collection = new NetworkStatsCollection(mBucketDuration);
+ collection.readLegacyNetwork(file);
+
+ final long startMillis = collection.getStartMillis();
+ final long endMillis = collection.getEndMillis();
+
+ if (!collection.isEmpty()) {
+ // process legacy data, creating active file at starting time, then
+ // using end time to possibly trigger rotation.
+ mRotator.rewriteActive(new CombiningRewriter(collection), startMillis);
+ mRotator.maybeRotate(endMillis);
+ }
+ }
+
+ public void importLegacyUidLocked(File file) throws IOException {
+ // legacy file still exists; start empty to avoid double importing
+ mRotator.deleteAll();
+
+ final NetworkStatsCollection collection = new NetworkStatsCollection(mBucketDuration);
+ collection.readLegacyUid(file, mOnlyTags);
+
+ final long startMillis = collection.getStartMillis();
+ final long endMillis = collection.getEndMillis();
+
+ if (!collection.isEmpty()) {
+ // process legacy data, creating active file at starting time, then
+ // using end time to possibly trigger rotation.
+ mRotator.rewriteActive(new CombiningRewriter(collection), startMillis);
+ mRotator.maybeRotate(endMillis);
+ }
+ }
+
+ public void dumpLocked(IndentingPrintWriter pw, boolean fullHistory) {
+ pw.print("Pending bytes: "); pw.println(mPending.getTotalBytes());
+ if (fullHistory) {
+ pw.println("Complete history:");
+ getOrLoadCompleteLocked().dump(pw);
+ } else {
+ pw.println("History since boot:");
+ mSinceBoot.dump(pw);
+ }
+ }
+}
diff --git a/services/java/com/android/server/net/NetworkStatsService.java b/services/java/com/android/server/net/NetworkStatsService.java
index eeb7fec..414ed1e 100644
--- a/services/java/com/android/server/net/NetworkStatsService.java
+++ b/services/java/com/android/server/net/NetworkStatsService.java
@@ -34,14 +34,18 @@
import static android.net.NetworkStats.UID_ALL;
import static android.net.NetworkTemplate.buildTemplateMobileAll;
import static android.net.NetworkTemplate.buildTemplateWifi;
-import static android.net.TrafficStats.UID_REMOVED;
-import static android.provider.Settings.Secure.NETSTATS_NETWORK_BUCKET_DURATION;
-import static android.provider.Settings.Secure.NETSTATS_NETWORK_MAX_HISTORY;
-import static android.provider.Settings.Secure.NETSTATS_PERSIST_THRESHOLD;
+import static android.provider.Settings.Secure.NETSTATS_DEV_BUCKET_DURATION;
+import static android.provider.Settings.Secure.NETSTATS_DEV_DELETE_AGE;
+import static android.provider.Settings.Secure.NETSTATS_DEV_PERSIST_BYTES;
+import static android.provider.Settings.Secure.NETSTATS_DEV_ROTATE_AGE;
+import static android.provider.Settings.Secure.NETSTATS_GLOBAL_ALERT_BYTES;
import static android.provider.Settings.Secure.NETSTATS_POLL_INTERVAL;
-import static android.provider.Settings.Secure.NETSTATS_TAG_MAX_HISTORY;
+import static android.provider.Settings.Secure.NETSTATS_SAMPLE_ENABLED;
+import static android.provider.Settings.Secure.NETSTATS_TIME_CACHE_MAX_AGE;
import static android.provider.Settings.Secure.NETSTATS_UID_BUCKET_DURATION;
-import static android.provider.Settings.Secure.NETSTATS_UID_MAX_HISTORY;
+import static android.provider.Settings.Secure.NETSTATS_UID_DELETE_AGE;
+import static android.provider.Settings.Secure.NETSTATS_UID_PERSIST_BYTES;
+import static android.provider.Settings.Secure.NETSTATS_UID_ROTATE_AGE;
import static android.telephony.PhoneStateListener.LISTEN_DATA_CONNECTION_STATE;
import static android.telephony.PhoneStateListener.LISTEN_NONE;
import static android.text.format.DateUtils.DAY_IN_MILLIS;
@@ -61,12 +65,10 @@
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
-import android.content.pm.ApplicationInfo;
-import android.content.pm.PackageManager;
-import android.content.pm.PackageManager.NameNotFoundException;
import android.net.IConnectivityManager;
import android.net.INetworkManagementEventObserver;
import android.net.INetworkStatsService;
+import android.net.LinkProperties;
import android.net.NetworkIdentity;
import android.net.NetworkInfo;
import android.net.NetworkState;
@@ -74,6 +76,7 @@
import android.net.NetworkStats.NonMonotonicObserver;
import android.net.NetworkStatsHistory;
import android.net.NetworkTemplate;
+import android.net.TrafficStats;
import android.os.Binder;
import android.os.DropBoxManager;
import android.os.Environment;
@@ -94,32 +97,18 @@
import android.util.SparseIntArray;
import android.util.TrustedTime;
-import com.android.internal.os.AtomicFile;
-import com.android.internal.util.Objects;
+import com.android.internal.util.FileRotator;
+import com.android.internal.util.IndentingPrintWriter;
import com.android.server.EventLogTags;
import com.android.server.connectivity.Tethering;
-import com.google.android.collect.Lists;
import com.google.android.collect.Maps;
-import com.google.android.collect.Sets;
-import java.io.BufferedInputStream;
-import java.io.BufferedOutputStream;
-import java.io.DataInputStream;
-import java.io.DataOutputStream;
import java.io.File;
import java.io.FileDescriptor;
-import java.io.FileNotFoundException;
-import java.io.FileOutputStream;
import java.io.IOException;
import java.io.PrintWriter;
-import java.net.ProtocolException;
-import java.util.ArrayList;
-import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
-import java.util.Random;
-
-import libcore.io.IoUtils;
/**
* Collect and persist detailed network statistics, and provide this data to
@@ -127,19 +116,12 @@
*/
public class NetworkStatsService extends INetworkStatsService.Stub {
private static final String TAG = "NetworkStats";
- private static final boolean LOGD = false;
- private static final boolean LOGV = false;
-
- /** File header magic number: "ANET" */
- private static final int FILE_MAGIC = 0x414E4554;
- private static final int VERSION_NETWORK_INIT = 1;
- private static final int VERSION_UID_INIT = 1;
- private static final int VERSION_UID_WITH_IDENT = 2;
- private static final int VERSION_UID_WITH_TAG = 3;
- private static final int VERSION_UID_WITH_SET = 4;
+ private static final boolean LOGD = true;
+ private static final boolean LOGV = true;
private static final int MSG_PERFORM_POLL = 1;
private static final int MSG_UPDATE_IFACES = 2;
+ private static final int MSG_REGISTER_GLOBAL_ALERT = 3;
/** Flags to control detail level of poll event. */
private static final int FLAG_PERSIST_NETWORK = 0x1;
@@ -147,9 +129,6 @@
private static final int FLAG_PERSIST_ALL = FLAG_PERSIST_NETWORK | FLAG_PERSIST_UID;
private static final int FLAG_PERSIST_FORCE = 0x100;
- /** Sample recent usage after each poll event. */
- private static final boolean ENABLE_SAMPLE_AFTER_POLL = true;
-
private static final String TAG_NETSTATS_ERROR = "netstats_error";
private final Context mContext;
@@ -159,10 +138,12 @@
private final TelephonyManager mTeleManager;
private final NetworkStatsSettings mSettings;
+ private final File mSystemDir;
+ private final File mBaseDir;
+
private final PowerManager.WakeLock mWakeLock;
private IConnectivityManager mConnManager;
- private DropBoxManager mDropBox;
// @VisibleForTesting
public static final String ACTION_NETWORK_STATS_POLL =
@@ -172,71 +153,76 @@
private PendingIntent mPollIntent;
- // TODO: trim empty history objects entirely
-
private static final long KB_IN_BYTES = 1024;
private static final long MB_IN_BYTES = 1024 * KB_IN_BYTES;
private static final long GB_IN_BYTES = 1024 * MB_IN_BYTES;
+ private static final String PREFIX_DEV = "dev";
+ private static final String PREFIX_UID = "uid";
+ private static final String PREFIX_UID_TAG = "uid_tag";
+
/**
* Settings that can be changed externally.
*/
public interface NetworkStatsSettings {
public long getPollInterval();
- public long getPersistThreshold();
- public long getNetworkBucketDuration();
- public long getNetworkMaxHistory();
- public long getUidBucketDuration();
- public long getUidMaxHistory();
- public long getTagMaxHistory();
public long getTimeCacheMaxAge();
+ public long getGlobalAlertBytes();
+ public boolean getSampleEnabled();
+
+ public static class Config {
+ public final long bucketDuration;
+ public final long persistBytes;
+ public final long rotateAgeMillis;
+ public final long deleteAgeMillis;
+
+ public Config(long bucketDuration, long persistBytes, long rotateAgeMillis,
+ long deleteAgeMillis) {
+ this.bucketDuration = bucketDuration;
+ this.persistBytes = persistBytes;
+ this.rotateAgeMillis = rotateAgeMillis;
+ this.deleteAgeMillis = deleteAgeMillis;
+ }
+ }
+
+ public Config getDevConfig();
+ public Config getUidConfig();
+ public Config getUidTagConfig();
}
private final Object mStatsLock = new Object();
/** Set of currently active ifaces. */
private HashMap<String, NetworkIdentitySet> mActiveIfaces = Maps.newHashMap();
- /** Set of historical {@code dev} stats for known networks. */
- private HashMap<NetworkIdentitySet, NetworkStatsHistory> mNetworkDevStats = Maps.newHashMap();
- /** Set of historical {@code xtables} stats for known networks. */
- private HashMap<NetworkIdentitySet, NetworkStatsHistory> mNetworkXtStats = Maps.newHashMap();
- /** Set of historical {@code xtables} stats for known UIDs. */
- private HashMap<UidStatsKey, NetworkStatsHistory> mUidStats = Maps.newHashMap();
+ /** Current default active iface. */
+ private String mActiveIface;
- /** Flag if {@link #mNetworkDevStats} have been loaded from disk. */
- private boolean mNetworkStatsLoaded = false;
- /** Flag if {@link #mUidStats} have been loaded from disk. */
- private boolean mUidStatsLoaded = false;
+ private final DropBoxNonMonotonicObserver mNonMonotonicObserver =
+ new DropBoxNonMonotonicObserver();
- private NetworkStats mLastPollNetworkDevSnapshot;
- private NetworkStats mLastPollNetworkXtSnapshot;
- private NetworkStats mLastPollUidSnapshot;
- private NetworkStats mLastPollOperationsSnapshot;
+ private NetworkStatsRecorder mDevRecorder;
+ private NetworkStatsRecorder mUidRecorder;
+ private NetworkStatsRecorder mUidTagRecorder;
- private NetworkStats mLastPersistNetworkDevSnapshot;
- private NetworkStats mLastPersistNetworkXtSnapshot;
- private NetworkStats mLastPersistUidSnapshot;
+ /** Cached {@link #mDevRecorder} stats. */
+ private NetworkStatsCollection mDevStatsCached;
/** Current counter sets for each UID. */
private SparseIntArray mActiveUidCounterSet = new SparseIntArray();
/** Data layer operation counters for splicing into other structures. */
- private NetworkStats mOperations = new NetworkStats(0L, 10);
+ private NetworkStats mUidOperations = new NetworkStats(0L, 10);
private final HandlerThread mHandlerThread;
private final Handler mHandler;
- private final AtomicFile mNetworkDevFile;
- private final AtomicFile mNetworkXtFile;
- private final AtomicFile mUidFile;
-
public NetworkStatsService(
Context context, INetworkManagementService networkManager, IAlarmManager alarmManager) {
this(context, networkManager, alarmManager, NtpTrustedTime.getInstance(context),
- getSystemDir(), new DefaultNetworkStatsSettings(context));
+ getDefaultSystemDir(), new DefaultNetworkStatsSettings(context));
}
- private static File getSystemDir() {
+ private static File getDefaultSystemDir() {
return new File(Environment.getDataDirectory(), "system");
}
@@ -258,9 +244,9 @@
mHandlerThread.start();
mHandler = new Handler(mHandlerThread.getLooper(), mHandlerCallback);
- mNetworkDevFile = new AtomicFile(new File(systemDir, "netstats.bin"));
- mNetworkXtFile = new AtomicFile(new File(systemDir, "netstats_xt.bin"));
- mUidFile = new AtomicFile(new File(systemDir, "netstats_uid.bin"));
+ mSystemDir = checkNotNull(systemDir);
+ mBaseDir = new File(systemDir, "netstats");
+ mBaseDir.mkdirs();
}
public void bindConnectivityManager(IConnectivityManager connManager) {
@@ -273,17 +259,22 @@
return;
}
- synchronized (mStatsLock) {
- // read historical network stats from disk, since policy service
- // might need them right away. we delay loading detailed UID stats
- // until actually needed.
- readNetworkDevStatsLocked();
- readNetworkXtStatsLocked();
- mNetworkStatsLoaded = true;
- }
+ // create data recorders along with historical rotators
+ mDevRecorder = buildRecorder(PREFIX_DEV, mSettings.getDevConfig(), false);
+ mUidRecorder = buildRecorder(PREFIX_UID, mSettings.getUidConfig(), false);
+ mUidTagRecorder = buildRecorder(PREFIX_UID_TAG, mSettings.getUidTagConfig(), true);
- // bootstrap initial stats to prevent double-counting later
- bootstrapStats();
+ synchronized (mStatsLock) {
+ // upgrade any legacy stats, migrating them to rotated files
+ maybeUpgradeLegacyStatsLocked();
+
+ // read historical network stats from disk, since policy service
+ // might need them right away.
+ mDevStatsCached = mDevRecorder.getOrLoadCompleteLocked();
+
+ // bootstrap initial stats to prevent double-counting later
+ bootstrapStatsLocked();
+ }
// watch for network interfaces to be claimed
final IntentFilter connFilter = new IntentFilter(CONNECTIVITY_ACTION_IMMEDIATE);
@@ -317,8 +308,14 @@
registerPollAlarmLocked();
registerGlobalAlert();
+ }
- mDropBox = (DropBoxManager) mContext.getSystemService(Context.DROPBOX_SERVICE);
+ private NetworkStatsRecorder buildRecorder(
+ String prefix, NetworkStatsSettings.Config config, boolean includeTags) {
+ return new NetworkStatsRecorder(
+ new FileRotator(mBaseDir, prefix, config.rotateAgeMillis, config.deleteAgeMillis),
+ mNonMonotonicObserver, prefix, config.bucketDuration, config.persistBytes,
+ includeTags);
}
private void shutdownLocked() {
@@ -330,18 +327,44 @@
mTeleManager.listen(mPhoneListener, LISTEN_NONE);
- if (mNetworkStatsLoaded) {
- writeNetworkDevStatsLocked();
- writeNetworkXtStatsLocked();
+ final long currentTime = mTime.hasCache() ? mTime.currentTimeMillis()
+ : System.currentTimeMillis();
+
+ // persist any pending stats
+ mDevRecorder.forcePersistLocked(currentTime);
+ mUidRecorder.forcePersistLocked(currentTime);
+ mUidTagRecorder.forcePersistLocked(currentTime);
+
+ mDevRecorder = null;
+ mUidRecorder = null;
+ mUidTagRecorder = null;
+
+ mDevStatsCached = null;
+ }
+
+ private void maybeUpgradeLegacyStatsLocked() {
+ File file;
+ try {
+ file = new File(mSystemDir, "netstats.bin");
+ if (file.exists()) {
+ mDevRecorder.importLegacyNetworkLocked(file);
+ file.delete();
+ }
+
+ file = new File(mSystemDir, "netstats_xt.bin");
+ if (file.exists()) {
+ file.delete();
+ }
+
+ file = new File(mSystemDir, "netstats_uid.bin");
+ if (file.exists()) {
+ mUidRecorder.importLegacyUidLocked(file);
+ mUidTagRecorder.importLegacyUidLocked(file);
+ file.delete();
+ }
+ } catch (IOException e) {
+ Log.wtf(TAG, "problem during legacy upgrade", e);
}
- if (mUidStatsLoaded) {
- writeUidStatsLocked();
- }
- mNetworkDevStats.clear();
- mNetworkXtStats.clear();
- mUidStats.clear();
- mNetworkStatsLoaded = false;
- mUidStatsLoaded = false;
}
/**
@@ -372,7 +395,7 @@
*/
private void registerGlobalAlert() {
try {
- final long alertBytes = mSettings.getPersistThreshold();
+ final long alertBytes = mSettings.getGlobalAlertBytes();
mNetworkManager.setGlobalAlert(alertBytes);
} catch (IllegalStateException e) {
Slog.w(TAG, "problem registering for global alert: " + e);
@@ -383,161 +406,39 @@
@Override
public NetworkStatsHistory getHistoryForNetwork(NetworkTemplate template, int fields) {
- mContext.enforceCallingOrSelfPermission(READ_NETWORK_USAGE_HISTORY, TAG);
- return getHistoryForNetworkDev(template, fields);
+ return mDevStatsCached.getHistory(template, UID_ALL, SET_ALL, TAG_NONE, fields);
}
- private NetworkStatsHistory getHistoryForNetworkDev(NetworkTemplate template, int fields) {
- return getHistoryForNetwork(template, fields, mNetworkDevStats);
- }
-
- private NetworkStatsHistory getHistoryForNetworkXt(NetworkTemplate template, int fields) {
- return getHistoryForNetwork(template, fields, mNetworkXtStats);
- }
-
- private NetworkStatsHistory getHistoryForNetwork(NetworkTemplate template, int fields,
- HashMap<NetworkIdentitySet, NetworkStatsHistory> source) {
- synchronized (mStatsLock) {
- // combine all interfaces that match template
- final NetworkStatsHistory combined = new NetworkStatsHistory(
- mSettings.getNetworkBucketDuration(), estimateNetworkBuckets(), fields);
- for (NetworkIdentitySet ident : source.keySet()) {
- if (templateMatches(template, ident)) {
- final NetworkStatsHistory history = source.get(ident);
- if (history != null) {
- combined.recordEntireHistory(history);
- }
- }
- }
- return combined;
- }
+ @Override
+ public NetworkStats getSummaryForNetwork(NetworkTemplate template, long start, long end) {
+ return mDevStatsCached.getSummary(template, start, end);
}
@Override
public NetworkStatsHistory getHistoryForUid(
NetworkTemplate template, int uid, int set, int tag, int fields) {
- mContext.enforceCallingOrSelfPermission(READ_NETWORK_USAGE_HISTORY, TAG);
-
- synchronized (mStatsLock) {
- ensureUidStatsLoadedLocked();
-
- // combine all interfaces that match template
- final NetworkStatsHistory combined = new NetworkStatsHistory(
- mSettings.getUidBucketDuration(), estimateUidBuckets(), fields);
- for (UidStatsKey key : mUidStats.keySet()) {
- final boolean setMatches = set == SET_ALL || key.set == set;
- if (templateMatches(template, key.ident) && key.uid == uid && setMatches
- && key.tag == tag) {
- final NetworkStatsHistory history = mUidStats.get(key);
- combined.recordEntireHistory(history);
- }
- }
-
- return combined;
+ // TODO: transition to stats sessions to avoid WeakReferences
+ if (tag == TAG_NONE) {
+ return mUidRecorder.getOrLoadCompleteLocked().getHistory(
+ template, uid, set, tag, fields);
+ } else {
+ return mUidTagRecorder.getOrLoadCompleteLocked().getHistory(
+ template, uid, set, tag, fields);
}
}
@Override
- public NetworkStats getSummaryForNetwork(NetworkTemplate template, long start, long end) {
- mContext.enforceCallingOrSelfPermission(READ_NETWORK_USAGE_HISTORY, TAG);
- return getSummaryForNetworkDev(template, start, end);
- }
-
- private NetworkStats getSummaryForNetworkDev(NetworkTemplate template, long start, long end) {
- return getSummaryForNetwork(template, start, end, mNetworkDevStats);
- }
-
- private NetworkStats getSummaryForNetworkXt(NetworkTemplate template, long start, long end) {
- return getSummaryForNetwork(template, start, end, mNetworkXtStats);
- }
-
- private NetworkStats getSummaryForNetwork(NetworkTemplate template, long start, long end,
- HashMap<NetworkIdentitySet, NetworkStatsHistory> source) {
- synchronized (mStatsLock) {
- // use system clock to be externally consistent
- final long now = System.currentTimeMillis();
-
- final NetworkStats stats = new NetworkStats(end - start, 1);
- final NetworkStats.Entry entry = new NetworkStats.Entry();
- NetworkStatsHistory.Entry historyEntry = null;
-
- // combine total from all interfaces that match template
- for (NetworkIdentitySet ident : source.keySet()) {
- if (templateMatches(template, ident)) {
- final NetworkStatsHistory history = source.get(ident);
- historyEntry = history.getValues(start, end, now, historyEntry);
-
- entry.iface = IFACE_ALL;
- entry.uid = UID_ALL;
- entry.tag = TAG_NONE;
- entry.rxBytes = historyEntry.rxBytes;
- entry.rxPackets = historyEntry.rxPackets;
- entry.txBytes = historyEntry.txBytes;
- entry.txPackets = historyEntry.txPackets;
-
- stats.combineValues(entry);
- }
- }
-
- return stats;
- }
- }
-
- private long getHistoryStartLocked(
- NetworkTemplate template, HashMap<NetworkIdentitySet, NetworkStatsHistory> source) {
- long start = Long.MAX_VALUE;
- for (NetworkIdentitySet ident : source.keySet()) {
- if (templateMatches(template, ident)) {
- final NetworkStatsHistory history = source.get(ident);
- start = Math.min(start, history.getStart());
- }
- }
- return start;
- }
-
- @Override
public NetworkStats getSummaryForAllUid(
NetworkTemplate template, long start, long end, boolean includeTags) {
- mContext.enforceCallingOrSelfPermission(READ_NETWORK_USAGE_HISTORY, TAG);
-
- synchronized (mStatsLock) {
- ensureUidStatsLoadedLocked();
-
- // use system clock to be externally consistent
- final long now = System.currentTimeMillis();
-
- final NetworkStats stats = new NetworkStats(end - start, 24);
- final NetworkStats.Entry entry = new NetworkStats.Entry();
- NetworkStatsHistory.Entry historyEntry = null;
-
- for (UidStatsKey key : mUidStats.keySet()) {
- if (templateMatches(template, key.ident)) {
- // always include summary under TAG_NONE, and include
- // other tags when requested.
- if (key.tag == TAG_NONE || includeTags) {
- final NetworkStatsHistory history = mUidStats.get(key);
- historyEntry = history.getValues(start, end, now, historyEntry);
-
- entry.iface = IFACE_ALL;
- entry.uid = key.uid;
- entry.set = key.set;
- entry.tag = key.tag;
- entry.rxBytes = historyEntry.rxBytes;
- entry.rxPackets = historyEntry.rxPackets;
- entry.txBytes = historyEntry.txBytes;
- entry.txPackets = historyEntry.txPackets;
- entry.operations = historyEntry.operations;
-
- if (entry.rxBytes > 0 || entry.rxPackets > 0 || entry.txBytes > 0
- || entry.txPackets > 0 || entry.operations > 0) {
- stats.combineValues(entry);
- }
- }
- }
- }
-
- return stats;
+ // TODO: transition to stats sessions to avoid WeakReferences
+ final NetworkStats stats = mUidRecorder.getOrLoadCompleteLocked().getSummary(
+ template, start, end);
+ if (includeTags) {
+ final NetworkStats tagStats = mUidTagRecorder.getOrLoadCompleteLocked().getSummary(
+ template, start, end);
+ stats.combineAllValues(tagStats);
}
+ return stats;
}
@Override
@@ -567,7 +468,7 @@
}
// splice in operation counts
- dataLayer.spliceOperationsFrom(mOperations);
+ dataLayer.spliceOperationsFrom(mUidOperations);
return dataLayer;
}
@@ -586,8 +487,10 @@
synchronized (mStatsLock) {
final int set = mActiveUidCounterSet.get(uid, SET_DEFAULT);
- mOperations.combineValues(IFACE_ALL, uid, set, tag, 0L, 0L, 0L, 0L, operationCount);
- mOperations.combineValues(IFACE_ALL, uid, set, TAG_NONE, 0L, 0L, 0L, 0L, operationCount);
+ mUidOperations.combineValues(
+ mActiveIface, uid, set, tag, 0L, 0L, 0L, 0L, operationCount);
+ mUidOperations.combineValues(
+ mActiveIface, uid, set, TAG_NONE, 0L, 0L, 0L, 0L, operationCount);
}
}
@@ -608,7 +511,13 @@
@Override
public void forceUpdate() {
mContext.enforceCallingOrSelfPermission(READ_NETWORK_USAGE_HISTORY, TAG);
- performPoll(FLAG_PERSIST_ALL);
+
+ final long token = Binder.clearCallingIdentity();
+ try {
+ performPoll(FLAG_PERSIST_ALL);
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
}
/**
@@ -692,7 +601,7 @@
mHandler.obtainMessage(MSG_PERFORM_POLL, flags, 0).sendToTarget();
// re-arm global alert for next update
- registerGlobalAlert();
+ mHandler.obtainMessage(MSG_REGISTER_GLOBAL_ALERT).sendToTarget();
}
}
};
@@ -755,13 +664,17 @@
performPollLocked(FLAG_PERSIST_NETWORK);
final NetworkState[] states;
+ final LinkProperties activeLink;
try {
states = mConnManager.getAllNetworkState();
+ activeLink = mConnManager.getActiveLinkProperties();
} catch (RemoteException e) {
// ignored; service lives in system_server
return;
}
+ mActiveIface = activeLink != null ? activeLink.getInterfaceName() : null;
+
// rebuild active interfaces based on connected networks
mActiveIfaces.clear();
@@ -785,12 +698,20 @@
* Bootstrap initial stats snapshot, usually during {@link #systemReady()}
* so we have baseline values without double-counting.
*/
- private void bootstrapStats() {
+ private void bootstrapStatsLocked() {
+ final long currentTime = mTime.hasCache() ? mTime.currentTimeMillis()
+ : System.currentTimeMillis();
+
try {
- mLastPollUidSnapshot = mNetworkManager.getNetworkStatsUidDetail(UID_ALL);
- mLastPollNetworkDevSnapshot = mNetworkManager.getNetworkStatsSummary();
- mLastPollNetworkXtSnapshot = computeNetworkXtSnapshotFromUid(mLastPollUidSnapshot);
- mLastPollOperationsSnapshot = new NetworkStats(0L, 0);
+ // snapshot and record current counters; read UID stats first to
+ // avoid overcounting dev stats.
+ final NetworkStats uidSnapshot = getNetworkStatsUidDetail();
+ final NetworkStats devSnapshot = getNetworkStatsSummary();
+
+ mDevRecorder.recordSnapshotLocked(devSnapshot, mActiveIfaces, currentTime);
+ mUidRecorder.recordSnapshotLocked(uidSnapshot, mActiveIfaces, currentTime);
+ mUidTagRecorder.recordSnapshotLocked(uidSnapshot, mActiveIfaces, currentTime);
+
} catch (IllegalStateException e) {
Slog.w(TAG, "problem reading network stats: " + e);
} catch (RemoteException e) {
@@ -830,27 +751,16 @@
// TODO: consider marking "untrusted" times in historical stats
final long currentTime = mTime.hasCache() ? mTime.currentTimeMillis()
: System.currentTimeMillis();
- final long threshold = mSettings.getPersistThreshold();
- final NetworkStats uidSnapshot;
- final NetworkStats networkXtSnapshot;
- final NetworkStats networkDevSnapshot;
try {
- // collect any tethering stats
- final NetworkStats tetherSnapshot = getNetworkStatsTethering();
+ // snapshot and record current counters; read UID stats first to
+ // avoid overcounting dev stats.
+ final NetworkStats uidSnapshot = getNetworkStatsUidDetail();
+ final NetworkStats devSnapshot = getNetworkStatsSummary();
- // record uid stats, folding in tethering stats
- uidSnapshot = mNetworkManager.getNetworkStatsUidDetail(UID_ALL);
- uidSnapshot.combineAllValues(tetherSnapshot);
- performUidPollLocked(uidSnapshot, currentTime);
-
- // record dev network stats
- networkDevSnapshot = mNetworkManager.getNetworkStatsSummary();
- performNetworkDevPollLocked(networkDevSnapshot, currentTime);
-
- // record xt network stats
- networkXtSnapshot = computeNetworkXtSnapshotFromUid(uidSnapshot);
- performNetworkXtPollLocked(networkXtSnapshot, currentTime);
+ mDevRecorder.recordSnapshotLocked(devSnapshot, mActiveIfaces, currentTime);
+ mUidRecorder.recordSnapshotLocked(uidSnapshot, mActiveIfaces, currentTime);
+ mUidTagRecorder.recordSnapshotLocked(uidSnapshot, mActiveIfaces, currentTime);
} catch (IllegalStateException e) {
Log.wtf(TAG, "problem reading network stats", e);
@@ -860,26 +770,19 @@
return;
}
- // persist when enough network data has occurred
- final long persistNetworkDevDelta = computeStatsDelta(
- mLastPersistNetworkDevSnapshot, networkDevSnapshot, true, "devp").getTotalBytes();
- final long persistNetworkXtDelta = computeStatsDelta(
- mLastPersistNetworkXtSnapshot, networkXtSnapshot, true, "xtp").getTotalBytes();
- final boolean networkOverThreshold = persistNetworkDevDelta > threshold
- || persistNetworkXtDelta > threshold;
- if (persistForce || (persistNetwork && networkOverThreshold)) {
- writeNetworkDevStatsLocked();
- writeNetworkXtStatsLocked();
- mLastPersistNetworkDevSnapshot = networkDevSnapshot;
- mLastPersistNetworkXtSnapshot = networkXtSnapshot;
- }
-
- // persist when enough uid data has occurred
- final long persistUidDelta = computeStatsDelta(
- mLastPersistUidSnapshot, uidSnapshot, true, "uidp").getTotalBytes();
- if (persistForce || (persistUid && persistUidDelta > threshold)) {
- writeUidStatsLocked();
- mLastPersistUidSnapshot = uidSnapshot;
+ // persist any pending data depending on requested flags
+ if (persistForce) {
+ mDevRecorder.forcePersistLocked(currentTime);
+ mUidRecorder.forcePersistLocked(currentTime);
+ mUidTagRecorder.forcePersistLocked(currentTime);
+ } else {
+ if (persistNetwork) {
+ mDevRecorder.maybePersistLocked(currentTime);
+ }
+ if (persistUid) {
+ mUidRecorder.maybePersistLocked(currentTime);
+ mUidTagRecorder.maybePersistLocked(currentTime);
+ }
}
if (LOGV) {
@@ -887,9 +790,9 @@
Slog.v(TAG, "performPollLocked() took " + duration + "ms");
}
- if (ENABLE_SAMPLE_AFTER_POLL) {
+ if (mSettings.getSampleEnabled()) {
// sample stats after each full poll
- performSample();
+ performSampleLocked();
}
// finally, dispatch updated event to any listeners
@@ -899,511 +802,58 @@
}
/**
- * Update {@link #mNetworkDevStats} historical usage.
- */
- private void performNetworkDevPollLocked(NetworkStats networkDevSnapshot, long currentTime) {
- final HashSet<String> unknownIface = Sets.newHashSet();
-
- final NetworkStats delta = computeStatsDelta(
- mLastPollNetworkDevSnapshot, networkDevSnapshot, false, "dev");
- final long timeStart = currentTime - delta.getElapsedRealtime();
-
- NetworkStats.Entry entry = null;
- for (int i = 0; i < delta.size(); i++) {
- entry = delta.getValues(i, entry);
- final NetworkIdentitySet ident = mActiveIfaces.get(entry.iface);
- if (ident == null) {
- unknownIface.add(entry.iface);
- continue;
- }
-
- final NetworkStatsHistory history = findOrCreateNetworkDevStatsLocked(ident);
- history.recordData(timeStart, currentTime, entry);
- }
-
- mLastPollNetworkDevSnapshot = networkDevSnapshot;
-
- if (LOGD && unknownIface.size() > 0) {
- Slog.w(TAG, "unknown dev interfaces " + unknownIface + ", ignoring those stats");
- }
- }
-
- /**
- * Update {@link #mNetworkXtStats} historical usage.
- */
- private void performNetworkXtPollLocked(NetworkStats networkXtSnapshot, long currentTime) {
- final HashSet<String> unknownIface = Sets.newHashSet();
-
- final NetworkStats delta = computeStatsDelta(
- mLastPollNetworkXtSnapshot, networkXtSnapshot, false, "xt");
- final long timeStart = currentTime - delta.getElapsedRealtime();
-
- NetworkStats.Entry entry = null;
- for (int i = 0; i < delta.size(); i++) {
- entry = delta.getValues(i, entry);
- final NetworkIdentitySet ident = mActiveIfaces.get(entry.iface);
- if (ident == null) {
- unknownIface.add(entry.iface);
- continue;
- }
-
- final NetworkStatsHistory history = findOrCreateNetworkXtStatsLocked(ident);
- history.recordData(timeStart, currentTime, entry);
- }
-
- mLastPollNetworkXtSnapshot = networkXtSnapshot;
-
- if (LOGD && unknownIface.size() > 0) {
- Slog.w(TAG, "unknown xt interfaces " + unknownIface + ", ignoring those stats");
- }
- }
-
- /**
- * Update {@link #mUidStats} historical usage.
- */
- private void performUidPollLocked(NetworkStats uidSnapshot, long currentTime) {
- ensureUidStatsLoadedLocked();
-
- final NetworkStats delta = computeStatsDelta(
- mLastPollUidSnapshot, uidSnapshot, false, "uid");
- final NetworkStats operationsDelta = computeStatsDelta(
- mLastPollOperationsSnapshot, mOperations, false, "uidop");
- final long timeStart = currentTime - delta.getElapsedRealtime();
-
- NetworkStats.Entry entry = null;
- NetworkStats.Entry operationsEntry = null;
- for (int i = 0; i < delta.size(); i++) {
- entry = delta.getValues(i, entry);
- final NetworkIdentitySet ident = mActiveIfaces.get(entry.iface);
- if (ident == null) {
- if (entry.rxBytes > 0 || entry.rxPackets > 0 || entry.txBytes > 0
- || entry.txPackets > 0) {
- Log.w(TAG, "dropping UID delta from unknown iface: " + entry);
- }
- continue;
- }
-
- // splice in operation counts since last poll
- final int j = operationsDelta.findIndex(IFACE_ALL, entry.uid, entry.set, entry.tag);
- if (j != -1) {
- operationsEntry = operationsDelta.getValues(j, operationsEntry);
- entry.operations = operationsEntry.operations;
- }
-
- final NetworkStatsHistory history = findOrCreateUidStatsLocked(
- ident, entry.uid, entry.set, entry.tag);
- history.recordData(timeStart, currentTime, entry);
- }
-
- mLastPollUidSnapshot = uidSnapshot;
- mLastPollOperationsSnapshot = mOperations.clone();
- }
-
- /**
* Sample recent statistics summary into {@link EventLog}.
*/
- private void performSample() {
- final long largestBucketSize = Math.max(
- mSettings.getNetworkBucketDuration(), mSettings.getUidBucketDuration());
-
- // take sample as atomic buckets
- final long now = mTime.hasCache() ? mTime.currentTimeMillis() : System.currentTimeMillis();
- final long end = now - (now % largestBucketSize) + largestBucketSize;
- final long start = end - largestBucketSize;
-
+ private void performSampleLocked() {
+ // TODO: migrate trustedtime fixes to separate binary log events
final long trustedTime = mTime.hasCache() ? mTime.currentTimeMillis() : -1;
- long devHistoryStart = Long.MAX_VALUE;
- NetworkTemplate template = null;
- NetworkStats.Entry devTotal = null;
- NetworkStats.Entry xtTotal = null;
- NetworkStats.Entry uidTotal = null;
+ NetworkTemplate template;
+ NetworkStats.Entry devTotal;
+ NetworkStats.Entry xtTotal;
+ NetworkStats.Entry uidTotal;
// collect mobile sample
template = buildTemplateMobileAll(getActiveSubscriberId(mContext));
- devTotal = getSummaryForNetworkDev(template, start, end).getTotal(devTotal);
- devHistoryStart = getHistoryStartLocked(template, mNetworkDevStats);
- xtTotal = getSummaryForNetworkXt(template, start, end).getTotal(xtTotal);
- uidTotal = getSummaryForAllUid(template, start, end, false).getTotal(uidTotal);
+ devTotal = mDevRecorder.getTotalSinceBootLocked(template);
+ xtTotal = new NetworkStats.Entry();
+ uidTotal = mUidRecorder.getTotalSinceBootLocked(template);
EventLogTags.writeNetstatsMobileSample(
devTotal.rxBytes, devTotal.rxPackets, devTotal.txBytes, devTotal.txPackets,
xtTotal.rxBytes, xtTotal.rxPackets, xtTotal.txBytes, xtTotal.txPackets,
uidTotal.rxBytes, uidTotal.rxPackets, uidTotal.txBytes, uidTotal.txPackets,
- trustedTime, devHistoryStart);
+ trustedTime);
// collect wifi sample
template = buildTemplateWifi();
- devTotal = getSummaryForNetworkDev(template, start, end).getTotal(devTotal);
- devHistoryStart = getHistoryStartLocked(template, mNetworkDevStats);
- xtTotal = getSummaryForNetworkXt(template, start, end).getTotal(xtTotal);
- uidTotal = getSummaryForAllUid(template, start, end, false).getTotal(uidTotal);
+ devTotal = mDevRecorder.getTotalSinceBootLocked(template);
+ xtTotal = new NetworkStats.Entry();
+ uidTotal = mUidRecorder.getTotalSinceBootLocked(template);
+
EventLogTags.writeNetstatsWifiSample(
devTotal.rxBytes, devTotal.rxPackets, devTotal.txBytes, devTotal.txPackets,
xtTotal.rxBytes, xtTotal.rxPackets, xtTotal.txBytes, xtTotal.txPackets,
uidTotal.rxBytes, uidTotal.rxPackets, uidTotal.txBytes, uidTotal.txPackets,
- trustedTime, devHistoryStart);
+ trustedTime);
}
/**
- * Clean up {@link #mUidStats} after UID is removed.
+ * Clean up {@link #mUidRecorder} after UID is removed.
*/
private void removeUidLocked(int uid) {
- ensureUidStatsLoadedLocked();
-
// perform one last poll before removing
performPollLocked(FLAG_PERSIST_ALL);
- final ArrayList<UidStatsKey> knownKeys = Lists.newArrayList();
- knownKeys.addAll(mUidStats.keySet());
-
- // migrate all UID stats into special "removed" bucket
- for (UidStatsKey key : knownKeys) {
- if (key.uid == uid) {
- // only migrate combined TAG_NONE history
- if (key.tag == TAG_NONE) {
- final NetworkStatsHistory uidHistory = mUidStats.get(key);
- final NetworkStatsHistory removedHistory = findOrCreateUidStatsLocked(
- key.ident, UID_REMOVED, SET_DEFAULT, TAG_NONE);
- removedHistory.recordEntireHistory(uidHistory);
- }
- mUidStats.remove(key);
- }
- }
-
- // clear UID from current stats snapshot
- if (mLastPollUidSnapshot != null) {
- mLastPollUidSnapshot = mLastPollUidSnapshot.withoutUid(uid);
- mLastPollNetworkXtSnapshot = computeNetworkXtSnapshotFromUid(mLastPollUidSnapshot);
- }
+ mUidRecorder.removeUidLocked(uid);
+ mUidTagRecorder.removeUidLocked(uid);
// clear kernel stats associated with UID
resetKernelUidStats(uid);
-
- // since this was radical rewrite, push to disk
- writeUidStatsLocked();
- }
-
- private NetworkStatsHistory findOrCreateNetworkXtStatsLocked(NetworkIdentitySet ident) {
- return findOrCreateNetworkStatsLocked(ident, mNetworkXtStats);
- }
-
- private NetworkStatsHistory findOrCreateNetworkDevStatsLocked(NetworkIdentitySet ident) {
- return findOrCreateNetworkStatsLocked(ident, mNetworkDevStats);
- }
-
- private NetworkStatsHistory findOrCreateNetworkStatsLocked(
- NetworkIdentitySet ident, HashMap<NetworkIdentitySet, NetworkStatsHistory> source) {
- final NetworkStatsHistory existing = source.get(ident);
-
- // update when no existing, or when bucket duration changed
- final long bucketDuration = mSettings.getNetworkBucketDuration();
- NetworkStatsHistory updated = null;
- if (existing == null) {
- updated = new NetworkStatsHistory(bucketDuration, 10);
- } else if (existing.getBucketDuration() != bucketDuration) {
- updated = new NetworkStatsHistory(
- bucketDuration, estimateResizeBuckets(existing, bucketDuration));
- updated.recordEntireHistory(existing);
- }
-
- if (updated != null) {
- source.put(ident, updated);
- return updated;
- } else {
- return existing;
- }
- }
-
- private NetworkStatsHistory findOrCreateUidStatsLocked(
- NetworkIdentitySet ident, int uid, int set, int tag) {
- ensureUidStatsLoadedLocked();
-
- final UidStatsKey key = new UidStatsKey(ident, uid, set, tag);
- final NetworkStatsHistory existing = mUidStats.get(key);
-
- // update when no existing, or when bucket duration changed
- final long bucketDuration = mSettings.getUidBucketDuration();
- NetworkStatsHistory updated = null;
- if (existing == null) {
- updated = new NetworkStatsHistory(bucketDuration, 10);
- } else if (existing.getBucketDuration() != bucketDuration) {
- updated = new NetworkStatsHistory(
- bucketDuration, estimateResizeBuckets(existing, bucketDuration));
- updated.recordEntireHistory(existing);
- }
-
- if (updated != null) {
- mUidStats.put(key, updated);
- return updated;
- } else {
- return existing;
- }
- }
-
- private void readNetworkDevStatsLocked() {
- if (LOGV) Slog.v(TAG, "readNetworkDevStatsLocked()");
- readNetworkStats(mNetworkDevFile, mNetworkDevStats);
- }
-
- private void readNetworkXtStatsLocked() {
- if (LOGV) Slog.v(TAG, "readNetworkXtStatsLocked()");
- readNetworkStats(mNetworkXtFile, mNetworkXtStats);
- }
-
- private static void readNetworkStats(
- AtomicFile inputFile, HashMap<NetworkIdentitySet, NetworkStatsHistory> output) {
- // clear any existing stats and read from disk
- output.clear();
-
- DataInputStream in = null;
- try {
- in = new DataInputStream(new BufferedInputStream(inputFile.openRead()));
-
- // verify file magic header intact
- final int magic = in.readInt();
- if (magic != FILE_MAGIC) {
- throw new ProtocolException("unexpected magic: " + magic);
- }
-
- final int version = in.readInt();
- switch (version) {
- case VERSION_NETWORK_INIT: {
- // network := size *(NetworkIdentitySet NetworkStatsHistory)
- final int size = in.readInt();
- for (int i = 0; i < size; i++) {
- final NetworkIdentitySet ident = new NetworkIdentitySet(in);
- final NetworkStatsHistory history = new NetworkStatsHistory(in);
- output.put(ident, history);
- }
- break;
- }
- default: {
- throw new ProtocolException("unexpected version: " + version);
- }
- }
- } catch (FileNotFoundException e) {
- // missing stats is okay, probably first boot
- } catch (IOException e) {
- Log.wtf(TAG, "problem reading network stats", e);
- } finally {
- IoUtils.closeQuietly(in);
- }
- }
-
- private void ensureUidStatsLoadedLocked() {
- if (!mUidStatsLoaded) {
- readUidStatsLocked();
- mUidStatsLoaded = true;
- }
- }
-
- private void readUidStatsLocked() {
- if (LOGV) Slog.v(TAG, "readUidStatsLocked()");
-
- // clear any existing stats and read from disk
- mUidStats.clear();
-
- DataInputStream in = null;
- try {
- in = new DataInputStream(new BufferedInputStream(mUidFile.openRead()));
-
- // verify file magic header intact
- final int magic = in.readInt();
- if (magic != FILE_MAGIC) {
- throw new ProtocolException("unexpected magic: " + magic);
- }
-
- final int version = in.readInt();
- switch (version) {
- case VERSION_UID_INIT: {
- // uid := size *(UID NetworkStatsHistory)
-
- // drop this data version, since we don't have a good
- // mapping into NetworkIdentitySet.
- break;
- }
- case VERSION_UID_WITH_IDENT: {
- // uid := size *(NetworkIdentitySet size *(UID NetworkStatsHistory))
-
- // drop this data version, since this version only existed
- // for a short time.
- break;
- }
- case VERSION_UID_WITH_TAG:
- case VERSION_UID_WITH_SET: {
- // uid := size *(NetworkIdentitySet size *(uid set tag NetworkStatsHistory))
- final int identSize = in.readInt();
- for (int i = 0; i < identSize; i++) {
- final NetworkIdentitySet ident = new NetworkIdentitySet(in);
-
- final int size = in.readInt();
- for (int j = 0; j < size; j++) {
- final int uid = in.readInt();
- final int set = (version >= VERSION_UID_WITH_SET) ? in.readInt()
- : SET_DEFAULT;
- final int tag = in.readInt();
-
- final UidStatsKey key = new UidStatsKey(ident, uid, set, tag);
- final NetworkStatsHistory history = new NetworkStatsHistory(in);
- mUidStats.put(key, history);
- }
- }
- break;
- }
- default: {
- throw new ProtocolException("unexpected version: " + version);
- }
- }
- } catch (FileNotFoundException e) {
- // missing stats is okay, probably first boot
- } catch (IOException e) {
- Log.wtf(TAG, "problem reading uid stats", e);
- } finally {
- IoUtils.closeQuietly(in);
- }
- }
-
- private void writeNetworkDevStatsLocked() {
- if (LOGV) Slog.v(TAG, "writeNetworkDevStatsLocked()");
- writeNetworkStats(mNetworkDevStats, mNetworkDevFile);
- }
-
- private void writeNetworkXtStatsLocked() {
- if (LOGV) Slog.v(TAG, "writeNetworkXtStatsLocked()");
- writeNetworkStats(mNetworkXtStats, mNetworkXtFile);
- }
-
- private void writeNetworkStats(
- HashMap<NetworkIdentitySet, NetworkStatsHistory> input, AtomicFile outputFile) {
- // TODO: consider duplicating stats and releasing lock while writing
-
- // trim any history beyond max
- if (mTime.hasCache()) {
- final long systemCurrentTime = System.currentTimeMillis();
- final long trustedCurrentTime = mTime.currentTimeMillis();
-
- final long currentTime = Math.min(systemCurrentTime, trustedCurrentTime);
- final long maxHistory = mSettings.getNetworkMaxHistory();
-
- for (NetworkStatsHistory history : input.values()) {
- final int beforeSize = history.size();
- history.removeBucketsBefore(currentTime - maxHistory);
- final int afterSize = history.size();
-
- if (beforeSize > 24 && afterSize < beforeSize / 2) {
- // yikes, dropping more than half of significant history
- final StringBuilder builder = new StringBuilder();
- builder.append("yikes, dropping more than half of history").append('\n');
- builder.append("systemCurrentTime=").append(systemCurrentTime).append('\n');
- builder.append("trustedCurrentTime=").append(trustedCurrentTime).append('\n');
- builder.append("maxHistory=").append(maxHistory).append('\n');
- builder.append("beforeSize=").append(beforeSize).append('\n');
- builder.append("afterSize=").append(afterSize).append('\n');
- mDropBox.addText(TAG_NETSTATS_ERROR, builder.toString());
- }
- }
- }
-
- FileOutputStream fos = null;
- try {
- fos = outputFile.startWrite();
- final DataOutputStream out = new DataOutputStream(new BufferedOutputStream(fos));
-
- out.writeInt(FILE_MAGIC);
- out.writeInt(VERSION_NETWORK_INIT);
-
- out.writeInt(input.size());
- for (NetworkIdentitySet ident : input.keySet()) {
- final NetworkStatsHistory history = input.get(ident);
- ident.writeToStream(out);
- history.writeToStream(out);
- }
-
- out.flush();
- outputFile.finishWrite(fos);
- } catch (IOException e) {
- Log.wtf(TAG, "problem writing stats", e);
- if (fos != null) {
- outputFile.failWrite(fos);
- }
- }
- }
-
- private void writeUidStatsLocked() {
- if (LOGV) Slog.v(TAG, "writeUidStatsLocked()");
-
- if (!mUidStatsLoaded) {
- Slog.w(TAG, "asked to write UID stats when not loaded; skipping");
- return;
- }
-
- // TODO: consider duplicating stats and releasing lock while writing
-
- // trim any history beyond max
- if (mTime.hasCache()) {
- final long currentTime = Math.min(
- System.currentTimeMillis(), mTime.currentTimeMillis());
- final long maxUidHistory = mSettings.getUidMaxHistory();
- final long maxTagHistory = mSettings.getTagMaxHistory();
- for (UidStatsKey key : mUidStats.keySet()) {
- final NetworkStatsHistory history = mUidStats.get(key);
-
- // detailed tags are trimmed sooner than summary in TAG_NONE
- if (key.tag == TAG_NONE) {
- history.removeBucketsBefore(currentTime - maxUidHistory);
- } else {
- history.removeBucketsBefore(currentTime - maxTagHistory);
- }
- }
- }
-
- // build UidStatsKey lists grouped by ident
- final HashMap<NetworkIdentitySet, ArrayList<UidStatsKey>> keysByIdent = Maps.newHashMap();
- for (UidStatsKey key : mUidStats.keySet()) {
- ArrayList<UidStatsKey> keys = keysByIdent.get(key.ident);
- if (keys == null) {
- keys = Lists.newArrayList();
- keysByIdent.put(key.ident, keys);
- }
- keys.add(key);
- }
-
- FileOutputStream fos = null;
- try {
- fos = mUidFile.startWrite();
- final DataOutputStream out = new DataOutputStream(new BufferedOutputStream(fos));
-
- out.writeInt(FILE_MAGIC);
- out.writeInt(VERSION_UID_WITH_SET);
-
- out.writeInt(keysByIdent.size());
- for (NetworkIdentitySet ident : keysByIdent.keySet()) {
- final ArrayList<UidStatsKey> keys = keysByIdent.get(ident);
- ident.writeToStream(out);
-
- out.writeInt(keys.size());
- for (UidStatsKey key : keys) {
- final NetworkStatsHistory history = mUidStats.get(key);
- out.writeInt(key.uid);
- out.writeInt(key.set);
- out.writeInt(key.tag);
- history.writeToStream(out);
- }
- }
-
- out.flush();
- mUidFile.finishWrite(fos);
- } catch (IOException e) {
- Log.wtf(TAG, "problem writing stats", e);
- if (fos != null) {
- mUidFile.failWrite(fos);
- }
- }
}
@Override
- protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+ protected void dump(FileDescriptor fd, PrintWriter writer, String[] args) {
mContext.enforceCallingOrSelfPermission(DUMP, TAG);
final HashSet<String> argSet = new HashSet<String>();
@@ -1411,187 +861,68 @@
argSet.add(arg);
}
- final boolean fullHistory = argSet.contains("full");
+ // usage: dumpsys netstats --full --uid --tag
+ final boolean poll = argSet.contains("--poll") || argSet.contains("poll");
+ final boolean fullHistory = argSet.contains("--full") || argSet.contains("full");
+ final boolean includeUid = argSet.contains("--uid") || argSet.contains("detail");
+ final boolean includeTag = argSet.contains("--tag") || argSet.contains("detail");
+
+ final IndentingPrintWriter pw = new IndentingPrintWriter(writer, " ");
synchronized (mStatsLock) {
- // TODO: remove this testing code, since it corrupts stats
- if (argSet.contains("generate")) {
- generateRandomLocked(args);
- pw.println("Generated stub stats");
- return;
- }
-
- if (argSet.contains("poll")) {
+ if (poll) {
performPollLocked(FLAG_PERSIST_ALL | FLAG_PERSIST_FORCE);
pw.println("Forced poll");
return;
}
pw.println("Active interfaces:");
+ pw.increaseIndent();
for (String iface : mActiveIfaces.keySet()) {
final NetworkIdentitySet ident = mActiveIfaces.get(iface);
- pw.print(" iface="); pw.print(iface);
+ pw.print("iface="); pw.print(iface);
pw.print(" ident="); pw.println(ident.toString());
}
+ pw.decreaseIndent();
- pw.println("Known historical dev stats:");
- for (NetworkIdentitySet ident : mNetworkDevStats.keySet()) {
- final NetworkStatsHistory history = mNetworkDevStats.get(ident);
- pw.print(" ident="); pw.println(ident.toString());
- history.dump(" ", pw, fullHistory);
+ pw.println("Dev stats:");
+ pw.increaseIndent();
+ mDevRecorder.dumpLocked(pw, fullHistory);
+ pw.decreaseIndent();
+
+ if (includeUid) {
+ pw.println("UID stats:");
+ pw.increaseIndent();
+ mUidRecorder.dumpLocked(pw, fullHistory);
+ pw.decreaseIndent();
}
- pw.println("Known historical xt stats:");
- for (NetworkIdentitySet ident : mNetworkXtStats.keySet()) {
- final NetworkStatsHistory history = mNetworkXtStats.get(ident);
- pw.print(" ident="); pw.println(ident.toString());
- history.dump(" ", pw, fullHistory);
- }
-
- if (argSet.contains("detail")) {
- // since explicitly requested with argument, we're okay to load
- // from disk if not already in memory.
- ensureUidStatsLoadedLocked();
-
- final ArrayList<UidStatsKey> keys = Lists.newArrayList();
- keys.addAll(mUidStats.keySet());
- Collections.sort(keys);
-
- pw.println("Detailed UID stats:");
- for (UidStatsKey key : keys) {
- pw.print(" ident="); pw.print(key.ident.toString());
- pw.print(" uid="); pw.print(key.uid);
- pw.print(" set="); pw.print(NetworkStats.setToString(key.set));
- pw.print(" tag="); pw.println(NetworkStats.tagToString(key.tag));
-
- final NetworkStatsHistory history = mUidStats.get(key);
- history.dump(" ", pw, fullHistory);
- }
+ if (includeTag) {
+ pw.println("UID tag stats:");
+ pw.increaseIndent();
+ mUidTagRecorder.dumpLocked(pw, fullHistory);
+ pw.decreaseIndent();
}
}
}
+ private NetworkStats getNetworkStatsSummary() throws RemoteException {
+ return mNetworkManager.getNetworkStatsSummary();
+ }
+
/**
- * @deprecated only for temporary testing
+ * Return snapshot of current UID statistics, including any
+ * {@link TrafficStats#UID_TETHERING} and {@link #mUidOperations} values.
*/
- @Deprecated
- private void generateRandomLocked(String[] args) {
- final long totalBytes = Long.parseLong(args[1]);
- final long totalTime = Long.parseLong(args[2]);
-
- final PackageManager pm = mContext.getPackageManager();
- final ArrayList<Integer> specialUidList = Lists.newArrayList();
- for (int i = 3; i < args.length; i++) {
- try {
- specialUidList.add(pm.getApplicationInfo(args[i], 0).uid);
- } catch (NameNotFoundException e) {
- throw new RuntimeException(e);
- }
- }
+ private NetworkStats getNetworkStatsUidDetail() throws RemoteException {
+ final NetworkStats uidSnapshot = mNetworkManager.getNetworkStatsUidDetail(UID_ALL);
- final HashSet<Integer> otherUidSet = Sets.newHashSet();
- for (ApplicationInfo info : pm.getInstalledApplications(0)) {
- if (pm.checkPermission(android.Manifest.permission.INTERNET, info.packageName)
- == PackageManager.PERMISSION_GRANTED && !specialUidList.contains(info.uid)) {
- otherUidSet.add(info.uid);
- }
- }
+ // fold tethering stats and operations into uid snapshot
+ final NetworkStats tetherSnapshot = getNetworkStatsTethering();
+ uidSnapshot.combineAllValues(tetherSnapshot);
+ uidSnapshot.combineAllValues(mUidOperations);
- final ArrayList<Integer> otherUidList = new ArrayList<Integer>(otherUidSet);
-
- final long end = System.currentTimeMillis();
- final long start = end - totalTime;
-
- mNetworkDevStats.clear();
- mNetworkXtStats.clear();
- mUidStats.clear();
-
- final Random r = new Random();
- for (NetworkIdentitySet ident : mActiveIfaces.values()) {
- final NetworkStatsHistory devHistory = findOrCreateNetworkDevStatsLocked(ident);
- final NetworkStatsHistory xtHistory = findOrCreateNetworkXtStatsLocked(ident);
-
- final ArrayList<Integer> uidList = new ArrayList<Integer>();
- uidList.addAll(specialUidList);
-
- if (uidList.size() == 0) {
- Collections.shuffle(otherUidList);
- uidList.addAll(otherUidList);
- }
-
- boolean first = true;
- long remainingBytes = totalBytes;
- for (int uid : uidList) {
- final NetworkStatsHistory defaultHistory = findOrCreateUidStatsLocked(
- ident, uid, SET_DEFAULT, TAG_NONE);
- final NetworkStatsHistory foregroundHistory = findOrCreateUidStatsLocked(
- ident, uid, SET_FOREGROUND, TAG_NONE);
-
- final long uidBytes = totalBytes / uidList.size();
-
- final float fractionDefault = r.nextFloat();
- final long defaultBytes = (long) (uidBytes * fractionDefault);
- final long foregroundBytes = (long) (uidBytes * (1 - fractionDefault));
-
- defaultHistory.generateRandom(start, end, defaultBytes);
- foregroundHistory.generateRandom(start, end, foregroundBytes);
-
- if (first) {
- final long bumpTime = (start + end) / 2;
- defaultHistory.recordData(
- bumpTime, bumpTime + DAY_IN_MILLIS, 200 * MB_IN_BYTES, 0);
- first = false;
- }
-
- devHistory.recordEntireHistory(defaultHistory);
- devHistory.recordEntireHistory(foregroundHistory);
- xtHistory.recordEntireHistory(defaultHistory);
- xtHistory.recordEntireHistory(foregroundHistory);
- }
- }
- }
-
- private StatsObserver mStatsObserver = new StatsObserver();
-
- private class StatsObserver implements NonMonotonicObserver {
- private String mCurrentType;
-
- public void setCurrentType(String type) {
- mCurrentType = type;
- }
-
- /** {@inheritDoc} */
- public void foundNonMonotonic(
- NetworkStats left, int leftIndex, NetworkStats right, int rightIndex) {
- Log.w(TAG, "found non-monotonic values; saving to dropbox");
-
- // record error for debugging
- final StringBuilder builder = new StringBuilder();
- builder.append("found non-monotonic " + mCurrentType + " values at left[" + leftIndex
- + "] - right[" + rightIndex + "]\n");
- builder.append("left=").append(left).append('\n');
- builder.append("right=").append(right).append('\n');
- mDropBox.addText(TAG_NETSTATS_ERROR, builder.toString());
- }
- }
-
- /**
- * Return the delta between two {@link NetworkStats} snapshots, where {@code
- * before} can be {@code null}.
- */
- private NetworkStats computeStatsDelta(
- NetworkStats before, NetworkStats current, boolean collectStale, String type) {
- if (before != null) {
- mStatsObserver.setCurrentType(type);
- return NetworkStats.subtract(current, before, mStatsObserver);
- } else if (collectStale) {
- // caller is okay collecting stale stats for first call.
- return current;
- } else {
- // this is first snapshot; to prevent from double-counting we only
- // observe traffic occuring between known snapshots.
- return new NetworkStats(0L, 10);
- }
+ return uidSnapshot;
}
/**
@@ -1608,35 +939,6 @@
}
}
- private static NetworkStats computeNetworkXtSnapshotFromUid(NetworkStats uidSnapshot) {
- return uidSnapshot.groupedByIface();
- }
-
- private int estimateNetworkBuckets() {
- return (int) (mSettings.getNetworkMaxHistory() / mSettings.getNetworkBucketDuration());
- }
-
- private int estimateUidBuckets() {
- return (int) (mSettings.getUidMaxHistory() / mSettings.getUidBucketDuration());
- }
-
- private static int estimateResizeBuckets(NetworkStatsHistory existing, long newBucketDuration) {
- return (int) (existing.size() * existing.getBucketDuration() / newBucketDuration);
- }
-
- /**
- * Test if given {@link NetworkTemplate} matches any {@link NetworkIdentity}
- * in the given {@link NetworkIdentitySet}.
- */
- private static boolean templateMatches(NetworkTemplate template, NetworkIdentitySet identSet) {
- for (NetworkIdentity ident : identSet) {
- if (template.matches(ident)) {
- return true;
- }
- }
- return false;
- }
-
private Handler.Callback mHandlerCallback = new Handler.Callback() {
/** {@inheritDoc} */
public boolean handleMessage(Message msg) {
@@ -1650,6 +952,10 @@
updateIfaces();
return true;
}
+ case MSG_REGISTER_GLOBAL_ALERT: {
+ registerGlobalAlert();
+ return true;
+ }
default: {
return false;
}
@@ -1672,40 +978,22 @@
}
}
- /**
- * Key uniquely identifying a {@link NetworkStatsHistory} for a UID.
- */
- private static class UidStatsKey implements Comparable<UidStatsKey> {
- public final NetworkIdentitySet ident;
- public final int uid;
- public final int set;
- public final int tag;
-
- public UidStatsKey(NetworkIdentitySet ident, int uid, int set, int tag) {
- this.ident = ident;
- this.uid = uid;
- this.set = set;
- this.tag = tag;
- }
-
- @Override
- public int hashCode() {
- return Objects.hashCode(ident, uid, set, tag);
- }
-
- @Override
- public boolean equals(Object obj) {
- if (obj instanceof UidStatsKey) {
- final UidStatsKey key = (UidStatsKey) obj;
- return Objects.equal(ident, key.ident) && uid == key.uid && set == key.set
- && tag == key.tag;
- }
- return false;
- }
-
+ private class DropBoxNonMonotonicObserver implements NonMonotonicObserver<String> {
/** {@inheritDoc} */
- public int compareTo(UidStatsKey another) {
- return Integer.compare(uid, another.uid);
+ public void foundNonMonotonic(NetworkStats left, int leftIndex, NetworkStats right,
+ int rightIndex, String cookie) {
+ Log.w(TAG, "found non-monotonic values; saving to dropbox");
+
+ // record error for debugging
+ final StringBuilder builder = new StringBuilder();
+ builder.append("found non-monotonic " + cookie + " values at left[" + leftIndex
+ + "] - right[" + rightIndex + "]\n");
+ builder.append("left=").append(left).append('\n');
+ builder.append("right=").append(right).append('\n');
+
+ final DropBoxManager dropBox = (DropBoxManager) mContext.getSystemService(
+ Context.DROPBOX_SERVICE);
+ dropBox.addText(TAG_NETSTATS_ERROR, builder.toString());
}
}
@@ -1731,26 +1019,35 @@
public long getPollInterval() {
return getSecureLong(NETSTATS_POLL_INTERVAL, 30 * MINUTE_IN_MILLIS);
}
- public long getPersistThreshold() {
- return getSecureLong(NETSTATS_PERSIST_THRESHOLD, 2 * MB_IN_BYTES);
- }
- public long getNetworkBucketDuration() {
- return getSecureLong(NETSTATS_NETWORK_BUCKET_DURATION, HOUR_IN_MILLIS);
- }
- public long getNetworkMaxHistory() {
- return getSecureLong(NETSTATS_NETWORK_MAX_HISTORY, 90 * DAY_IN_MILLIS);
- }
- public long getUidBucketDuration() {
- return getSecureLong(NETSTATS_UID_BUCKET_DURATION, 2 * HOUR_IN_MILLIS);
- }
- public long getUidMaxHistory() {
- return getSecureLong(NETSTATS_UID_MAX_HISTORY, 90 * DAY_IN_MILLIS);
- }
- public long getTagMaxHistory() {
- return getSecureLong(NETSTATS_TAG_MAX_HISTORY, 30 * DAY_IN_MILLIS);
- }
public long getTimeCacheMaxAge() {
- return DAY_IN_MILLIS;
+ return getSecureLong(NETSTATS_TIME_CACHE_MAX_AGE, DAY_IN_MILLIS);
+ }
+ public long getGlobalAlertBytes() {
+ return getSecureLong(NETSTATS_GLOBAL_ALERT_BYTES, 2 * MB_IN_BYTES);
+ }
+ public boolean getSampleEnabled() {
+ return getSecureBoolean(NETSTATS_SAMPLE_ENABLED, true);
+ }
+
+ public Config getDevConfig() {
+ return new Config(getSecureLong(NETSTATS_DEV_BUCKET_DURATION, HOUR_IN_MILLIS),
+ getSecureLong(NETSTATS_DEV_PERSIST_BYTES, 2 * MB_IN_BYTES),
+ getSecureLong(NETSTATS_DEV_ROTATE_AGE, 15 * DAY_IN_MILLIS),
+ getSecureLong(NETSTATS_DEV_DELETE_AGE, 90 * DAY_IN_MILLIS));
+ }
+
+ public Config getUidConfig() {
+ return new Config(getSecureLong(NETSTATS_UID_BUCKET_DURATION, 2 * HOUR_IN_MILLIS),
+ getSecureLong(NETSTATS_UID_PERSIST_BYTES, 2 * MB_IN_BYTES),
+ getSecureLong(NETSTATS_UID_ROTATE_AGE, 15 * DAY_IN_MILLIS),
+ getSecureLong(NETSTATS_UID_DELETE_AGE, 90 * DAY_IN_MILLIS));
+ }
+
+ public Config getUidTagConfig() {
+ return new Config(getSecureLong(NETSTATS_UID_BUCKET_DURATION, 2 * HOUR_IN_MILLIS),
+ getSecureLong(NETSTATS_UID_PERSIST_BYTES, 2 * MB_IN_BYTES),
+ getSecureLong(NETSTATS_UID_ROTATE_AGE, 5 * DAY_IN_MILLIS),
+ getSecureLong(NETSTATS_UID_DELETE_AGE, 15 * DAY_IN_MILLIS));
}
}
}
diff --git a/services/java/com/android/server/pm/PackageManagerService.java b/services/java/com/android/server/pm/PackageManagerService.java
index 6b61c47..090ca64 100644
--- a/services/java/com/android/server/pm/PackageManagerService.java
+++ b/services/java/com/android/server/pm/PackageManagerService.java
@@ -620,11 +620,11 @@
packages = new String[size];
components = new ArrayList[size];
uids = new int[size];
- Iterator<HashMap.Entry<String, ArrayList<String>>>
+ Iterator<Map.Entry<String, ArrayList<String>>>
it = mPendingBroadcasts.entrySet().iterator();
int i = 0;
while (it.hasNext() && i < size) {
- HashMap.Entry<String, ArrayList<String>> ent = it.next();
+ Map.Entry<String, ArrayList<String>> ent = it.next();
packages[i] = ent.getKey();
components[i] = ent.getValue();
PackageSetting ps = mSettings.mPackages.get(ent.getKey());
diff --git a/services/java/com/android/server/pm/Settings.java b/services/java/com/android/server/pm/Settings.java
index 32aa7a4..3616aa2 100644
--- a/services/java/com/android/server/pm/Settings.java
+++ b/services/java/com/android/server/pm/Settings.java
@@ -62,6 +62,7 @@
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
+import java.util.Map;
import libcore.io.IoUtils;
@@ -929,7 +930,7 @@
}
if (mRenamedPackages.size() > 0) {
- for (HashMap.Entry<String, String> e : mRenamedPackages.entrySet()) {
+ for (Map.Entry<String, String> e : mRenamedPackages.entrySet()) {
serializer.startTag(null, "renamed-package");
serializer.attribute(null, "new", e.getKey());
serializer.attribute(null, "old", e.getValue());
@@ -2144,7 +2145,7 @@
printedSomething = false;
if (mRenamedPackages.size() > 0) {
- for (final HashMap.Entry<String, String> e : mRenamedPackages.entrySet()) {
+ for (final Map.Entry<String, String> e : mRenamedPackages.entrySet()) {
if (packageName != null && !packageName.equals(e.getKey())
&& !packageName.equals(e.getValue())) {
continue;
@@ -2258,4 +2259,4 @@
pw.println("Settings parse messages:");
pw.print(mReadMessages.toString());
}
-}
\ No newline at end of file
+}
diff --git a/services/java/com/android/server/wm/ScreenRotationAnimation.java b/services/java/com/android/server/wm/ScreenRotationAnimation.java
index 8fc9a70..55fb038 100644
--- a/services/java/com/android/server/wm/ScreenRotationAnimation.java
+++ b/services/java/com/android/server/wm/ScreenRotationAnimation.java
@@ -17,13 +17,8 @@
package com.android.server.wm;
import android.content.Context;
-import android.graphics.Bitmap;
-import android.graphics.Canvas;
import android.graphics.Matrix;
-import android.graphics.Paint;
import android.graphics.PixelFormat;
-import android.graphics.PorterDuff;
-import android.graphics.PorterDuffXfermode;
import android.graphics.Rect;
import android.util.Slog;
import android.view.Surface;
@@ -34,7 +29,8 @@
class ScreenRotationAnimation {
static final String TAG = "ScreenRotationAnimation";
- static final boolean DEBUG = false;
+ static final boolean DEBUG_STATE = false;
+ static final boolean DEBUG_TRANSFORMS = false;
static final int FREEZE_LAYER = WindowManagerService.TYPE_LAYER_MULTIPLIER * 200;
@@ -49,11 +45,51 @@
int mOriginalWidth, mOriginalHeight;
int mCurRotation;
- Animation mExitAnimation;
+ // For all animations, "exit" is for the UI elements that are going
+ // away (that is the snapshot of the old screen), and "enter" is for
+ // the new UI elements that are appearing (that is the active windows
+ // in their final orientation).
+
+ // The starting animation for the exiting and entering elements. This
+ // animation applies a transformation while the rotation is in progress.
+ // It is started immediately, before the new entering UI is ready.
+ Animation mStartExitAnimation;
+ final Transformation mStartExitTransformation = new Transformation();
+ Animation mStartEnterAnimation;
+ final Transformation mStartEnterTransformation = new Transformation();
+
+ // The finishing animation for the exiting and entering elements. This
+ // animation needs to undo the transformation of the starting animation.
+ // It starts running once the new rotation UI elements are ready to be
+ // displayed.
+ Animation mFinishExitAnimation;
+ final Transformation mFinishExitTransformation = new Transformation();
+ Animation mFinishEnterAnimation;
+ final Transformation mFinishEnterTransformation = new Transformation();
+
+ // The current active animation to move from the old to the new rotated
+ // state. Which animation is run here will depend on the old and new
+ // rotations.
+ Animation mRotateExitAnimation;
+ final Transformation mRotateExitTransformation = new Transformation();
+ Animation mRotateEnterAnimation;
+ final Transformation mRotateEnterTransformation = new Transformation();
+
+ // A previously running rotate animation. This will be used if we need
+ // to switch to a new rotation before finishing the previous one.
+ Animation mLastRotateExitAnimation;
+ final Transformation mLastRotateExitTransformation = new Transformation();
+ Animation mLastRotateEnterAnimation;
+ final Transformation mLastRotateEnterTransformation = new Transformation();
+
+ // Complete transformations being applied.
final Transformation mExitTransformation = new Transformation();
- Animation mEnterAnimation;
final Transformation mEnterTransformation = new Transformation();
+
boolean mStarted;
+ boolean mAnimRunning;
+ boolean mFinishAnimReady;
+ long mFinishAnimStartTime;
final Matrix mSnapshotInitialMatrix = new Matrix();
final Matrix mSnapshotFinalMatrix = new Matrix();
@@ -133,7 +169,7 @@
mTmpFloats[Matrix.MSCALE_X], mTmpFloats[Matrix.MSKEW_Y],
mTmpFloats[Matrix.MSKEW_X], mTmpFloats[Matrix.MSCALE_Y]);
mSurface.setAlpha(alpha);
- if (DEBUG) {
+ if (DEBUG_TRANSFORMS) {
float[] srcPnts = new float[] { 0, 0, mWidth, mHeight };
float[] dstPnts = new float[4];
matrix.mapPoints(dstPnts, srcPnts);
@@ -167,7 +203,7 @@
}
// Must be called while in a transaction.
- public void setRotation(int rotation) {
+ private void setRotation(int rotation) {
mCurRotation = rotation;
// Compute the transformation matrix that must be applied
@@ -176,46 +212,78 @@
int delta = deltaRotation(rotation, mSnapshotRotation);
createRotationMatrix(delta, mWidth, mHeight, mSnapshotInitialMatrix);
- if (DEBUG) Slog.v(TAG, "**** ROTATION: " + delta);
+ if (DEBUG_STATE) Slog.v(TAG, "**** ROTATION: " + delta);
setSnapshotTransform(mSnapshotInitialMatrix, 1.0f);
}
+ // Must be called while in a transaction.
+ public boolean setRotation(int rotation, SurfaceSession session,
+ long maxAnimationDuration, float animationScale, int finalWidth, int finalHeight) {
+ setRotation(rotation);
+ return startAnimation(session, maxAnimationDuration, animationScale,
+ finalWidth, finalHeight, false);
+ }
+
/**
* Returns true if animating.
*/
- public boolean dismiss(SurfaceSession session, long maxAnimationDuration,
- float animationScale, int finalWidth, int finalHeight) {
+ private boolean startAnimation(SurfaceSession session, long maxAnimationDuration,
+ float animationScale, int finalWidth, int finalHeight, boolean dismissing) {
if (mSurface == null) {
// Can't do animation.
return false;
}
+ if (mStarted) {
+ return true;
+ }
+
+ mStarted = true;
+
+ boolean firstStart = false;
// Figure out how the screen has moved from the original rotation.
int delta = deltaRotation(mCurRotation, mOriginalRotation);
+ if (mFinishExitAnimation == null && (!dismissing || delta != Surface.ROTATION_0)) {
+ if (DEBUG_STATE) Slog.v(TAG, "Creating start and finish animations");
+ firstStart = true;
+ mStartExitAnimation = AnimationUtils.loadAnimation(mContext,
+ com.android.internal.R.anim.screen_rotate_start_exit);
+ mStartEnterAnimation = AnimationUtils.loadAnimation(mContext,
+ com.android.internal.R.anim.screen_rotate_start_enter);
+ mFinishExitAnimation = AnimationUtils.loadAnimation(mContext,
+ com.android.internal.R.anim.screen_rotate_finish_exit);
+ mFinishEnterAnimation = AnimationUtils.loadAnimation(mContext,
+ com.android.internal.R.anim.screen_rotate_finish_enter);
+ }
+
+ if (DEBUG_STATE) Slog.v(TAG, "Rotation delta: " + delta + " finalWidth="
+ + finalWidth + " finalHeight=" + finalHeight
+ + " origWidth=" + mOriginalWidth + " origHeight=" + mOriginalHeight);
+
switch (delta) {
case Surface.ROTATION_0:
- mExitAnimation = AnimationUtils.loadAnimation(mContext,
+ mRotateExitAnimation = AnimationUtils.loadAnimation(mContext,
com.android.internal.R.anim.screen_rotate_0_exit);
- mEnterAnimation = AnimationUtils.loadAnimation(mContext,
+ mRotateEnterAnimation = AnimationUtils.loadAnimation(mContext,
com.android.internal.R.anim.screen_rotate_0_enter);
break;
case Surface.ROTATION_90:
- mExitAnimation = AnimationUtils.loadAnimation(mContext,
+ mRotateExitAnimation = AnimationUtils.loadAnimation(mContext,
com.android.internal.R.anim.screen_rotate_plus_90_exit);
- mEnterAnimation = AnimationUtils.loadAnimation(mContext,
+ mRotateEnterAnimation = AnimationUtils.loadAnimation(mContext,
com.android.internal.R.anim.screen_rotate_plus_90_enter);
break;
case Surface.ROTATION_180:
- mExitAnimation = AnimationUtils.loadAnimation(mContext,
+ mRotateExitAnimation = AnimationUtils.loadAnimation(mContext,
com.android.internal.R.anim.screen_rotate_180_exit);
- mEnterAnimation = AnimationUtils.loadAnimation(mContext,
+ mRotateEnterAnimation = AnimationUtils.loadAnimation(mContext,
com.android.internal.R.anim.screen_rotate_180_enter);
break;
case Surface.ROTATION_270:
- mExitAnimation = AnimationUtils.loadAnimation(mContext,
+ mRotateExitAnimation = AnimationUtils.loadAnimation(mContext,
com.android.internal.R.anim.screen_rotate_minus_90_exit);
- mEnterAnimation = AnimationUtils.loadAnimation(mContext,
+ mRotateEnterAnimation = AnimationUtils.loadAnimation(mContext,
com.android.internal.R.anim.screen_rotate_minus_90_enter);
break;
}
@@ -224,35 +292,85 @@
// means to allow supplying the last and next size. In this definition
// "%p" is the original (let's call it "previous") size, and "%" is the
// screen's current/new size.
- mEnterAnimation.initialize(finalWidth, finalHeight, mOriginalWidth, mOriginalHeight);
- mExitAnimation.initialize(finalWidth, finalHeight, mOriginalWidth, mOriginalHeight);
- mStarted = false;
+ if (firstStart) {
+ if (DEBUG_STATE) Slog.v(TAG, "Initializing start and finish animations");
+ mStartEnterAnimation.initialize(finalWidth, finalHeight,
+ mOriginalWidth, mOriginalHeight);
+ mStartExitAnimation.initialize(finalWidth, finalHeight,
+ mOriginalWidth, mOriginalHeight);
+ mFinishEnterAnimation.initialize(finalWidth, finalHeight,
+ mOriginalWidth, mOriginalHeight);
+ mFinishExitAnimation.initialize(finalWidth, finalHeight,
+ mOriginalWidth, mOriginalHeight);
+ }
+ mRotateEnterAnimation.initialize(finalWidth, finalHeight, mOriginalWidth, mOriginalHeight);
+ mRotateExitAnimation.initialize(finalWidth, finalHeight, mOriginalWidth, mOriginalHeight);
+ mAnimRunning = false;
+ mFinishAnimReady = false;
+ mFinishAnimStartTime = -1;
- mExitAnimation.restrictDuration(maxAnimationDuration);
- mExitAnimation.scaleCurrentDuration(animationScale);
- mEnterAnimation.restrictDuration(maxAnimationDuration);
- mEnterAnimation.scaleCurrentDuration(animationScale);
+ if (firstStart) {
+ mStartExitAnimation.restrictDuration(maxAnimationDuration);
+ mStartExitAnimation.scaleCurrentDuration(animationScale);
+ mStartEnterAnimation.restrictDuration(maxAnimationDuration);
+ mStartEnterAnimation.scaleCurrentDuration(animationScale);
+ mFinishExitAnimation.restrictDuration(maxAnimationDuration);
+ mFinishExitAnimation.scaleCurrentDuration(animationScale);
+ mFinishEnterAnimation.restrictDuration(maxAnimationDuration);
+ mFinishEnterAnimation.scaleCurrentDuration(animationScale);
+ }
+ mRotateExitAnimation.restrictDuration(maxAnimationDuration);
+ mRotateExitAnimation.scaleCurrentDuration(animationScale);
+ mRotateEnterAnimation.restrictDuration(maxAnimationDuration);
+ mRotateEnterAnimation.scaleCurrentDuration(animationScale);
- if (WindowManagerService.SHOW_LIGHT_TRANSACTIONS) Slog.i(WindowManagerService.TAG,
- ">>> OPEN TRANSACTION ScreenRotationAnimation.dismiss");
- Surface.openTransaction();
+ if (mBlackFrame == null) {
+ if (WindowManagerService.SHOW_LIGHT_TRANSACTIONS || DEBUG_STATE) Slog.i(
+ WindowManagerService.TAG,
+ ">>> OPEN TRANSACTION ScreenRotationAnimation.startAnimation");
+ Surface.openTransaction();
- try {
- Rect outer = new Rect(-finalWidth, -finalHeight, finalWidth * 2, finalHeight * 2);
- Rect inner = new Rect(0, 0, finalWidth, finalHeight);
- mBlackFrame = new BlackFrame(session, outer, inner, FREEZE_LAYER);
- } catch (Surface.OutOfResourcesException e) {
- Slog.w(TAG, "Unable to allocate black surface", e);
- } finally {
- Surface.closeTransaction();
- if (WindowManagerService.SHOW_LIGHT_TRANSACTIONS) Slog.i(WindowManagerService.TAG,
- "<<< CLOSE TRANSACTION ScreenRotationAnimation.dismiss");
+ try {
+ Rect outer = new Rect(-finalWidth*1, -finalHeight*1, finalWidth*2, finalHeight*2);
+ Rect inner = new Rect(0, 0, finalWidth, finalHeight);
+ mBlackFrame = new BlackFrame(session, outer, inner, FREEZE_LAYER);
+ } catch (Surface.OutOfResourcesException e) {
+ Slog.w(TAG, "Unable to allocate black surface", e);
+ } finally {
+ Surface.closeTransaction();
+ if (WindowManagerService.SHOW_LIGHT_TRANSACTIONS || DEBUG_STATE) Slog.i(
+ WindowManagerService.TAG,
+ "<<< CLOSE TRANSACTION ScreenRotationAnimation.startAnimation");
+ }
}
return true;
}
+ /**
+ * Returns true if animating.
+ */
+ public boolean dismiss(SurfaceSession session, long maxAnimationDuration,
+ float animationScale, int finalWidth, int finalHeight) {
+ if (DEBUG_STATE) Slog.v(TAG, "Dismiss!");
+ if (mSurface == null) {
+ // Can't do animation.
+ return false;
+ }
+ if (!mStarted) {
+ startAnimation(session, maxAnimationDuration, animationScale, finalWidth, finalHeight,
+ true);
+ }
+ if (!mStarted) {
+ return false;
+ }
+ if (DEBUG_STATE) Slog.v(TAG, "Setting mFinishAnimReady = true");
+ mFinishAnimReady = true;
+ return true;
+ }
+
public void kill() {
+ if (DEBUG_STATE) Slog.v(TAG, "Kill!");
if (mSurface != null) {
if (WindowManagerService.SHOW_TRANSACTIONS ||
WindowManagerService.SHOW_SURFACE_ALLOC) Slog.i(WindowManagerService.TAG,
@@ -262,74 +380,198 @@
}
if (mBlackFrame != null) {
mBlackFrame.kill();
+ mBlackFrame = null;
}
- if (mExitAnimation != null) {
- mExitAnimation.cancel();
- mExitAnimation = null;
+ if (mStartExitAnimation != null) {
+ mStartExitAnimation.cancel();
+ mStartExitAnimation = null;
}
- if (mEnterAnimation != null) {
- mEnterAnimation.cancel();
- mEnterAnimation = null;
+ if (mStartEnterAnimation != null) {
+ mStartEnterAnimation.cancel();
+ mStartEnterAnimation = null;
+ }
+ if (mFinishExitAnimation != null) {
+ mFinishExitAnimation.cancel();
+ mFinishExitAnimation = null;
+ }
+ if (mStartEnterAnimation != null) {
+ mStartEnterAnimation.cancel();
+ mStartEnterAnimation = null;
+ }
+ if (mRotateExitAnimation != null) {
+ mRotateExitAnimation.cancel();
+ mRotateExitAnimation = null;
+ }
+ if (mRotateEnterAnimation != null) {
+ mRotateEnterAnimation.cancel();
+ mRotateEnterAnimation = null;
}
}
public boolean isAnimating() {
- return mEnterAnimation != null || mExitAnimation != null;
+ return mStartEnterAnimation != null || mStartExitAnimation != null
+ && mFinishEnterAnimation != null || mFinishExitAnimation != null
+ && mRotateEnterAnimation != null || mRotateExitAnimation != null;
}
public boolean stepAnimation(long now) {
- if (mEnterAnimation == null && mExitAnimation == null) {
+ if (!isAnimating()) {
+ if (DEBUG_STATE) Slog.v(TAG, "Step: no animations running");
return false;
}
- if (!mStarted) {
- if (mEnterAnimation != null) {
- mEnterAnimation.setStartTime(now);
+ if (!mAnimRunning) {
+ if (DEBUG_STATE) Slog.v(TAG, "Step: starting start, finish, rotate");
+ if (mStartEnterAnimation != null) {
+ mStartEnterAnimation.setStartTime(now);
}
- if (mExitAnimation != null) {
- mExitAnimation.setStartTime(now);
+ if (mStartExitAnimation != null) {
+ mStartExitAnimation.setStartTime(now);
}
- mStarted = true;
+ if (mFinishEnterAnimation != null) {
+ mFinishEnterAnimation.setStartTime(0);
+ }
+ if (mFinishExitAnimation != null) {
+ mFinishExitAnimation.setStartTime(0);
+ }
+ if (mRotateEnterAnimation != null) {
+ mRotateEnterAnimation.setStartTime(now);
+ }
+ if (mRotateExitAnimation != null) {
+ mRotateExitAnimation.setStartTime(now);
+ }
+ mAnimRunning = true;
}
- mExitTransformation.clear();
- boolean moreExit = false;
- if (mExitAnimation != null) {
- moreExit = mExitAnimation.getTransformation(now, mExitTransformation);
- if (DEBUG) Slog.v(TAG, "Stepped exit: " + mExitTransformation);
- if (!moreExit) {
- if (DEBUG) Slog.v(TAG, "Exit animation done!");
- mExitAnimation.cancel();
- mExitAnimation = null;
- mExitTransformation.clear();
- if (mSurface != null) {
- mSurface.hide();
- }
+ if (mFinishAnimReady && mFinishAnimStartTime < 0) {
+ if (DEBUG_STATE) Slog.v(TAG, "Step: finish anim now ready");
+ mFinishAnimStartTime = now;
+ }
+
+ // If the start animation is no longer running, we want to keep its
+ // transformation intact until the finish animation also completes.
+
+ boolean moreStartExit = false;
+ if (mStartExitAnimation != null) {
+ mStartExitTransformation.clear();
+ moreStartExit = mStartExitAnimation.getTransformation(now, mStartExitTransformation);
+ if (DEBUG_TRANSFORMS) Slog.v(TAG, "Stepped start exit: " + mStartExitTransformation);
+ if (!moreStartExit) {
+ if (DEBUG_STATE) Slog.v(TAG, "Start exit animation done!");
+ mStartExitAnimation.cancel();
+ mStartExitAnimation = null;
}
}
- mEnterTransformation.clear();
- boolean moreEnter = false;
- if (mEnterAnimation != null) {
- moreEnter = mEnterAnimation.getTransformation(now, mEnterTransformation);
- if (!moreEnter) {
- mEnterAnimation.cancel();
- mEnterAnimation = null;
- mEnterTransformation.clear();
- if (mBlackFrame != null) {
- mBlackFrame.hide();
- }
- } else {
- if (mBlackFrame != null) {
- mBlackFrame.setMatrix(mEnterTransformation.getMatrix());
- }
+ boolean moreStartEnter = false;
+ if (mStartEnterAnimation != null) {
+ mStartEnterTransformation.clear();
+ moreStartEnter = mStartEnterAnimation.getTransformation(now, mStartEnterTransformation);
+ if (DEBUG_TRANSFORMS) Slog.v(TAG, "Stepped start enter: " + mStartEnterTransformation);
+ if (!moreStartEnter) {
+ if (DEBUG_STATE) Slog.v(TAG, "Start enter animation done!");
+ mStartEnterAnimation.cancel();
+ mStartEnterAnimation = null;
+ }
+ }
+
+ long finishNow = mFinishAnimReady ? (now - mFinishAnimStartTime) : 0;
+ if (DEBUG_STATE) Slog.v(TAG, "Step: finishNow=" + finishNow);
+
+ mFinishExitTransformation.clear();
+ boolean moreFinishExit = false;
+ if (mFinishExitAnimation != null) {
+ moreFinishExit = mFinishExitAnimation.getTransformation(finishNow, mFinishExitTransformation);
+ if (DEBUG_TRANSFORMS) Slog.v(TAG, "Stepped finish exit: " + mFinishExitTransformation);
+ if (!moreStartExit && !moreFinishExit) {
+ if (DEBUG_STATE) Slog.v(TAG, "Finish exit animation done, clearing start/finish anims!");
+ mStartExitTransformation.clear();
+ mFinishExitAnimation.cancel();
+ mFinishExitAnimation = null;
+ mFinishExitTransformation.clear();
+ }
+ }
+
+ mFinishEnterTransformation.clear();
+ boolean moreFinishEnter = false;
+ if (mFinishEnterAnimation != null) {
+ moreFinishEnter = mFinishEnterAnimation.getTransformation(finishNow, mFinishEnterTransformation);
+ if (DEBUG_TRANSFORMS) Slog.v(TAG, "Stepped finish enter: " + mFinishEnterTransformation);
+ if (!moreStartEnter && !moreFinishEnter) {
+ if (DEBUG_STATE) Slog.v(TAG, "Finish enter animation done, clearing start/finish anims!");
+ mStartEnterTransformation.clear();
+ mFinishEnterAnimation.cancel();
+ mFinishEnterAnimation = null;
+ mFinishEnterTransformation.clear();
+ }
+ }
+
+ mRotateExitTransformation.clear();
+ boolean moreRotateExit = false;
+ if (mRotateExitAnimation != null) {
+ moreRotateExit = mRotateExitAnimation.getTransformation(now, mRotateExitTransformation);
+ if (DEBUG_TRANSFORMS) Slog.v(TAG, "Stepped rotate exit: " + mRotateExitTransformation);
+ }
+
+ if (!moreFinishExit && !moreRotateExit) {
+ if (DEBUG_STATE) Slog.v(TAG, "Rotate exit animation done!");
+ mRotateExitAnimation.cancel();
+ mRotateExitAnimation = null;
+ mRotateExitTransformation.clear();
+ }
+
+ mRotateEnterTransformation.clear();
+ boolean moreRotateEnter = false;
+ if (mRotateEnterAnimation != null) {
+ moreRotateEnter = mRotateEnterAnimation.getTransformation(now, mRotateEnterTransformation);
+ if (DEBUG_TRANSFORMS) Slog.v(TAG, "Stepped rotate enter: " + mRotateEnterTransformation);
+ }
+
+ if (!moreFinishEnter && !moreRotateEnter) {
+ if (DEBUG_STATE) Slog.v(TAG, "Rotate enter animation done!");
+ mRotateEnterAnimation.cancel();
+ mRotateEnterAnimation = null;
+ mRotateEnterTransformation.clear();
+ }
+
+ mExitTransformation.set(mRotateExitTransformation);
+ mExitTransformation.compose(mStartExitTransformation);
+ mExitTransformation.compose(mFinishExitTransformation);
+
+ mEnterTransformation.set(mRotateEnterTransformation);
+ mEnterTransformation.compose(mStartEnterTransformation);
+ mEnterTransformation.compose(mFinishEnterTransformation);
+
+ if (DEBUG_TRANSFORMS) Slog.v(TAG, "Final exit: " + mExitTransformation);
+ if (DEBUG_TRANSFORMS) Slog.v(TAG, "Final enter: " + mEnterTransformation);
+
+ if (!moreStartExit && !moreFinishExit && !moreRotateExit) {
+ if (mSurface != null) {
+ if (DEBUG_STATE) Slog.v(TAG, "Exit animations done, hiding screenshot surface");
+ mSurface.hide();
+ }
+ }
+
+ if (!moreStartEnter && !moreFinishEnter && !moreRotateEnter) {
+ if (mBlackFrame != null) {
+ if (DEBUG_STATE) Slog.v(TAG, "Enter animations done, hiding black frame");
+ mBlackFrame.hide();
+ }
+ } else {
+ if (mBlackFrame != null) {
+ mBlackFrame.setMatrix(mEnterTransformation.getMatrix());
}
}
mSnapshotFinalMatrix.setConcat(mExitTransformation.getMatrix(), mSnapshotInitialMatrix);
setSnapshotTransform(mSnapshotFinalMatrix, mExitTransformation.getAlpha());
- return moreEnter || moreExit;
+ final boolean more = moreStartEnter || moreStartExit || moreFinishEnter || moreFinishExit
+ || moreRotateEnter || moreRotateExit || !mFinishAnimReady;
+
+ if (DEBUG_STATE) Slog.v(TAG, "Step: more=" + more);
+
+ return more;
}
public Transformation getEnterTransformation() {
diff --git a/services/java/com/android/server/wm/WindowManagerService.java b/services/java/com/android/server/wm/WindowManagerService.java
index 6ff0100..620d74c 100644
--- a/services/java/com/android/server/wm/WindowManagerService.java
+++ b/services/java/com/android/server/wm/WindowManagerService.java
@@ -95,6 +95,7 @@
import android.util.Slog;
import android.util.SparseIntArray;
import android.util.TypedValue;
+import android.view.Choreographer;
import android.view.Display;
import android.view.Gravity;
import android.view.IApplicationToken;
@@ -141,7 +142,8 @@
/** {@hide} */
public class WindowManagerService extends IWindowManager.Stub
- implements Watchdog.Monitor, WindowManagerPolicy.WindowManagerFuncs {
+ implements Watchdog.Monitor, WindowManagerPolicy.WindowManagerFuncs,
+ Choreographer.OnAnimateListener {
static final String TAG = "WindowManager";
static final boolean DEBUG = false;
static final boolean DEBUG_ADD_REMOVE = false;
@@ -456,7 +458,7 @@
int mDeferredRotationPauseCount;
boolean mLayoutNeeded = true;
- boolean mAnimationPending = false;
+ boolean mTraversalScheduled = false;
boolean mDisplayFrozen = false;
boolean mWaitingForConfig = false;
boolean mWindowsFreezingScreen = false;
@@ -503,7 +505,9 @@
final DisplayMetrics mTmpDisplayMetrics = new DisplayMetrics();
final DisplayMetrics mCompatDisplayMetrics = new DisplayMetrics();
- H mH = new H();
+ final H mH = new H();
+
+ final Choreographer mChoreographer = Choreographer.getInstance();
WindowState mCurrentFocus = null;
WindowState mLastFocus = null;
@@ -559,6 +563,7 @@
float mWindowAnimationScale = 1.0f;
float mTransitionAnimationScale = 1.0f;
+ float mAnimatorDurationScale = 1.0f;
final InputManager mInputManager;
@@ -691,6 +696,7 @@
Looper.prepare();
WindowManagerService s = new WindowManagerService(mContext, mPM,
mHaveInputMethods, mAllowBootMessages);
+ s.mChoreographer.addOnAnimateListener(s);
android.os.Process.setThreadPriority(
android.os.Process.THREAD_PRIORITY_DISPLAY);
android.os.Process.setCanSelfBackground(false);
@@ -774,6 +780,8 @@
Settings.System.WINDOW_ANIMATION_SCALE, mWindowAnimationScale);
mTransitionAnimationScale = Settings.System.getFloat(context.getContentResolver(),
Settings.System.TRANSITION_ANIMATION_SCALE, mTransitionAnimationScale);
+ mAnimatorDurationScale = Settings.System.getFloat(context.getContentResolver(),
+ Settings.System.ANIMATOR_DURATION_SCALE, mTransitionAnimationScale);
// Track changes to DevicePolicyManager state so we can enable/disable keyguard.
IntentFilter filter = new IntentFilter();
@@ -2543,8 +2551,12 @@
if (win == null) {
return 0;
}
- win.mRequestedWidth = requestedWidth;
- win.mRequestedHeight = requestedHeight;
+ if (win.mRequestedWidth != requestedWidth
+ || win.mRequestedHeight != requestedHeight) {
+ win.mLayoutNeeded = true;
+ win.mRequestedWidth = requestedWidth;
+ win.mRequestedHeight = requestedHeight;
+ }
if (attrs != null && seq == win.mSeq) {
win.mSystemUiVisibility = systemUiVisibility;
}
@@ -2565,6 +2577,9 @@
}
flagChanges = win.mAttrs.flags ^= attrs.flags;
attrChanges = win.mAttrs.copyFrom(attrs);
+ if ((attrChanges&WindowManager.LayoutParams.LAYOUT_CHANGED) != 0) {
+ win.mLayoutNeeded = true;
+ }
}
if (DEBUG_LAYOUT) Slog.v(TAG, "Relayout " + win + ": " + win.mAttrs);
@@ -3446,7 +3461,7 @@
// the value of the previous configuration.
mTempConfiguration.setToDefaults();
mTempConfiguration.fontScale = currentConfig.fontScale;
- if (computeNewConfigurationLocked(mTempConfiguration)) {
+ if (computeScreenConfigurationLocked(mTempConfiguration)) {
if (currentConfig.diff(mTempConfiguration) != 0) {
mWaitingForConfig = true;
mLayoutNeeded = true;
@@ -4650,6 +4665,7 @@
switch (which) {
case 0: mWindowAnimationScale = fixScale(scale); break;
case 1: mTransitionAnimationScale = fixScale(scale); break;
+ case 2: mAnimatorDurationScale = fixScale(scale); break;
}
// Persist setting
@@ -4669,6 +4685,9 @@
if (scales.length >= 2) {
mTransitionAnimationScale = fixScale(scales[1]);
}
+ if (scales.length >= 3) {
+ mAnimatorDurationScale = fixScale(scales[2]);
+ }
}
// Persist setting
@@ -4679,12 +4698,14 @@
switch (which) {
case 0: return mWindowAnimationScale;
case 1: return mTransitionAnimationScale;
+ case 2: return mAnimatorDurationScale;
}
return 0;
}
public float[] getAnimationScales() {
- return new float[] { mWindowAnimationScale, mTransitionAnimationScale };
+ return new float[] { mWindowAnimationScale, mTransitionAnimationScale,
+ mAnimatorDurationScale };
}
public int getSwitchState(int sw) {
@@ -5362,6 +5383,14 @@
startFreezingDisplayLocked(inTransaction);
mInputManager.setDisplayOrientation(0, rotation);
+ // We need to update our screen size information to match the new
+ // rotation. Note that this is redundant with the later call to
+ // sendNewConfiguration() that must be called after this function
+ // returns... however we need to do the screen size part of that
+ // before then so we have the correct size to use when initializiation
+ // the rotation animation for the new rotation.
+ computeScreenConfigurationLocked(null);
+
if (!inTransaction) {
if (SHOW_TRANSACTIONS) Slog.i(TAG,
">>> OPEN TRANSACTION setRotationUnchecked");
@@ -5372,7 +5401,11 @@
// it doesn't support hardware OpenGL emulation yet.
if (CUSTOM_SCREEN_ROTATION && mScreenRotationAnimation != null
&& mScreenRotationAnimation.hasScreenshot()) {
- mScreenRotationAnimation.setRotation(rotation);
+ if (mScreenRotationAnimation.setRotation(rotation, mFxSession,
+ MAX_ANIMATION_DURATION, mTransitionAnimationScale,
+ mCurDisplayWidth, mCurDisplayHeight)) {
+ mChoreographer.scheduleAnimation();
+ }
}
Surface.setOrientation(0, rotation);
} finally {
@@ -5860,7 +5893,7 @@
Configuration computeNewConfigurationLocked() {
Configuration config = new Configuration();
config.fontScale = 0;
- if (!computeNewConfigurationLocked(config)) {
+ if (!computeScreenConfigurationLocked(config)) {
return null;
}
return config;
@@ -6011,12 +6044,10 @@
return sw;
}
- boolean computeNewConfigurationLocked(Configuration config) {
+ boolean computeScreenConfigurationLocked(Configuration config) {
if (mDisplay == null) {
return false;
}
-
- mInputManager.getInputConfiguration(config);
// Use the effective "visual" dimensions based on current rotation
final boolean rotated = (mRotation == Surface.ROTATION_90
@@ -6050,13 +6081,17 @@
final int dw = mCurDisplayWidth;
final int dh = mCurDisplayHeight;
- int orientation = Configuration.ORIENTATION_SQUARE;
- if (dw < dh) {
- orientation = Configuration.ORIENTATION_PORTRAIT;
- } else if (dw > dh) {
- orientation = Configuration.ORIENTATION_LANDSCAPE;
+ if (config != null) {
+ mInputManager.getInputConfiguration(config);
+
+ int orientation = Configuration.ORIENTATION_SQUARE;
+ if (dw < dh) {
+ orientation = Configuration.ORIENTATION_PORTRAIT;
+ } else if (dw > dh) {
+ orientation = Configuration.ORIENTATION_LANDSCAPE;
+ }
+ config.orientation = orientation;
}
- config.orientation = orientation;
// Update real display metrics.
mDisplay.getMetricsWithSize(mRealDisplayMetrics, mCurDisplayWidth, mCurDisplayHeight);
@@ -6078,36 +6113,39 @@
mCompatibleScreenScale = CompatibilityInfo.computeCompatibleScaling(dm,
mCompatDisplayMetrics);
- config.screenWidthDp = (int)(mPolicy.getConfigDisplayWidth(dw, dh, mRotation)
- / dm.density);
- config.screenHeightDp = (int)(mPolicy.getConfigDisplayHeight(dw, dh, mRotation)
- / dm.density);
- computeSmallestWidthAndScreenLayout(rotated, dw, dh, dm.density, config);
+ if (config != null) {
+ config.screenWidthDp = (int)(mPolicy.getConfigDisplayWidth(dw, dh, mRotation)
+ / dm.density);
+ config.screenHeightDp = (int)(mPolicy.getConfigDisplayHeight(dw, dh, mRotation)
+ / 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);
+ config.compatScreenWidthDp = (int)(config.screenWidthDp / mCompatibleScreenScale);
+ config.compatScreenHeightDp = (int)(config.screenHeightDp / mCompatibleScreenScale);
+ config.compatSmallestScreenWidthDp = computeCompatSmallestWidth(rotated, dm, dw, dh);
- // Determine whether a hard keyboard is available and enabled.
- boolean hardKeyboardAvailable = config.keyboard != Configuration.KEYBOARD_NOKEYS;
- if (hardKeyboardAvailable != mHardKeyboardAvailable) {
- mHardKeyboardAvailable = hardKeyboardAvailable;
- mHardKeyboardEnabled = hardKeyboardAvailable;
+ // Determine whether a hard keyboard is available and enabled.
+ boolean hardKeyboardAvailable = config.keyboard != Configuration.KEYBOARD_NOKEYS;
+ if (hardKeyboardAvailable != mHardKeyboardAvailable) {
+ mHardKeyboardAvailable = hardKeyboardAvailable;
+ mHardKeyboardEnabled = hardKeyboardAvailable;
- mH.removeMessages(H.REPORT_HARD_KEYBOARD_STATUS_CHANGE);
- mH.sendEmptyMessage(H.REPORT_HARD_KEYBOARD_STATUS_CHANGE);
- }
- if (!mHardKeyboardEnabled) {
- config.keyboard = Configuration.KEYBOARD_NOKEYS;
+ mH.removeMessages(H.REPORT_HARD_KEYBOARD_STATUS_CHANGE);
+ mH.sendEmptyMessage(H.REPORT_HARD_KEYBOARD_STATUS_CHANGE);
+ }
+ if (!mHardKeyboardEnabled) {
+ config.keyboard = Configuration.KEYBOARD_NOKEYS;
+ }
+
+ // Update value of keyboardHidden, hardKeyboardHidden and navigationHidden
+ // based on whether a hard or soft keyboard is present, whether navigation keys
+ // are present and the lid switch state.
+ config.keyboardHidden = Configuration.KEYBOARDHIDDEN_NO;
+ config.hardKeyboardHidden = Configuration.HARDKEYBOARDHIDDEN_NO;
+ config.navigationHidden = Configuration.NAVIGATIONHIDDEN_NO;
+ mPolicy.adjustConfigurationLw(config);
}
- // Update value of keyboardHidden, hardKeyboardHidden and navigationHidden
- // based on whether a hard or soft keyboard is present, whether navigation keys
- // are present and the lid switch state.
- config.keyboardHidden = Configuration.KEYBOARDHIDDEN_NO;
- config.hardKeyboardHidden = Configuration.HARDKEYBOARDHIDDEN_NO;
- config.navigationHidden = Configuration.NAVIGATIONHIDDEN_NO;
- mPolicy.adjustConfigurationLw(config);
return true;
}
@@ -6489,7 +6527,7 @@
final class H extends Handler {
public static final int REPORT_FOCUS_CHANGE = 2;
public static final int REPORT_LOSING_FOCUS = 3;
- public static final int ANIMATE = 4;
+ public static final int DO_TRAVERSAL = 4;
public static final int ADD_STARTING = 5;
public static final int REMOVE_STARTING = 6;
public static final int FINISHED_STARTING = 7;
@@ -6583,9 +6621,9 @@
}
} break;
- case ANIMATE: {
+ case DO_TRAVERSAL: {
synchronized(mWindowMap) {
- mAnimationPending = false;
+ mTraversalScheduled = false;
performLayoutAndPlaceSurfacesLocked();
}
} break;
@@ -6801,12 +6839,14 @@
Settings.System.WINDOW_ANIMATION_SCALE, mWindowAnimationScale);
Settings.System.putFloat(mContext.getContentResolver(),
Settings.System.TRANSITION_ANIMATION_SCALE, mTransitionAnimationScale);
+ Settings.System.putFloat(mContext.getContentResolver(),
+ Settings.System.ANIMATOR_DURATION_SCALE, mAnimatorDurationScale);
break;
}
case FORCE_GC: {
synchronized(mWindowMap) {
- if (mAnimationPending) {
+ if (mChoreographer.isAnimationScheduled()) {
// If we are animating, don't do the gc now but
// delay a bit so we don't interrupt the animation.
mH.sendMessageDelayed(mH.obtainMessage(H.FORCE_GC),
@@ -7114,7 +7154,7 @@
boolean configChanged = updateOrientationFromAppTokensLocked(false);
mTempConfiguration.setToDefaults();
mTempConfiguration.fontScale = mCurConfiguration.fontScale;
- if (computeNewConfigurationLocked(mTempConfiguration)) {
+ if (computeScreenConfigurationLocked(mTempConfiguration)) {
if (mCurConfiguration.diff(mTempConfiguration) != 0) {
configChanged = true;
}
@@ -7365,7 +7405,7 @@
} else {
mInLayout = false;
if (mLayoutNeeded) {
- requestAnimationLocked(0);
+ requestTraversalLocked();
}
}
if (mWindowsChanged && !mWindowChangeListeners.isEmpty()) {
@@ -7443,12 +7483,13 @@
// if they want. (We do the normal layout for INVISIBLE
// windows, since that means "perform layout as normal,
// just don't display").
- if (!gone || !win.mHaveFrame) {
+ if (!gone || !win.mHaveFrame || win.mLayoutNeeded) {
if (!win.mLayoutAttached) {
if (initial) {
//Slog.i(TAG, "Window " + this + " clearing mContentChanged - initial");
win.mContentChanged = false;
}
+ win.mLayoutNeeded = false;
win.prelayout();
mPolicy.layoutWindowLw(win, win.mAttrs, null);
win.mLayoutSeq = seq;
@@ -7480,11 +7521,12 @@
// windows, since that means "perform layout as normal,
// just don't display").
if ((win.mViewVisibility != View.GONE && win.mRelayoutCalled)
- || !win.mHaveFrame) {
+ || !win.mHaveFrame || win.mLayoutNeeded) {
if (initial) {
//Slog.i(TAG, "Window " + this + " clearing mContentChanged - initial");
win.mContentChanged = false;
}
+ win.mLayoutNeeded = false;
win.prelayout();
mPolicy.layoutWindowLw(win, win.mAttrs, win.mAttachedWindow);
win.mLayoutSeq = seq;
@@ -8796,10 +8838,9 @@
needRelayout = adjustWallpaperWindowsLocked() != 0;
}
if (needRelayout) {
- requestAnimationLocked(0);
+ requestTraversalLocked();
} else if (animating) {
- final int refreshTimeUs = (int)(1000 / mDisplay.getRefreshRate());
- requestAnimationLocked(currentTime + refreshTimeUs - SystemClock.uptimeMillis());
+ mChoreographer.scheduleAnimation();
}
// Finally update all input windows now that the window changes have stabilized.
@@ -8918,10 +8959,17 @@
}
}
- void requestAnimationLocked(long delay) {
- if (!mAnimationPending) {
- mAnimationPending = true;
- mH.sendMessageDelayed(mH.obtainMessage(H.ANIMATE), delay);
+ void requestTraversalLocked() {
+ if (!mTraversalScheduled) {
+ mTraversalScheduled = true;
+ mH.sendEmptyMessage(H.DO_TRAVERSAL);
+ }
+ }
+
+ @Override
+ public void onAnimate() {
+ synchronized(mWindowMap) {
+ performLayoutAndPlaceSurfacesLocked();
}
}
@@ -9241,7 +9289,7 @@
if (DEBUG_ORIENTATION) Slog.i(TAG, "**** Dismissing screen rotation animation");
if (mScreenRotationAnimation.dismiss(mFxSession, MAX_ANIMATION_DURATION,
mTransitionAnimationScale, mCurDisplayWidth, mCurDisplayHeight)) {
- requestAnimationLocked(0);
+ mChoreographer.scheduleAnimation();
} else {
mScreenRotationAnimation = null;
updateRotation = true;
@@ -9422,6 +9470,10 @@
return mPolicy.hasNavigationBar();
}
+ public void lockNow() {
+ mPolicy.lockNow();
+ }
+
void dumpInput(FileDescriptor fd, PrintWriter pw, boolean dumpAll) {
pw.println("WINDOW MANAGER INPUT (dumpsys window input)");
mInputManager.dump(pw);
@@ -9729,9 +9781,10 @@
pw.print(" mLastWindowForcedOrientation"); pw.print(mLastWindowForcedOrientation);
pw.print(" mForcedAppOrientation="); pw.println(mForcedAppOrientation);
pw.print(" mDeferredRotationPauseCount="); pw.println(mDeferredRotationPauseCount);
- pw.print(" mAnimationPending="); pw.print(mAnimationPending);
+ pw.print(" mTraversalScheduled="); pw.print(mTraversalScheduled);
pw.print(" mWindowAnimationScale="); pw.print(mWindowAnimationScale);
pw.print(" mTransitionWindowAnimationScale="); pw.println(mTransitionAnimationScale);
+ pw.print(" mAnimatorDurationScale="); pw.println(mAnimatorDurationScale);
pw.print(" mNextAppTransition=0x");
pw.print(Integer.toHexString(mNextAppTransition));
pw.print(" mAppTransitionReady="); pw.println(mAppTransitionReady);
diff --git a/services/java/com/android/server/wm/WindowState.java b/services/java/com/android/server/wm/WindowState.java
index 794515b..6868cf6 100644
--- a/services/java/com/android/server/wm/WindowState.java
+++ b/services/java/com/android/server/wm/WindowState.java
@@ -238,6 +238,12 @@
// we can give the window focus before waiting for the relayout.
boolean mRelayoutCalled;
+ // If the application has called relayout() with changes that can
+ // impact its window's size, we need to perform a layout pass on it
+ // even if it is not currently visible for layout. This is set
+ // when in that case until the layout is done.
+ boolean mLayoutNeeded;
+
// This is set after the Surface has been created but before the
// window has been drawn. During this time the surface is hidden.
boolean mDrawPending;
@@ -1587,7 +1593,7 @@
mService.applyAnimationLocked(this, WindowManagerPolicy.TRANSIT_ENTER, true);
}
if (requestAnim) {
- mService.requestAnimationLocked(0);
+ mService.mChoreographer.scheduleAnimation();
}
return true;
}
@@ -1628,7 +1634,7 @@
}
}
if (requestAnim) {
- mService.requestAnimationLocked(0);
+ mService.mChoreographer.scheduleAnimation();
}
return true;
}
@@ -1728,8 +1734,9 @@
pw.print(mPolicyVisibilityAfterAnim);
pw.print(" mAttachedHidden="); pw.println(mAttachedHidden);
}
- if (!mRelayoutCalled) {
- pw.print(prefix); pw.print("mRelayoutCalled="); pw.println(mRelayoutCalled);
+ if (!mRelayoutCalled || mLayoutNeeded) {
+ pw.print(prefix); pw.print("mRelayoutCalled="); pw.print(mRelayoutCalled);
+ pw.print(" mLayoutNeeded="); pw.println(mLayoutNeeded);
}
if (mSurfaceResized || mSurfaceDestroyDeferred) {
pw.print(prefix); pw.print("mSurfaceResized="); pw.print(mSurfaceResized);
diff --git a/services/surfaceflinger/Android.mk b/services/surfaceflinger/Android.mk
index 95d651a..8b4c074 100644
--- a/services/surfaceflinger/Android.mk
+++ b/services/surfaceflinger/Android.mk
@@ -23,6 +23,10 @@
LOCAL_CFLAGS:= -DLOG_TAG=\"SurfaceFlinger\"
LOCAL_CFLAGS += -DGL_GLEXT_PROTOTYPES -DEGL_EGLEXT_PROTOTYPES
+ifeq ($(TARGET_HAS_WAITFORVSYNC), true)
+ LOCAL_CFLAGS += -DHAS_WAITFORVSYNC
+endif
+
ifeq ($(TARGET_BOARD_PLATFORM), omap3)
LOCAL_CFLAGS += -DNO_RGBX_8888
endif
@@ -31,10 +35,8 @@
endif
ifeq ($(TARGET_BOARD_PLATFORM), s5pc110)
LOCAL_CFLAGS += -DHAS_CONTEXT_PRIORITY -DNEVER_DEFAULT_TO_ASYNC_MODE
- LOCAL_CFLAGS += -DREFRESH_RATE=56
endif
-
LOCAL_SHARED_LIBRARIES := \
libcutils \
libhardware \
diff --git a/services/surfaceflinger/DisplayHardware/DisplayHardware.cpp b/services/surfaceflinger/DisplayHardware/DisplayHardware.cpp
index 438a6da..986aec5 100644
--- a/services/surfaceflinger/DisplayHardware/DisplayHardware.cpp
+++ b/services/surfaceflinger/DisplayHardware/DisplayHardware.cpp
@@ -350,15 +350,28 @@
}
// this needs to be thread safe
-nsecs_t DisplayHardware::waitForVSync() const {
+nsecs_t DisplayHardware::waitForRefresh() const {
nsecs_t timestamp;
if (mVSync.wait(×tamp) < 0) {
// vsync not supported!
usleep( getDelayToNextVSyncUs(×tamp) );
}
+ mLastHwVSync = timestamp; // FIXME: Not thread safe
return timestamp;
}
+nsecs_t DisplayHardware::getRefreshTimestamp() const {
+ // this returns the last refresh timestamp.
+ // if the last one is not available, we estimate it based on
+ // the refresh period and whatever closest timestamp we have.
+ nsecs_t now = systemTime();
+ return now - ((now - mLastHwVSync) % mRefreshPeriod);
+}
+
+nsecs_t DisplayHardware::getRefreshPeriod() const {
+ return mRefreshPeriod;
+}
+
int32_t DisplayHardware::getDelayToNextVSyncUs(nsecs_t* timestamp) const {
Mutex::Autolock _l(mFakeVSyncMutex);
const nsecs_t period = mRefreshPeriod;
diff --git a/services/surfaceflinger/DisplayHardware/DisplayHardware.h b/services/surfaceflinger/DisplayHardware/DisplayHardware.h
index 77da272..02be4dc 100644
--- a/services/surfaceflinger/DisplayHardware/DisplayHardware.h
+++ b/services/surfaceflinger/DisplayHardware/DisplayHardware.h
@@ -76,7 +76,9 @@
uint32_t getMaxViewportDims() const;
// waits for the next vsync and returns the timestamp of when it happened
- nsecs_t waitForVSync() const;
+ nsecs_t waitForRefresh() const;
+ nsecs_t getRefreshPeriod() const;
+ nsecs_t getRefreshTimestamp() const;
uint32_t getPageFlipCount() const;
EGLDisplay getEGLDisplay() const { return mDisplay; }
@@ -119,6 +121,7 @@
mutable Mutex mFakeVSyncMutex;
mutable nsecs_t mNextFakeVSync;
nsecs_t mRefreshPeriod;
+ mutable nsecs_t mLastHwVSync;
HWComposer* mHwc;
diff --git a/services/surfaceflinger/DisplayHardware/DisplayHardwareBase.cpp b/services/surfaceflinger/DisplayHardware/DisplayHardwareBase.cpp
index f4afeea..09f1906 100644
--- a/services/surfaceflinger/DisplayHardware/DisplayHardwareBase.cpp
+++ b/services/surfaceflinger/DisplayHardware/DisplayHardwareBase.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2007 The Android Open Source Project
+ * Copyright (C) 2012 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -14,7 +14,6 @@
* limitations under the License.
*/
-#include <assert.h>
#include <errno.h>
#include <stdlib.h>
#include <stdio.h>
@@ -22,15 +21,6 @@
#include <unistd.h>
#include <fcntl.h>
-#include <signal.h>
-#include <termios.h>
-#include <sys/ioctl.h>
-#include <sys/mman.h>
-#include <sys/time.h>
-#include <sys/types.h>
-#include <sys/resource.h>
-
-#include <linux/unistd.h>
#include <utils/Log.h>
@@ -45,39 +35,30 @@
// ----------------------------------------------------------------------------
-DisplayHardwareBase::DisplayEventThreadBase::DisplayEventThreadBase(
+DisplayHardwareBase::DisplayEventThread::DisplayEventThread(
const sp<SurfaceFlinger>& flinger)
: Thread(false), mFlinger(flinger) {
}
-DisplayHardwareBase::DisplayEventThreadBase::~DisplayEventThreadBase() {
+DisplayHardwareBase::DisplayEventThread::~DisplayEventThread() {
}
-// ----------------------------------------------------------------------------
-
-DisplayHardwareBase::DisplayEventThread::DisplayEventThread(
- const sp<SurfaceFlinger>& flinger)
- : DisplayEventThreadBase(flinger)
-{
+void DisplayHardwareBase::DisplayEventThread::onFirstRef() {
+ if (initCheck() == NO_ERROR) {
+ run("DisplayEventThread", PRIORITY_URGENT_DISPLAY);
+ } else {
+ ALOGW("/sys/power/wait_for_fb_{wake|sleep} don't exist");
+ }
}
-DisplayHardwareBase::DisplayEventThread::~DisplayEventThread()
-{
+status_t DisplayHardwareBase::DisplayEventThread::initCheck() const {
+ return ((access(kSleepFileName, R_OK) == 0 &&
+ access(kWakeFileName, R_OK) == 0)) ? NO_ERROR : NO_INIT;
}
-bool DisplayHardwareBase::DisplayEventThread::threadLoop()
-{
- int err = 0;
- char buf;
- int fd;
+bool DisplayHardwareBase::DisplayEventThread::threadLoop() {
- fd = open(kSleepFileName, O_RDONLY, 0);
- do {
- err = read(fd, &buf, 1);
- } while (err < 0 && errno == EINTR);
- close(fd);
- ALOGW_IF(err<0, "ANDROID_WAIT_FOR_FB_SLEEP failed (%s)", strerror(errno));
- if (err >= 0) {
+ if (waitForFbSleep() == NO_ERROR) {
sp<SurfaceFlinger> flinger = mFlinger.promote();
ALOGD("About to give-up screen, flinger = %p", flinger.get());
if (flinger != 0) {
@@ -85,39 +66,51 @@
flinger->screenReleased(0);
mBarrier.wait();
}
+ if (waitForFbWake() == NO_ERROR) {
+ sp<SurfaceFlinger> flinger = mFlinger.promote();
+ ALOGD("Screen about to return, flinger = %p", flinger.get());
+ if (flinger != 0) {
+ flinger->screenAcquired(0);
+ }
+ return true;
+ }
}
- fd = open(kWakeFileName, O_RDONLY, 0);
+
+ // error, exit the thread
+ return false;
+}
+
+status_t DisplayHardwareBase::DisplayEventThread::waitForFbSleep() {
+ int err = 0;
+ char buf;
+ int fd = open(kSleepFileName, O_RDONLY, 0);
+ // if the file doesn't exist, the error will be caught in read() below
do {
- err = read(fd, &buf, 1);
+ err = read(fd, &buf, 1);
} while (err < 0 && errno == EINTR);
close(fd);
- ALOGW_IF(err<0, "ANDROID_WAIT_FOR_FB_WAKE failed (%s)", strerror(errno));
- if (err >= 0) {
- sp<SurfaceFlinger> flinger = mFlinger.promote();
- ALOGD("Screen about to return, flinger = %p", flinger.get());
- if (flinger != 0)
- flinger->screenAcquired(0);
- }
- return true;
+ ALOGE_IF(err<0, "*** ANDROID_WAIT_FOR_FB_SLEEP failed (%s)", strerror(errno));
+ return err < 0 ? -errno : int(NO_ERROR);
}
-status_t DisplayHardwareBase::DisplayEventThread::releaseScreen() const
-{
+status_t DisplayHardwareBase::DisplayEventThread::waitForFbWake() {
+ int err = 0;
+ char buf;
+ int fd = open(kWakeFileName, O_RDONLY, 0);
+ // if the file doesn't exist, the error will be caught in read() below
+ do {
+ err = read(fd, &buf, 1);
+ } while (err < 0 && errno == EINTR);
+ close(fd);
+ ALOGE_IF(err<0, "*** ANDROID_WAIT_FOR_FB_WAKE failed (%s)", strerror(errno));
+ return err < 0 ? -errno : int(NO_ERROR);
+}
+
+status_t DisplayHardwareBase::DisplayEventThread::releaseScreen() const {
mBarrier.open();
return NO_ERROR;
}
-status_t DisplayHardwareBase::DisplayEventThread::readyToRun()
-{
- return NO_ERROR;
-}
-
-status_t DisplayHardwareBase::DisplayEventThread::initCheck() const
-{
- return ((access(kSleepFileName, R_OK) == 0 &&
- access(kWakeFileName, R_OK) == 0)) ? NO_ERROR : NO_INIT;
-}
-
// ----------------------------------------------------------------------------
DisplayHardwareBase::DisplayHardwareBase(const sp<SurfaceFlinger>& flinger,
@@ -127,35 +120,27 @@
mDisplayEventThread = new DisplayEventThread(flinger);
}
-DisplayHardwareBase::~DisplayHardwareBase()
-{
+DisplayHardwareBase::~DisplayHardwareBase() {
// request exit
mDisplayEventThread->requestExitAndWait();
}
-bool DisplayHardwareBase::canDraw() const
-{
+bool DisplayHardwareBase::canDraw() const {
return mScreenAcquired;
}
-void DisplayHardwareBase::releaseScreen() const
-{
+void DisplayHardwareBase::releaseScreen() const {
status_t err = mDisplayEventThread->releaseScreen();
if (err >= 0) {
mScreenAcquired = false;
}
}
-void DisplayHardwareBase::acquireScreen() const
-{
- status_t err = mDisplayEventThread->acquireScreen();
- if (err >= 0) {
- mScreenAcquired = true;
- }
+void DisplayHardwareBase::acquireScreen() const {
+ mScreenAcquired = true;
}
-bool DisplayHardwareBase::isScreenAcquired() const
-{
+bool DisplayHardwareBase::isScreenAcquired() const {
return mScreenAcquired;
}
diff --git a/services/surfaceflinger/DisplayHardware/DisplayHardwareBase.h b/services/surfaceflinger/DisplayHardware/DisplayHardwareBase.h
index ef2df43..91ea602 100644
--- a/services/surfaceflinger/DisplayHardware/DisplayHardwareBase.h
+++ b/services/surfaceflinger/DisplayHardware/DisplayHardwareBase.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2007 The Android Open Source Project
+ * Copyright (C) 2012 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -20,8 +20,6 @@
#include <stdint.h>
#include <utils/RefBase.h>
#include <utils/threads.h>
-#include <linux/kd.h>
-#include <linux/vt.h>
#include "Barrier.h"
namespace android {
@@ -31,11 +29,11 @@
class DisplayHardwareBase
{
public:
- DisplayHardwareBase(
- const sp<SurfaceFlinger>& flinger,
- uint32_t displayIndex);
+ DisplayHardwareBase(
+ const sp<SurfaceFlinger>& flinger,
+ uint32_t displayIndex);
- ~DisplayHardwareBase();
+ ~DisplayHardwareBase();
// console management
void releaseScreen() const;
@@ -46,34 +44,22 @@
private:
- class DisplayEventThreadBase : public Thread {
- protected:
+ class DisplayEventThread : public Thread {
wp<SurfaceFlinger> mFlinger;
- public:
- DisplayEventThreadBase(const sp<SurfaceFlinger>& flinger);
- virtual ~DisplayEventThreadBase();
- virtual void onFirstRef() {
- run("DisplayEventThread", PRIORITY_URGENT_DISPLAY);
- }
- virtual status_t acquireScreen() const { return NO_ERROR; };
- virtual status_t releaseScreen() const { return NO_ERROR; };
- virtual status_t initCheck() const = 0;
- };
-
- class DisplayEventThread : public DisplayEventThreadBase
- {
mutable Barrier mBarrier;
+ status_t waitForFbSleep();
+ status_t waitForFbWake();
public:
- DisplayEventThread(const sp<SurfaceFlinger>& flinger);
+ DisplayEventThread(const sp<SurfaceFlinger>& flinger);
virtual ~DisplayEventThread();
+ virtual void onFirstRef();
virtual bool threadLoop();
- virtual status_t readyToRun();
- virtual status_t releaseScreen() const;
- virtual status_t initCheck() const;
+ status_t releaseScreen() const;
+ status_t initCheck() const;
};
- sp<DisplayEventThreadBase> mDisplayEventThread;
- mutable int mScreenAcquired;
+ sp<DisplayEventThread> mDisplayEventThread;
+ mutable int mScreenAcquired;
};
}; // namespace android
diff --git a/services/surfaceflinger/EventThread.cpp b/services/surfaceflinger/EventThread.cpp
index 80ab519..af0da0b 100644
--- a/services/surfaceflinger/EventThread.cpp
+++ b/services/surfaceflinger/EventThread.cpp
@@ -36,6 +36,7 @@
EventThread::EventThread(const sp<SurfaceFlinger>& flinger)
: mFlinger(flinger),
mHw(flinger->graphicPlane(0).displayHardware()),
+ mLastVSyncTimestamp(0),
mDeliveredEvents(0)
{
}
@@ -44,6 +45,20 @@
run("EventThread", PRIORITY_URGENT_DISPLAY + PRIORITY_MORE_FAVORABLE);
}
+sp<DisplayEventConnection> EventThread::createEventConnection() const {
+ return new DisplayEventConnection(const_cast<EventThread*>(this));
+}
+
+nsecs_t EventThread::getLastVSyncTimestamp() const {
+ Mutex::Autolock _l(mLock);
+ return mLastVSyncTimestamp;
+}
+
+nsecs_t EventThread::getVSyncPeriod() const {
+ return mHw.getRefreshPeriod();
+
+}
+
status_t EventThread::registerDisplayEventConnection(
const sp<DisplayEventConnection>& connection) {
Mutex::Autolock _l(mLock);
@@ -80,8 +95,11 @@
Mutex::Autolock _l(mLock);
ConnectionInfo* info = getConnectionInfoLocked(connection);
if (info) {
- info->count = (count == 0) ? -1 : count;
- mCondition.signal();
+ const int32_t new_count = (count == 0) ? -1 : count;
+ if (info->count != new_count) {
+ info->count = new_count;
+ mCondition.signal();
+ }
}
}
}
@@ -90,10 +108,8 @@
const wp<DisplayEventConnection>& connection) {
Mutex::Autolock _l(mLock);
ConnectionInfo* info = getConnectionInfoLocked(connection);
- if (info) {
- if (info->count < 0) {
- info->count = 0;
- }
+ if (info && info->count < 0) {
+ info->count = 0;
mCondition.signal();
}
}
@@ -129,14 +145,15 @@
// at least one listener requested VSYNC
mLock.unlock();
- timestamp = mHw.waitForVSync();
+ timestamp = mHw.waitForRefresh();
mLock.lock();
mDeliveredEvents++;
+ mLastVSyncTimestamp = timestamp;
// now see if we still need to report this VSYNC event
- bool reportVsync = false;
- size_t count = mDisplayEventConnections.size();
+ const size_t count = mDisplayEventConnections.size();
for (size_t i=0 ; i<count ; i++) {
+ bool reportVsync = false;
const ConnectionInfo& info(
mDisplayEventConnections.valueAt(i));
if (info.count >= 1) {
@@ -157,11 +174,7 @@
displayEventConnections.add(mDisplayEventConnections.keyAt(i));
}
}
-
- if (reportVsync) {
- break;
- }
- } while (true);
+ } while (!displayEventConnections.size());
// dispatch vsync events to listeners...
vsync.header.type = DisplayEventReceiver::DISPLAY_EVENT_VSYNC;
diff --git a/services/surfaceflinger/EventThread.h b/services/surfaceflinger/EventThread.h
index 35bd299..3a3071e 100644
--- a/services/surfaceflinger/EventThread.h
+++ b/services/surfaceflinger/EventThread.h
@@ -36,6 +36,7 @@
class SurfaceFlinger;
class DisplayHardware;
+class DisplayEventConnection;
// ---------------------------------------------------------------------------
@@ -45,6 +46,8 @@
public:
EventThread(const sp<SurfaceFlinger>& flinger);
+ sp<DisplayEventConnection> createEventConnection() const;
+
status_t registerDisplayEventConnection(
const sp<DisplayEventConnection>& connection);
@@ -56,6 +59,10 @@
void requestNextVsync(const wp<DisplayEventConnection>& connection);
+ nsecs_t getLastVSyncTimestamp() const;
+
+ nsecs_t getVSyncPeriod() const;
+
void dump(String8& result, char* buffer, size_t SIZE) const;
private:
@@ -88,6 +95,7 @@
// protected by mLock
KeyedVector< wp<DisplayEventConnection>, ConnectionInfo > mDisplayEventConnections;
+ nsecs_t mLastVSyncTimestamp;
// main thread only
size_t mDeliveredEvents;
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index d4c4b1f..64f72d5 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -38,6 +38,7 @@
#include "Layer.h"
#include "SurfaceFlinger.h"
#include "SurfaceTextureLayer.h"
+#include <math.h>
#define DEBUG_RESIZE 0
@@ -54,6 +55,9 @@
mCurrentTransform(0),
mCurrentScalingMode(NATIVE_WINDOW_SCALING_MODE_FREEZE),
mCurrentOpacity(true),
+ mRefreshPending(0),
+ mFrameLatencyNeeded(false),
+ mFrameLatencyOffset(0),
mFormat(PIXEL_FORMAT_NONE),
mGLExtensions(GLExtensions::getInstance()),
mOpaqueLayer(true),
@@ -65,6 +69,17 @@
glGenTextures(1, &mTextureName);
}
+void Layer::onLayerDisplayed() {
+ if (mFrameLatencyNeeded) {
+ const DisplayHardware& hw(graphicPlane(0).displayHardware());
+ mFrameStats[mFrameLatencyOffset].timestamp = mSurfaceTexture->getTimestamp();
+ mFrameStats[mFrameLatencyOffset].set = systemTime();
+ mFrameStats[mFrameLatencyOffset].vsync = hw.getRefreshTimestamp();
+ mFrameLatencyOffset = (mFrameLatencyOffset + 1) % 128;
+ mFrameLatencyNeeded = false;
+ }
+}
+
void Layer::onFirstRef()
{
LayerBaseClient::onFirstRef();
@@ -94,7 +109,7 @@
void Layer::onFrameQueued() {
android_atomic_inc(&mQueuedFrames);
- mFlinger->signalEvent();
+ mFlinger->signalLayerUpdate();
}
// called with SurfaceFlinger::mStateLock as soon as the layer is entered
@@ -388,16 +403,37 @@
// pageflip handling...
// ----------------------------------------------------------------------------
+bool Layer::onPreComposition()
+{
+ // if there was more than one pending update, request a refresh
+ if (mRefreshPending >= 2) {
+ mRefreshPending = 0;
+ return true;
+ }
+ mRefreshPending = 0;
+ return false;
+}
+
void Layer::lockPageFlip(bool& recomputeVisibleRegions)
{
if (mQueuedFrames > 0) {
+
+ // if we've already called updateTexImage() without going through
+ // a composition step, we have to skip this layer at this point
+ // because we cannot call updateTeximage() without a corresponding
+ // compositionComplete() call.
+ // we'll trigger an update in onPreComposition().
+ if (mRefreshPending++) {
+ return;
+ }
+
// Capture the old state of the layer for comparisons later
const bool oldOpacity = isOpaque();
sp<GraphicBuffer> oldActiveBuffer = mActiveBuffer;
// signal another event if we have more frames pending
if (android_atomic_dec(&mQueuedFrames) > 1) {
- mFlinger->signalEvent();
+ mFlinger->signalLayerUpdate();
}
if (mSurfaceTexture->updateTexImage() < NO_ERROR) {
@@ -408,6 +444,7 @@
// update the active buffer
mActiveBuffer = mSurfaceTexture->getCurrentBuffer();
+ mFrameLatencyNeeded = true;
const Rect crop(mSurfaceTexture->getCurrentCrop());
const uint32_t transform(mSurfaceTexture->getCurrentTransform());
@@ -499,6 +536,10 @@
void Layer::unlockPageFlip(
const Transform& planeTransform, Region& outDirtyRegion)
{
+ if (mRefreshPending >= 2) {
+ return;
+ }
+
Region dirtyRegion(mPostedDirtyRegion);
if (!dirtyRegion.isEmpty()) {
mPostedDirtyRegion.clear();
@@ -532,9 +573,9 @@
snprintf(buffer, SIZE,
" "
"format=%2d, activeBuffer=[%4ux%4u:%4u,%3X],"
- " transform-hint=0x%02x, queued-frames=%d\n",
+ " transform-hint=0x%02x, queued-frames=%d, mRefreshPending=%d\n",
mFormat, w0, h0, s0,f0,
- getTransformHint(), mQueuedFrames);
+ getTransformHint(), mQueuedFrames, mRefreshPending);
result.append(buffer);
@@ -543,6 +584,32 @@
}
}
+void Layer::dumpStats(String8& result, char* buffer, size_t SIZE) const
+{
+ LayerBaseClient::dumpStats(result, buffer, SIZE);
+ const size_t o = mFrameLatencyOffset;
+ const DisplayHardware& hw(graphicPlane(0).displayHardware());
+ const nsecs_t period = hw.getRefreshPeriod();
+ result.appendFormat("%lld\n", period);
+ for (size_t i=0 ; i<128 ; i++) {
+ const size_t index = (o+i) % 128;
+ const nsecs_t time_app = mFrameStats[index].timestamp;
+ const nsecs_t time_set = mFrameStats[index].set;
+ const nsecs_t time_vsync = mFrameStats[index].vsync;
+ result.appendFormat("%lld\t%lld\t%lld\n",
+ time_app,
+ time_vsync,
+ time_set);
+ }
+ result.append("\n");
+}
+
+void Layer::clearStats()
+{
+ LayerBaseClient::clearStats();
+ memset(mFrameStats, 0, sizeof(mFrameStats));
+}
+
uint32_t Layer::getEffectiveUsage(uint32_t usage) const
{
// TODO: should we do something special if mSecure is set?
diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h
index 2b9471b..bf30608 100644
--- a/services/surfaceflinger/Layer.h
+++ b/services/surfaceflinger/Layer.h
@@ -34,6 +34,7 @@
#include "LayerBase.h"
#include "SurfaceTextureLayer.h"
#include "Transform.h"
+#include <utils/Timers.h>
namespace android {
@@ -78,12 +79,17 @@
// LayerBaseClient interface
virtual wp<IBinder> getSurfaceTextureBinder() const;
+ virtual void onLayerDisplayed();
+ virtual bool onPreComposition();
+
// only for debugging
inline const sp<GraphicBuffer>& getActiveBuffer() const { return mActiveBuffer; }
protected:
virtual void onFirstRef();
virtual void dump(String8& result, char* scratch, size_t size) const;
+ virtual void dumpStats(String8& result, char* buffer, size_t SIZE) const;
+ virtual void clearStats();
private:
friend class SurfaceTextureLayer;
@@ -110,6 +116,19 @@
uint32_t mCurrentTransform;
uint32_t mCurrentScalingMode;
bool mCurrentOpacity;
+ size_t mRefreshPending;
+ bool mFrameLatencyNeeded;
+ int mFrameLatencyOffset;
+
+ struct Statistics {
+ Statistics() : timestamp(0), set(0), vsync(0) { }
+ nsecs_t timestamp; // buffer timestamp
+ nsecs_t set; // buffer displayed timestamp
+ nsecs_t vsync; // vsync immediately before set
+ };
+
+ // protected by mLock
+ Statistics mFrameStats[128];
// constants
PixelFormat mFormat;
@@ -121,9 +140,6 @@
bool mSecure; // no screenshots
bool mProtectedByApp; // application requires protected path to external sink
Region mPostedDirtyRegion;
-
- // binder thread, transaction thread
- mutable Mutex mLock;
};
// ---------------------------------------------------------------------------
diff --git a/services/surfaceflinger/LayerBase.cpp b/services/surfaceflinger/LayerBase.cpp
index 37879f1..44aafdf 100644
--- a/services/surfaceflinger/LayerBase.cpp
+++ b/services/surfaceflinger/LayerBase.cpp
@@ -47,8 +47,7 @@
mOrientation(0),
mPlaneOrientation(0),
mTransactionFlags(0),
- mPremultipliedAlpha(true), mName("unnamed"), mDebug(false),
- mInvalidate(0)
+ mPremultipliedAlpha(true), mName("unnamed"), mDebug(false)
{
const DisplayHardware& hw(flinger->graphicPlane(0).displayHardware());
mFlags = hw.getFlags();
@@ -262,23 +261,11 @@
mTransformedBounds = tr.makeBounds(w, h);
}
-void LayerBase::lockPageFlip(bool& recomputeVisibleRegions)
-{
+void LayerBase::lockPageFlip(bool& recomputeVisibleRegions) {
}
void LayerBase::unlockPageFlip(
- const Transform& planeTransform, Region& outDirtyRegion)
-{
- if ((android_atomic_and(~1, &mInvalidate)&1) == 1) {
- outDirtyRegion.orSelf(visibleRegionScreen);
- }
-}
-
-void LayerBase::invalidate()
-{
- if ((android_atomic_or(1, &mInvalidate)&1) == 0) {
- mFlinger->signalEvent();
- }
+ const Transform& planeTransform, Region& outDirtyRegion) {
}
void LayerBase::drawRegion(const Region& reg) const
@@ -471,6 +458,9 @@
void LayerBase::dump(String8& result, char* buffer, size_t SIZE) const
{
const Layer::State& s(drawingState());
+ s.transparentRegion.dump(result, "transparentRegion");
+ transparentRegionScreen.dump(result, "transparentRegionScreen");
+ visibleRegionScreen.dump(result, "visibleRegionScreen");
snprintf(buffer, SIZE,
"+ %s %p (%s)\n"
" "
@@ -486,11 +476,15 @@
result.append(buffer);
}
-void LayerBase::shortDump(String8& result, char* scratch, size_t size) const
-{
+void LayerBase::shortDump(String8& result, char* scratch, size_t size) const {
LayerBase::dump(result, scratch, size);
}
+void LayerBase::dumpStats(String8& result, char* scratch, size_t SIZE) const {
+}
+
+void LayerBase::clearStats() {
+}
// ---------------------------------------------------------------------------
diff --git a/services/surfaceflinger/LayerBase.h b/services/surfaceflinger/LayerBase.h
index 7f62145..b8f7680 100644
--- a/services/surfaceflinger/LayerBase.h
+++ b/services/surfaceflinger/LayerBase.h
@@ -103,8 +103,6 @@
Rect visibleBounds() const;
void drawRegion(const Region& reg) const;
- void invalidate();
-
virtual sp<LayerBaseClient> getLayerBaseClient() const { return 0; }
virtual sp<Layer> getLayer() const { return 0; }
@@ -204,11 +202,22 @@
/** called with the state lock when the surface is removed from the
* current list */
- virtual void onRemoved() { };
-
+ virtual void onRemoved() { }
+
+ /** called after page-flip
+ */
+ virtual void onLayerDisplayed() { }
+
+ /** called before composition.
+ * returns true if the layer has pending updates.
+ */
+ virtual bool onPreComposition() { return false; }
+
/** always call base class first */
virtual void dump(String8& result, char* scratch, size_t size) const;
virtual void shortDump(String8& result, char* scratch, size_t size) const;
+ virtual void dumpStats(String8& result, char* buffer, size_t SIZE) const;
+ virtual void clearStats();
enum { // flags for doTransaction()
@@ -271,10 +280,6 @@
mutable bool mDebug;
- // atomic
- volatile int32_t mInvalidate;
-
-
public:
// called from class SurfaceFlinger
virtual ~LayerBase();
diff --git a/services/surfaceflinger/MessageQueue.cpp b/services/surfaceflinger/MessageQueue.cpp
index cbd530c..1ff3567 100644
--- a/services/surfaceflinger/MessageQueue.cpp
+++ b/services/surfaceflinger/MessageQueue.cpp
@@ -18,12 +18,18 @@
#include <errno.h>
#include <sys/types.h>
+#include <binder/IPCThreadState.h>
+
#include <utils/threads.h>
#include <utils/Timers.h>
#include <utils/Log.h>
-#include <binder/IPCThreadState.h>
+
+#include <gui/IDisplayEventConnection.h>
+#include <gui/BitTube.h>
#include "MessageQueue.h"
+#include "EventThread.h"
+#include "SurfaceFlinger.h"
namespace android {
@@ -43,36 +49,69 @@
// ---------------------------------------------------------------------------
+void MessageQueue::Handler::signalRefresh() {
+ if ((android_atomic_or(eventMaskRefresh, &mEventMask) & eventMaskRefresh) == 0) {
+ mQueue.mLooper->sendMessage(this, Message(MessageQueue::REFRESH));
+ }
+}
+
+void MessageQueue::Handler::signalInvalidate() {
+ if ((android_atomic_or(eventMaskInvalidate, &mEventMask) & eventMaskInvalidate) == 0) {
+ mQueue.mLooper->sendMessage(this, Message(MessageQueue::INVALIDATE));
+ }
+}
+
+void MessageQueue::Handler::handleMessage(const Message& message) {
+ switch (message.what) {
+ case INVALIDATE:
+ android_atomic_and(~eventMaskInvalidate, &mEventMask);
+ mQueue.mFlinger->onMessageReceived(message.what);
+ break;
+ case REFRESH:
+ android_atomic_and(~eventMaskRefresh, &mEventMask);
+ mQueue.mFlinger->onMessageReceived(message.what);
+ break;
+ }
+}
+
+// ---------------------------------------------------------------------------
+
MessageQueue::MessageQueue()
- : mLooper(new Looper(true)), mWorkPending(0)
{
}
MessageQueue::~MessageQueue() {
}
+void MessageQueue::init(const sp<SurfaceFlinger>& flinger)
+{
+ mFlinger = flinger;
+ mLooper = new Looper(true);
+ mHandler = new Handler(*this);
+}
+
+void MessageQueue::setEventThread(const sp<EventThread>& eventThread)
+{
+ mEventThread = eventThread;
+ mEvents = eventThread->createEventConnection();
+ mEventTube = mEvents->getDataChannel();
+ mLooper->addFd(mEventTube->getFd(), 0, ALOOPER_EVENT_INPUT,
+ MessageQueue::cb_eventReceiver, this);
+}
+
void MessageQueue::waitMessage() {
do {
IPCThreadState::self()->flushCommands();
-
int32_t ret = mLooper->pollOnce(-1);
switch (ret) {
case ALOOPER_POLL_WAKE:
case ALOOPER_POLL_CALLBACK:
- // callback and/or wake
- if (android_atomic_and(0, &mWorkPending)) {
- return;
- }
continue;
-
+ case ALOOPER_POLL_ERROR:
+ ALOGE("ALOOPER_POLL_ERROR");
case ALOOPER_POLL_TIMEOUT:
// timeout (should not happen)
continue;
-
- case ALOOPER_POLL_ERROR:
- ALOGE("ALOOPER_POLL_ERROR");
- continue;
-
default:
// should not happen
ALOGE("Looper::pollOnce() returned unknown status %d", ret);
@@ -93,11 +132,31 @@
return NO_ERROR;
}
-status_t MessageQueue::invalidate() {
- if (android_atomic_or(1, &mWorkPending) == 0) {
- mLooper->wake();
+void MessageQueue::invalidate() {
+ mHandler->signalInvalidate();
+}
+
+void MessageQueue::refresh() {
+ mEvents->requestNextVsync();
+}
+
+int MessageQueue::cb_eventReceiver(int fd, int events, void* data) {
+ MessageQueue* queue = reinterpret_cast<MessageQueue *>(data);
+ return queue->eventReceiver(fd, events);
+}
+
+int MessageQueue::eventReceiver(int fd, int events) {
+ ssize_t n;
+ DisplayEventReceiver::Event buffer[8];
+ while ((n = DisplayEventReceiver::getEvents(mEventTube, buffer, 8)) > 0) {
+ for (int i=0 ; i<n ; i++) {
+ if (buffer[i].header.type == DisplayEventReceiver::DISPLAY_EVENT_VSYNC) {
+ mHandler->signalRefresh();
+ break;
+ }
+ }
}
- return NO_ERROR;
+ return 1;
}
// ---------------------------------------------------------------------------
diff --git a/services/surfaceflinger/MessageQueue.h b/services/surfaceflinger/MessageQueue.h
index 2317d81..ea29e7e 100644
--- a/services/surfaceflinger/MessageQueue.h
+++ b/services/surfaceflinger/MessageQueue.h
@@ -25,10 +25,16 @@
#include <utils/Timers.h>
#include <utils/Looper.h>
+#include <gui/DisplayEventReceiver.h>
+
#include "Barrier.h"
namespace android {
+class IDisplayEventConnection;
+class EventThread;
+class SurfaceFlinger;
+
// ---------------------------------------------------------------------------
class MessageBase : public MessageHandler
@@ -54,16 +60,48 @@
// ---------------------------------------------------------------------------
class MessageQueue {
+ class Handler : public MessageHandler {
+ enum {
+ eventMaskInvalidate = 0x1,
+ eventMaskRefresh = 0x2
+ };
+ MessageQueue& mQueue;
+ int32_t mEventMask;
+ public:
+ Handler(MessageQueue& queue) : mQueue(queue), mEventMask(0) { }
+ virtual void handleMessage(const Message& message);
+ void signalRefresh();
+ void signalInvalidate();
+ };
+
+ friend class Handler;
+
+ sp<SurfaceFlinger> mFlinger;
sp<Looper> mLooper;
- volatile int32_t mWorkPending;
+ sp<EventThread> mEventThread;
+ sp<IDisplayEventConnection> mEvents;
+ sp<BitTube> mEventTube;
+ sp<Handler> mHandler;
+
+
+ static int cb_eventReceiver(int fd, int events, void* data);
+ int eventReceiver(int fd, int events);
public:
+ enum {
+ INVALIDATE = 0,
+ REFRESH = 1,
+ };
+
MessageQueue();
~MessageQueue();
+ void init(const sp<SurfaceFlinger>& flinger);
+ void setEventThread(const sp<EventThread>& events);
void waitMessage();
status_t postMessage(const sp<MessageBase>& message, nsecs_t reltime=0);
- status_t invalidate();
+ void invalidate();
+ void refresh();
};
// ---------------------------------------------------------------------------
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index af47402..870235b 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -125,11 +125,34 @@
ALOGI_IF(mDebugDDMS, "DDMS debugging enabled");
}
+void SurfaceFlinger::onFirstRef()
+{
+ mEventQueue.init(this);
+
+ run("SurfaceFlinger", PRIORITY_URGENT_DISPLAY);
+
+ // Wait for the main thread to be done with its initialization
+ mReadyToRunBarrier.wait();
+}
+
+
SurfaceFlinger::~SurfaceFlinger()
{
glDeleteTextures(1, &mWormholeTexName);
}
+void SurfaceFlinger::binderDied(const wp<IBinder>& who)
+{
+ // the window manager died on us. prepare its eulogy.
+
+ // reset screen orientation
+ Vector<ComposerState> state;
+ setTransactionState(state, eOrientationDefault, 0);
+
+ // restart the boot-animation
+ property_set("ctl.start", "bootanim");
+}
+
sp<IMemoryHeap> SurfaceFlinger::getCblk() const
{
return mServerHeap;
@@ -183,25 +206,6 @@
property_set("ctl.stop", "bootanim");
}
-void SurfaceFlinger::binderDied(const wp<IBinder>& who)
-{
- // the window manager died on us. prepare its eulogy.
-
- // reset screen orientation
- setOrientation(0, eOrientationDefault, 0);
-
- // restart the boot-animation
- property_set("ctl.start", "bootanim");
-}
-
-void SurfaceFlinger::onFirstRef()
-{
- run("SurfaceFlinger", PRIORITY_URGENT_DISPLAY);
-
- // Wait for the main thread to be done with its initialization
- mReadyToRunBarrier.wait();
-}
-
static inline uint16_t pack565(int r, int g, int b) {
return (r<<11)|(g<<5)|b;
}
@@ -295,6 +299,7 @@
// start the EventThread
mEventThread = new EventThread(this);
+ mEventQueue.setEventThread(mEventThread);
/*
* We're now ready to accept clients...
@@ -309,34 +314,6 @@
}
// ----------------------------------------------------------------------------
-#if 0
-#pragma mark -
-#pragma mark Events Handler
-#endif
-
-void SurfaceFlinger::waitForEvent() {
- mEventQueue.waitMessage();
-}
-
-void SurfaceFlinger::signalEvent() {
- mEventQueue.invalidate();
-}
-
-status_t SurfaceFlinger::postMessageAsync(const sp<MessageBase>& msg,
- nsecs_t reltime, uint32_t flags) {
- return mEventQueue.postMessage(msg, reltime);
-}
-
-status_t SurfaceFlinger::postMessageSync(const sp<MessageBase>& msg,
- nsecs_t reltime, uint32_t flags) {
- status_t res = mEventQueue.postMessage(msg, reltime);
- if (res == NO_ERROR) {
- msg->wait();
- }
- return res;
-}
-
-// ----------------------------------------------------------------------------
bool SurfaceFlinger::authenticateSurfaceTexture(
const sp<ISurfaceTexture>& surfaceTexture) const {
@@ -382,60 +359,97 @@
// ----------------------------------------------------------------------------
sp<IDisplayEventConnection> SurfaceFlinger::createDisplayEventConnection() {
- sp<DisplayEventConnection> result(new DisplayEventConnection(mEventThread));
- return result;
+ return mEventThread->createEventConnection();
}
// ----------------------------------------------------------------------------
-#if 0
-#pragma mark -
-#pragma mark Main loop
-#endif
+
+void SurfaceFlinger::waitForEvent() {
+ mEventQueue.waitMessage();
+}
+
+void SurfaceFlinger::signalTransaction() {
+ mEventQueue.invalidate();
+}
+
+void SurfaceFlinger::signalLayerUpdate() {
+ mEventQueue.invalidate();
+}
+
+void SurfaceFlinger::signalRefresh() {
+ mEventQueue.refresh();
+}
+
+status_t SurfaceFlinger::postMessageAsync(const sp<MessageBase>& msg,
+ nsecs_t reltime, uint32_t flags) {
+ return mEventQueue.postMessage(msg, reltime);
+}
+
+status_t SurfaceFlinger::postMessageSync(const sp<MessageBase>& msg,
+ nsecs_t reltime, uint32_t flags) {
+ status_t res = mEventQueue.postMessage(msg, reltime);
+ if (res == NO_ERROR) {
+ msg->wait();
+ }
+ return res;
+}
bool SurfaceFlinger::threadLoop()
{
waitForEvent();
-
- // check for transactions
- if (CC_UNLIKELY(mConsoleSignals)) {
- handleConsoleEvents();
- }
-
- // if we're in a global transaction, don't do anything.
- const uint32_t mask = eTransactionNeeded | eTraversalNeeded;
- uint32_t transactionFlags = peekTransactionFlags(mask);
- if (CC_UNLIKELY(transactionFlags)) {
- handleTransaction(transactionFlags);
- }
-
- // post surfaces (if needed)
- handlePageFlip();
-
- if (mDirtyRegion.isEmpty()) {
- // nothing new to do.
- return true;
- }
-
- if (CC_UNLIKELY(mHwWorkListDirty)) {
- // build the h/w work list
- handleWorkList();
- }
-
- const DisplayHardware& hw(graphicPlane(0).displayHardware());
- if (CC_LIKELY(hw.canDraw())) {
- // repaint the framebuffer (if needed)
- handleRepaint();
- // inform the h/w that we're done compositing
- hw.compositionComplete();
- postFramebuffer();
- } else {
- // pretend we did the post
- hw.compositionComplete();
- hw.waitForVSync();
- }
return true;
}
+void SurfaceFlinger::onMessageReceived(int32_t what)
+{
+ switch (what) {
+ case MessageQueue::INVALIDATE: {
+ // check for transactions
+ if (CC_UNLIKELY(mConsoleSignals)) {
+ handleConsoleEvents();
+ }
+
+ // if we're in a global transaction, don't do anything.
+ const uint32_t mask = eTransactionNeeded | eTraversalNeeded;
+ uint32_t transactionFlags = peekTransactionFlags(mask);
+ if (CC_UNLIKELY(transactionFlags)) {
+ handleTransaction(transactionFlags);
+ }
+
+ // post surfaces (if needed)
+ handlePageFlip();
+
+ if (!mDirtyRegion.isEmpty()) {
+ signalRefresh();
+ }
+ } break;
+
+ case MessageQueue::REFRESH: {
+ if (!mDirtyRegion.isEmpty()) {
+ // NOTE: it is mandatory to call hw.compositionComplete()
+ // after handleRefresh()
+ handleRefresh();
+
+ const DisplayHardware& hw(graphicPlane(0).displayHardware());
+ if (CC_UNLIKELY(mHwWorkListDirty)) {
+ // build the h/w work list
+ handleWorkList();
+ }
+ if (CC_LIKELY(hw.canDraw())) {
+ // repaint the framebuffer (if needed)
+ handleRepaint();
+ // inform the h/w that we're done compositing
+ hw.compositionComplete();
+ postFramebuffer();
+ } else {
+ // pretend we did the post
+ hw.compositionComplete();
+ }
+ }
+ } break;
+ }
+}
+
void SurfaceFlinger::postFramebuffer()
{
// this should never happen. we do the flip anyways so we don't
@@ -445,6 +459,12 @@
const nsecs_t now = systemTime();
mDebugInSwapBuffers = now;
hw.flip(mSwapRegion);
+
+ size_t numLayers = mVisibleLayersSortedByZ.size();
+ for (size_t i = 0; i < numLayers; i++) {
+ mVisibleLayersSortedByZ[i]->onLayerDisplayed();
+ }
+
mLastSwapBufferTime = systemTime() - now;
mDebugInSwapBuffers = 0;
mSwapRegion.clear();
@@ -711,13 +731,13 @@
void SurfaceFlinger::handlePageFlip()
{
- bool visibleRegions = mVisibleRegionsDirty;
- const LayerVector& currentLayers(mDrawingState.layersSortedByZ);
- visibleRegions |= lockPageFlip(currentLayers);
+ const DisplayHardware& hw = graphicPlane(0).displayHardware();
+ const Region screenRegion(hw.bounds());
- const DisplayHardware& hw = graphicPlane(0).displayHardware();
- const Region screenRegion(hw.bounds());
- if (visibleRegions) {
+ const LayerVector& currentLayers(mDrawingState.layersSortedByZ);
+ const bool visibleRegions = lockPageFlip(currentLayers);
+
+ if (visibleRegions || mVisibleRegionsDirty) {
Region opaqueRegion;
computeVisibleRegions(currentLayers, mDirtyRegion, opaqueRegion);
@@ -764,7 +784,7 @@
{
const GraphicPlane& plane(graphicPlane(0));
const Transform& planeTransform(plane.transform());
- size_t count = currentLayers.size();
+ const size_t count = currentLayers.size();
sp<LayerBase> const* layers = currentLayers.array();
for (size_t i=0 ; i<count ; i++) {
const sp<LayerBase>& layer(layers[i]);
@@ -772,6 +792,23 @@
}
}
+void SurfaceFlinger::handleRefresh()
+{
+ bool needInvalidate = false;
+ const LayerVector& currentLayers(mDrawingState.layersSortedByZ);
+ const size_t count = currentLayers.size();
+ for (size_t i=0 ; i<count ; i++) {
+ const sp<LayerBase>& layer(currentLayers[i]);
+ if (layer->onPreComposition()) {
+ needInvalidate = true;
+ }
+ }
+ if (needInvalidate) {
+ signalLayerUpdate();
+ }
+}
+
+
void SurfaceFlinger::handleWorkList()
{
mHwWorkListDirty = false;
@@ -1169,7 +1206,7 @@
{
uint32_t old = android_atomic_or(flags, &mTransactionFlags);
if ((old & flags)==0) { // wake the server up
- signalEvent();
+ signalTransaction();
}
return old;
}
@@ -1219,26 +1256,6 @@
}
}
-int SurfaceFlinger::setOrientation(DisplayID dpy,
- int orientation, uint32_t flags)
-{
- if (CC_UNLIKELY(uint32_t(dpy) >= DISPLAY_COUNT))
- return BAD_VALUE;
-
- Mutex::Autolock _l(mStateLock);
- if (mCurrentState.orientation != orientation) {
- if (uint32_t(orientation)<=eOrientation270 || orientation==42) {
- mCurrentState.orientationFlags = flags;
- mCurrentState.orientation = orientation;
- setTransactionFlags(eTransactionNeeded);
- mTransactionCV.wait(mStateLock);
- } else {
- orientation = BAD_VALUE;
- }
- }
- return orientation;
-}
-
sp<ISurface> SurfaceFlinger::createSurface(
ISurfaceComposerClient::surface_data_t* params,
const String8& name,
@@ -1440,14 +1457,14 @@
{
// this may be called by a signal handler, we can't do too much in here
android_atomic_or(eConsoleReleased, &mConsoleSignals);
- signalEvent();
+ signalTransaction();
}
void SurfaceFlinger::screenAcquired(int dpy)
{
// this may be called by a signal handler, we can't do too much in here
android_atomic_or(eConsoleAcquired, &mConsoleSignals);
- signalEvent();
+ signalTransaction();
}
status_t SurfaceFlinger::dump(int fd, const Vector<String16>& args)
@@ -1463,14 +1480,6 @@
IPCThreadState::self()->getCallingUid());
result.append(buffer);
} else {
-
- // figure out if we're stuck somewhere
- const nsecs_t now = systemTime();
- const nsecs_t inSwapBuffers(mDebugInSwapBuffers);
- const nsecs_t inTransaction(mDebugInTransaction);
- nsecs_t inSwapBuffersDuration = (inSwapBuffers) ? now-inSwapBuffers : 0;
- nsecs_t inTransactionDuration = (inTransaction) ? now-inTransaction : 0;
-
// Try to get the main lock, but don't insist if we can't
// (this would indicate SF is stuck, but we want to be able to
// print something in dumpsys).
@@ -1486,111 +1495,35 @@
result.append(buffer);
}
- /*
- * Dump the visible layer list
- */
- const LayerVector& currentLayers = mCurrentState.layersSortedByZ;
- const size_t count = currentLayers.size();
- snprintf(buffer, SIZE, "Visible layers (count = %d)\n", count);
- result.append(buffer);
- for (size_t i=0 ; i<count ; i++) {
- const sp<LayerBase>& layer(currentLayers[i]);
- layer->dump(result, buffer, SIZE);
- const Layer::State& s(layer->drawingState());
- s.transparentRegion.dump(result, "transparentRegion");
- layer->transparentRegionScreen.dump(result, "transparentRegionScreen");
- layer->visibleRegionScreen.dump(result, "visibleRegionScreen");
+ bool dumpAll = true;
+ size_t index = 0;
+ size_t numArgs = args.size();
+ if (numArgs) {
+ dumpAll = false;
+
+ if ((index < numArgs) &&
+ (args[index] == String16("--list"))) {
+ index++;
+ listLayersLocked(args, index, result, buffer, SIZE);
+ }
+
+ if ((index < numArgs) &&
+ (args[index] == String16("--latency"))) {
+ index++;
+ dumpStatsLocked(args, index, result, buffer, SIZE);
+ }
+
+ if ((index < numArgs) &&
+ (args[index] == String16("--latency-clear"))) {
+ index++;
+ clearStatsLocked(args, index, result, buffer, SIZE);
+ }
}
- /*
- * Dump the layers in the purgatory
- */
-
- const size_t purgatorySize = mLayerPurgatory.size();
- snprintf(buffer, SIZE, "Purgatory state (%d entries)\n", purgatorySize);
- result.append(buffer);
- for (size_t i=0 ; i<purgatorySize ; i++) {
- const sp<LayerBase>& layer(mLayerPurgatory.itemAt(i));
- layer->shortDump(result, buffer, SIZE);
+ if (dumpAll) {
+ dumpAllLocked(result, buffer, SIZE);
}
- /*
- * Dump SurfaceFlinger global state
- */
-
- snprintf(buffer, SIZE, "SurfaceFlinger global state:\n");
- result.append(buffer);
-
- const GLExtensions& extensions(GLExtensions::getInstance());
- snprintf(buffer, SIZE, "GLES: %s, %s, %s\n",
- extensions.getVendor(),
- extensions.getRenderer(),
- extensions.getVersion());
- result.append(buffer);
-
- snprintf(buffer, SIZE, "EGL : %s\n",
- eglQueryString(graphicPlane(0).getEGLDisplay(),
- EGL_VERSION_HW_ANDROID));
- result.append(buffer);
-
- snprintf(buffer, SIZE, "EXTS: %s\n", extensions.getExtension());
- result.append(buffer);
-
- mWormholeRegion.dump(result, "WormholeRegion");
- const DisplayHardware& hw(graphicPlane(0).displayHardware());
- snprintf(buffer, SIZE,
- " orientation=%d, canDraw=%d\n",
- mCurrentState.orientation, hw.canDraw());
- result.append(buffer);
- snprintf(buffer, SIZE,
- " last eglSwapBuffers() time: %f us\n"
- " last transaction time : %f us\n"
- " refresh-rate : %f fps\n"
- " x-dpi : %f\n"
- " y-dpi : %f\n",
- mLastSwapBufferTime/1000.0,
- mLastTransactionTime/1000.0,
- hw.getRefreshRate(),
- hw.getDpiX(),
- hw.getDpiY());
- result.append(buffer);
-
- if (inSwapBuffersDuration || !locked) {
- snprintf(buffer, SIZE, " eglSwapBuffers time: %f us\n",
- inSwapBuffersDuration/1000.0);
- result.append(buffer);
- }
-
- if (inTransactionDuration || !locked) {
- snprintf(buffer, SIZE, " transaction time: %f us\n",
- inTransactionDuration/1000.0);
- result.append(buffer);
- }
-
- /*
- * VSYNC state
- */
- mEventThread->dump(result, buffer, SIZE);
-
- /*
- * Dump HWComposer state
- */
- HWComposer& hwc(hw.getHwComposer());
- snprintf(buffer, SIZE, "h/w composer state:\n");
- result.append(buffer);
- snprintf(buffer, SIZE, " h/w composer %s and %s\n",
- hwc.initCheck()==NO_ERROR ? "present" : "not present",
- (mDebugDisableHWC || mDebugRegion) ? "disabled" : "enabled");
- result.append(buffer);
- hwc.dump(result, buffer, SIZE, mVisibleLayersSortedByZ);
-
- /*
- * Dump gralloc state
- */
- const GraphicBufferAllocator& alloc(GraphicBufferAllocator::get());
- alloc.dump(result);
- hw.dump(result);
-
if (locked) {
mStateLock.unlock();
}
@@ -1599,6 +1532,168 @@
return NO_ERROR;
}
+void SurfaceFlinger::listLayersLocked(const Vector<String16>& args, size_t& index,
+ String8& result, char* buffer, size_t SIZE) const
+{
+ const LayerVector& currentLayers = mCurrentState.layersSortedByZ;
+ const size_t count = currentLayers.size();
+ for (size_t i=0 ; i<count ; i++) {
+ const sp<LayerBase>& layer(currentLayers[i]);
+ snprintf(buffer, SIZE, "%s\n", layer->getName().string());
+ result.append(buffer);
+ }
+}
+
+void SurfaceFlinger::dumpStatsLocked(const Vector<String16>& args, size_t& index,
+ String8& result, char* buffer, size_t SIZE) const
+{
+ String8 name;
+ if (index < args.size()) {
+ name = String8(args[index]);
+ index++;
+ }
+
+ const LayerVector& currentLayers = mCurrentState.layersSortedByZ;
+ const size_t count = currentLayers.size();
+ for (size_t i=0 ; i<count ; i++) {
+ const sp<LayerBase>& layer(currentLayers[i]);
+ if (name.isEmpty()) {
+ snprintf(buffer, SIZE, "%s\n", layer->getName().string());
+ result.append(buffer);
+ }
+ if (name.isEmpty() || (name == layer->getName())) {
+ layer->dumpStats(result, buffer, SIZE);
+ }
+ }
+}
+
+void SurfaceFlinger::clearStatsLocked(const Vector<String16>& args, size_t& index,
+ String8& result, char* buffer, size_t SIZE) const
+{
+ String8 name;
+ if (index < args.size()) {
+ name = String8(args[index]);
+ index++;
+ }
+
+ const LayerVector& currentLayers = mCurrentState.layersSortedByZ;
+ const size_t count = currentLayers.size();
+ for (size_t i=0 ; i<count ; i++) {
+ const sp<LayerBase>& layer(currentLayers[i]);
+ if (name.isEmpty() || (name == layer->getName())) {
+ layer->clearStats();
+ }
+ }
+}
+
+void SurfaceFlinger::dumpAllLocked(
+ String8& result, char* buffer, size_t SIZE) const
+{
+ // figure out if we're stuck somewhere
+ const nsecs_t now = systemTime();
+ const nsecs_t inSwapBuffers(mDebugInSwapBuffers);
+ const nsecs_t inTransaction(mDebugInTransaction);
+ nsecs_t inSwapBuffersDuration = (inSwapBuffers) ? now-inSwapBuffers : 0;
+ nsecs_t inTransactionDuration = (inTransaction) ? now-inTransaction : 0;
+
+ /*
+ * Dump the visible layer list
+ */
+ const LayerVector& currentLayers = mCurrentState.layersSortedByZ;
+ const size_t count = currentLayers.size();
+ snprintf(buffer, SIZE, "Visible layers (count = %d)\n", count);
+ result.append(buffer);
+ for (size_t i=0 ; i<count ; i++) {
+ const sp<LayerBase>& layer(currentLayers[i]);
+ layer->dump(result, buffer, SIZE);
+ }
+
+ /*
+ * Dump the layers in the purgatory
+ */
+
+ const size_t purgatorySize = mLayerPurgatory.size();
+ snprintf(buffer, SIZE, "Purgatory state (%d entries)\n", purgatorySize);
+ result.append(buffer);
+ for (size_t i=0 ; i<purgatorySize ; i++) {
+ const sp<LayerBase>& layer(mLayerPurgatory.itemAt(i));
+ layer->shortDump(result, buffer, SIZE);
+ }
+
+ /*
+ * Dump SurfaceFlinger global state
+ */
+
+ snprintf(buffer, SIZE, "SurfaceFlinger global state:\n");
+ result.append(buffer);
+
+ const GLExtensions& extensions(GLExtensions::getInstance());
+ snprintf(buffer, SIZE, "GLES: %s, %s, %s\n",
+ extensions.getVendor(),
+ extensions.getRenderer(),
+ extensions.getVersion());
+ result.append(buffer);
+
+ snprintf(buffer, SIZE, "EGL : %s\n",
+ eglQueryString(graphicPlane(0).getEGLDisplay(),
+ EGL_VERSION_HW_ANDROID));
+ result.append(buffer);
+
+ snprintf(buffer, SIZE, "EXTS: %s\n", extensions.getExtension());
+ result.append(buffer);
+
+ mWormholeRegion.dump(result, "WormholeRegion");
+ const DisplayHardware& hw(graphicPlane(0).displayHardware());
+ snprintf(buffer, SIZE,
+ " orientation=%d, canDraw=%d\n",
+ mCurrentState.orientation, hw.canDraw());
+ result.append(buffer);
+ snprintf(buffer, SIZE,
+ " last eglSwapBuffers() time: %f us\n"
+ " last transaction time : %f us\n"
+ " refresh-rate : %f fps\n"
+ " x-dpi : %f\n"
+ " y-dpi : %f\n",
+ mLastSwapBufferTime/1000.0,
+ mLastTransactionTime/1000.0,
+ hw.getRefreshRate(),
+ hw.getDpiX(),
+ hw.getDpiY());
+ result.append(buffer);
+
+ snprintf(buffer, SIZE, " eglSwapBuffers time: %f us\n",
+ inSwapBuffersDuration/1000.0);
+ result.append(buffer);
+
+ snprintf(buffer, SIZE, " transaction time: %f us\n",
+ inTransactionDuration/1000.0);
+ result.append(buffer);
+
+ /*
+ * VSYNC state
+ */
+ mEventThread->dump(result, buffer, SIZE);
+
+ /*
+ * Dump HWComposer state
+ */
+ HWComposer& hwc(hw.getHwComposer());
+ snprintf(buffer, SIZE, "h/w composer state:\n");
+ result.append(buffer);
+ snprintf(buffer, SIZE, " h/w composer %s and %s\n",
+ hwc.initCheck()==NO_ERROR ? "present" : "not present",
+ (mDebugDisableHWC || mDebugRegion) ? "disabled" : "enabled");
+ result.append(buffer);
+ hwc.dump(result, buffer, SIZE, mVisibleLayersSortedByZ);
+
+ /*
+ * Dump gralloc state
+ */
+ const GraphicBufferAllocator& alloc(GraphicBufferAllocator::get());
+ alloc.dump(result);
+ hw.dump(result);
+}
+
status_t SurfaceFlinger::onTransact(
uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
{
@@ -1705,7 +1800,7 @@
const DisplayHardware& hw(graphicPlane(0).displayHardware());
const Rect bounds(hw.getBounds());
setInvalidateRegion(Region(bounds));
- signalEvent();
+ signalTransaction();
}
void SurfaceFlinger::setInvalidateRegion(const Region& reg) {
@@ -2181,7 +2276,7 @@
// make sure to redraw the whole screen when the animation is done
mDirtyRegion.set(hw.bounds());
- signalEvent();
+ signalTransaction();
return NO_ERROR;
}
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index 7f6c90c..fcd9361 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -170,7 +170,6 @@
virtual void bootFinished();
virtual void setTransactionState(const Vector<ComposerState>& state,
int orientation, uint32_t flags);
- virtual int setOrientation(DisplayID dpy, int orientation, uint32_t flags);
virtual bool authenticateSurfaceTexture(const sp<ISurfaceTexture>& surface) const;
virtual sp<IDisplayEventConnection> createDisplayEventConnection();
@@ -191,6 +190,8 @@
status_t renderScreenToTextureLocked(DisplayID dpy,
GLuint* textureName, GLfloat* uOut, GLfloat* vOut);
+ void onMessageReceived(int32_t what);
+
status_t postMessageAsync(const sp<MessageBase>& msg,
nsecs_t reltime=0, uint32_t flags = 0);
@@ -284,7 +285,10 @@
public: // hack to work around gcc 4.0.3 bug
const GraphicPlane& graphicPlane(int dpy) const;
GraphicPlane& graphicPlane(int dpy);
- void signalEvent();
+
+ void signalTransaction();
+ void signalLayerUpdate();
+ void signalRefresh();
void repaintEverything();
private:
@@ -301,6 +305,7 @@
void handlePageFlip();
bool lockPageFlip(const LayerVector& currentLayers);
void unlockPageFlip(const LayerVector& currentLayers);
+ void handleRefresh();
void handleWorkList();
void handleRepaint();
void postFramebuffer();
@@ -337,6 +342,13 @@
void debugFlashRegions();
void drawWormhole() const;
+ void listLayersLocked(const Vector<String16>& args, size_t& index,
+ String8& result, char* buffer, size_t SIZE) const;
+ void dumpStatsLocked(const Vector<String16>& args, size_t& index,
+ String8& result, char* buffer, size_t SIZE) const;
+ void clearStatsLocked(const Vector<String16>& args, size_t& index,
+ String8& result, char* buffer, size_t SIZE) const;
+ void dumpAllLocked(String8& result, char* buffer, size_t SIZE) const;
mutable MessageQueue mEventQueue;
diff --git a/services/surfaceflinger/SurfaceTextureLayer.cpp b/services/surfaceflinger/SurfaceTextureLayer.cpp
index 259b937..49e8e63 100644
--- a/services/surfaceflinger/SurfaceTextureLayer.cpp
+++ b/services/surfaceflinger/SurfaceTextureLayer.cpp
@@ -94,6 +94,10 @@
*outTransform = orientation;
}
switch(api) {
+ case NATIVE_WINDOW_API_CPU:
+ // SurfaceTextureClient supports only 2 buffers for CPU connections
+ this->setBufferCountServer(2);
+ break;
case NATIVE_WINDOW_API_MEDIA:
case NATIVE_WINDOW_API_CAMERA:
// Camera preview and videos are rate-limited on the producer
diff --git a/services/surfaceflinger/tests/vsync/vsync.cpp b/services/surfaceflinger/tests/vsync/vsync.cpp
index 4f79080..b0d54c4 100644
--- a/services/surfaceflinger/tests/vsync/vsync.cpp
+++ b/services/surfaceflinger/tests/vsync/vsync.cpp
@@ -55,6 +55,8 @@
loop->addFd(myDisplayEvent.getFd(), 0, ALOOPER_EVENT_INPUT, receiver,
&myDisplayEvent);
+ myDisplayEvent.setVsyncRate(1);
+
do {
//printf("about to poll...\n");
int32_t ret = loop->pollOnce(-1);
diff --git a/services/tests/servicestests/res/raw/netstats_uid_v4 b/services/tests/servicestests/res/raw/netstats_uid_v4
new file mode 100644
index 0000000..e75fc1c
--- /dev/null
+++ b/services/tests/servicestests/res/raw/netstats_uid_v4
Binary files differ
diff --git a/services/tests/servicestests/res/raw/netstats_v1 b/services/tests/servicestests/res/raw/netstats_v1
new file mode 100644
index 0000000..e80860a
--- /dev/null
+++ b/services/tests/servicestests/res/raw/netstats_v1
Binary files differ
diff --git a/services/tests/servicestests/src/com/android/server/NetworkPolicyManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/NetworkPolicyManagerServiceTest.java
index 36a2567..2bf8b1c 100644
--- a/services/tests/servicestests/src/com/android/server/NetworkPolicyManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/NetworkPolicyManagerServiceTest.java
@@ -21,7 +21,6 @@
import static android.net.ConnectivityManager.CONNECTIVITY_ACTION_IMMEDIATE;
import static android.net.ConnectivityManager.TYPE_WIFI;
import static android.net.NetworkPolicy.LIMIT_DISABLED;
-import static android.net.NetworkPolicy.SNOOZE_NEVER;
import static android.net.NetworkPolicy.WARNING_DISABLED;
import static android.net.NetworkPolicyManager.POLICY_NONE;
import static android.net.NetworkPolicyManager.POLICY_REJECT_METERED_BACKGROUND;
@@ -256,41 +255,49 @@
}
public void testPidForegroundCombined() throws Exception {
+ IdleFuture idle;
+
// push all uid into background
+ idle = expectIdle();
mProcessObserver.onForegroundActivitiesChanged(PID_1, UID_A, false);
mProcessObserver.onForegroundActivitiesChanged(PID_2, UID_A, false);
mProcessObserver.onForegroundActivitiesChanged(PID_3, UID_B, false);
- waitUntilIdle();
+ idle.get();
assertFalse(mService.isUidForeground(UID_A));
assertFalse(mService.isUidForeground(UID_B));
// push one of the shared pids into foreground
+ idle = expectIdle();
mProcessObserver.onForegroundActivitiesChanged(PID_2, UID_A, true);
- waitUntilIdle();
+ idle.get();
assertTrue(mService.isUidForeground(UID_A));
assertFalse(mService.isUidForeground(UID_B));
// and swap another uid into foreground
+ idle = expectIdle();
mProcessObserver.onForegroundActivitiesChanged(PID_2, UID_A, false);
mProcessObserver.onForegroundActivitiesChanged(PID_3, UID_B, true);
- waitUntilIdle();
+ idle.get();
assertFalse(mService.isUidForeground(UID_A));
assertTrue(mService.isUidForeground(UID_B));
// push both pid into foreground
+ idle = expectIdle();
mProcessObserver.onForegroundActivitiesChanged(PID_1, UID_A, true);
mProcessObserver.onForegroundActivitiesChanged(PID_2, UID_A, true);
- waitUntilIdle();
+ idle.get();
assertTrue(mService.isUidForeground(UID_A));
// pull one out, should still be foreground
+ idle = expectIdle();
mProcessObserver.onForegroundActivitiesChanged(PID_1, UID_A, false);
- waitUntilIdle();
+ idle.get();
assertTrue(mService.isUidForeground(UID_A));
// pull final pid out, should now be background
+ idle = expectIdle();
mProcessObserver.onForegroundActivitiesChanged(PID_2, UID_A, false);
- waitUntilIdle();
+ idle.get();
assertFalse(mService.isUidForeground(UID_A));
}
@@ -434,7 +441,7 @@
final long expectedCycle = parseTime("2007-11-05T00:00:00.000Z");
final NetworkPolicy policy = new NetworkPolicy(
- sTemplateWifi, 5, 1024L, 1024L, SNOOZE_NEVER, false);
+ sTemplateWifi, 5, 1024L, 1024L, false);
final long actualCycle = computeLastCycleBoundary(currentTime, policy);
assertTimeEquals(expectedCycle, actualCycle);
}
@@ -445,7 +452,7 @@
final long expectedCycle = parseTime("2007-10-20T00:00:00.000Z");
final NetworkPolicy policy = new NetworkPolicy(
- sTemplateWifi, 20, 1024L, 1024L, SNOOZE_NEVER, false);
+ sTemplateWifi, 20, 1024L, 1024L, false);
final long actualCycle = computeLastCycleBoundary(currentTime, policy);
assertTimeEquals(expectedCycle, actualCycle);
}
@@ -456,7 +463,7 @@
final long expectedCycle = parseTime("2007-01-30T00:00:00.000Z");
final NetworkPolicy policy = new NetworkPolicy(
- sTemplateWifi, 30, 1024L, 1024L, SNOOZE_NEVER, false);
+ sTemplateWifi, 30, 1024L, 1024L, false);
final long actualCycle = computeLastCycleBoundary(currentTime, policy);
assertTimeEquals(expectedCycle, actualCycle);
}
@@ -467,14 +474,14 @@
final long expectedCycle = parseTime("2007-02-28T23:59:59.000Z");
final NetworkPolicy policy = new NetworkPolicy(
- sTemplateWifi, 30, 1024L, 1024L, SNOOZE_NEVER, false);
+ sTemplateWifi, 30, 1024L, 1024L, false);
final long actualCycle = computeLastCycleBoundary(currentTime, policy);
assertTimeEquals(expectedCycle, actualCycle);
}
public void testNextCycleSane() throws Exception {
final NetworkPolicy policy = new NetworkPolicy(
- sTemplateWifi, 31, WARNING_DISABLED, LIMIT_DISABLED, SNOOZE_NEVER, false);
+ sTemplateWifi, 31, WARNING_DISABLED, LIMIT_DISABLED, false);
final LinkedHashSet<Long> seen = new LinkedHashSet<Long>();
// walk forwards, ensuring that cycle boundaries don't get stuck
@@ -489,7 +496,7 @@
public void testLastCycleSane() throws Exception {
final NetworkPolicy policy = new NetworkPolicy(
- sTemplateWifi, 31, WARNING_DISABLED, LIMIT_DISABLED, SNOOZE_NEVER, false);
+ sTemplateWifi, 31, WARNING_DISABLED, LIMIT_DISABLED, false);
final LinkedHashSet<Long> seen = new LinkedHashSet<Long>();
// walk backwards, ensuring that cycle boundaries look sane
@@ -547,7 +554,7 @@
replay();
setNetworkPolicies(new NetworkPolicy(
- sTemplateWifi, CYCLE_DAY, 1 * MB_IN_BYTES, 2 * MB_IN_BYTES, SNOOZE_NEVER, false));
+ sTemplateWifi, CYCLE_DAY, 1 * MB_IN_BYTES, 2 * MB_IN_BYTES, false));
future.get();
verifyAndReset();
}
@@ -604,9 +611,8 @@
future = expectMeteredIfacesChanged();
replay();
- setNetworkPolicies(
- new NetworkPolicy(sTemplateWifi, CYCLE_DAY, 1 * MB_IN_BYTES, 2 * MB_IN_BYTES,
- SNOOZE_NEVER, false));
+ setNetworkPolicies(new NetworkPolicy(sTemplateWifi, CYCLE_DAY, 1 * MB_IN_BYTES,
+ 2 * MB_IN_BYTES, false));
future.get();
verifyAndReset();
}
@@ -698,7 +704,7 @@
tagFuture = expectEnqueueNotification();
replay();
- mService.snoozePolicy(sTemplateWifi);
+ mService.snoozeLimit(sTemplateWifi);
assertNotificationType(TYPE_LIMIT_SNOOZED, tagFuture.get());
future.get();
verifyAndReset();
@@ -736,9 +742,8 @@
future = expectMeteredIfacesChanged(TEST_IFACE);
replay();
- setNetworkPolicies(
- new NetworkPolicy(sTemplateWifi, CYCLE_DAY, WARNING_DISABLED, LIMIT_DISABLED,
- SNOOZE_NEVER, true));
+ setNetworkPolicies(new NetworkPolicy(sTemplateWifi, CYCLE_DAY, WARNING_DISABLED,
+ LIMIT_DISABLED, true));
future.get();
verifyAndReset();
}
@@ -890,10 +895,10 @@
/**
* Wait until {@link #mService} internal {@link Handler} is idle.
*/
- private void waitUntilIdle() throws Exception {
+ private IdleFuture expectIdle() {
final IdleFuture future = new IdleFuture();
mService.addIdleHandler(future);
- future.get();
+ return future;
}
private static void assertTimeEquals(long expected, long actual) {
diff --git a/services/tests/servicestests/src/com/android/server/NetworkStatsServiceTest.java b/services/tests/servicestests/src/com/android/server/NetworkStatsServiceTest.java
index 90b5a2e..8f5e77e 100644
--- a/services/tests/servicestests/src/com/android/server/NetworkStatsServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/NetworkStatsServiceTest.java
@@ -39,6 +39,7 @@
import static android.text.format.DateUtils.WEEK_IN_MILLIS;
import static com.android.server.net.NetworkStatsService.ACTION_NETWORK_STATS_POLL;
import static org.easymock.EasyMock.anyLong;
+import static org.easymock.EasyMock.aryEq;
import static org.easymock.EasyMock.capture;
import static org.easymock.EasyMock.createMock;
import static org.easymock.EasyMock.eq;
@@ -63,10 +64,12 @@
import android.telephony.TelephonyManager;
import android.test.AndroidTestCase;
import android.test.suitebuilder.annotation.LargeTest;
+import android.test.suitebuilder.annotation.Suppress;
import android.util.TrustedTime;
import com.android.server.net.NetworkStatsService;
import com.android.server.net.NetworkStatsService.NetworkStatsSettings;
+import com.android.server.net.NetworkStatsService.NetworkStatsSettings.Config;
import org.easymock.Capture;
import org.easymock.EasyMock;
@@ -89,6 +92,10 @@
private static final String IMSI_1 = "310004";
private static final String IMSI_2 = "310260";
+ private static final long KB_IN_BYTES = 1024;
+ private static final long MB_IN_BYTES = 1024 * KB_IN_BYTES;
+ private static final long GB_IN_BYTES = 1024 * MB_IN_BYTES;
+
private static NetworkTemplate sTemplateWifi = buildTemplateWifi();
private static NetworkTemplate sTemplateImsi1 = buildTemplateMobileAll(IMSI_1);
private static NetworkTemplate sTemplateImsi2 = buildTemplateMobileAll(IMSI_2);
@@ -282,13 +289,6 @@
mServiceContext.sendBroadcast(new Intent(Intent.ACTION_SHUTDOWN));
verifyAndReset();
- // talk with zombie service to assert stats have gone; and assert that
- // we persisted them to file.
- expectDefaultSettings();
- replay();
- assertNetworkTotal(sTemplateWifi, 0L, 0L, 0L, 0L, 0);
- verifyAndReset();
-
assertStatsFilesExist(true);
// boot through serviceReady() again
@@ -319,6 +319,8 @@
}
+ // TODO: simulate reboot to test bucket resize
+ @Suppress
public void testStatsBucketResize() throws Exception {
NetworkStatsHistory history = null;
@@ -602,7 +604,6 @@
assertUidTotal(sTemplateImsi1, UID_RED, 1536L, 12L, 1280L, 10L, 10);
verifyAndReset();
-
}
public void testSummaryForAllUid() throws Exception {
@@ -755,11 +756,15 @@
expectDefaultSettings();
expectNetworkStatsSummary(new NetworkStats(getElapsedRealtime(), 1)
.addIfaceValues(TEST_IFACE, 2048L, 16L, 512L, 4L));
- expectNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 1)
- .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, 128L, 2L, 128L, 2L, 0L));
+
+ final NetworkStats uidStats = new NetworkStats(getElapsedRealtime(), 1)
+ .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, 128L, 2L, 128L, 2L, 0L);
final String[] tetherIfacePairs = new String[] { TEST_IFACE, "wlan0" };
- expectNetworkStatsPoll(tetherIfacePairs, new NetworkStats(getElapsedRealtime(), 1)
- .addValues(TEST_IFACE, UID_TETHERING, SET_DEFAULT, TAG_NONE, 1920L, 14L, 384L, 2L, 0L));
+ final NetworkStats tetherStats = new NetworkStats(getElapsedRealtime(), 1)
+ .addValues(TEST_IFACE, UID_TETHERING, SET_DEFAULT, TAG_NONE, 1920L, 14L, 384L, 2L, 0L);
+
+ expectNetworkStatsUidDetail(uidStats, tetherIfacePairs, tetherStats);
+ expectNetworkStatsPoll();
replay();
mServiceContext.sendBroadcast(new Intent(ACTION_NETWORK_STATS_POLL));
@@ -808,6 +813,9 @@
private void expectNetworkState(NetworkState... state) throws Exception {
expect(mConnManager.getAllNetworkState()).andReturn(state).atLeastOnce();
+
+ final LinkProperties linkProp = state.length > 0 ? state[0].linkProperties : null;
+ expect(mConnManager.getActiveLinkProperties()).andReturn(linkProp).atLeastOnce();
}
private void expectNetworkStatsSummary(NetworkStats summary) throws Exception {
@@ -815,23 +823,35 @@
}
private void expectNetworkStatsUidDetail(NetworkStats detail) throws Exception {
+ expectNetworkStatsUidDetail(detail, new String[0], new NetworkStats(0L, 0));
+ }
+
+ private void expectNetworkStatsUidDetail(
+ NetworkStats detail, String[] tetherIfacePairs, NetworkStats tetherStats)
+ throws Exception {
expect(mNetManager.getNetworkStatsUidDetail(eq(UID_ALL))).andReturn(detail).atLeastOnce();
+
+ // also include tethering details, since they are folded into UID
+ expect(mConnManager.getTetheredIfacePairs()).andReturn(tetherIfacePairs).atLeastOnce();
+ expect(mNetManager.getNetworkStatsTethering(aryEq(tetherIfacePairs)))
+ .andReturn(tetherStats).atLeastOnce();
}
private void expectDefaultSettings() throws Exception {
expectSettings(0L, HOUR_IN_MILLIS, WEEK_IN_MILLIS);
}
- private void expectSettings(long persistThreshold, long bucketDuration, long maxHistory)
+ private void expectSettings(long persistBytes, long bucketDuration, long deleteAge)
throws Exception {
expect(mSettings.getPollInterval()).andReturn(HOUR_IN_MILLIS).anyTimes();
- expect(mSettings.getPersistThreshold()).andReturn(persistThreshold).anyTimes();
- expect(mSettings.getNetworkBucketDuration()).andReturn(bucketDuration).anyTimes();
- expect(mSettings.getNetworkMaxHistory()).andReturn(maxHistory).anyTimes();
- expect(mSettings.getUidBucketDuration()).andReturn(bucketDuration).anyTimes();
- expect(mSettings.getUidMaxHistory()).andReturn(maxHistory).anyTimes();
- expect(mSettings.getTagMaxHistory()).andReturn(maxHistory).anyTimes();
expect(mSettings.getTimeCacheMaxAge()).andReturn(DAY_IN_MILLIS).anyTimes();
+ expect(mSettings.getGlobalAlertBytes()).andReturn(MB_IN_BYTES).anyTimes();
+ expect(mSettings.getSampleEnabled()).andReturn(true).anyTimes();
+
+ final Config config = new Config(bucketDuration, persistBytes, deleteAge, deleteAge);
+ expect(mSettings.getDevConfig()).andReturn(config).anyTimes();
+ expect(mSettings.getUidConfig()).andReturn(config).anyTimes();
+ expect(mSettings.getUidTagConfig()).andReturn(config).anyTimes();
}
private void expectCurrentTime() throws Exception {
@@ -843,27 +863,16 @@
}
private void expectNetworkStatsPoll() throws Exception {
- expectNetworkStatsPoll(new String[0], new NetworkStats(getElapsedRealtime(), 0));
- }
-
- private void expectNetworkStatsPoll(String[] tetherIfacePairs, NetworkStats tetherStats)
- throws Exception {
mNetManager.setGlobalAlert(anyLong());
expectLastCall().anyTimes();
- expect(mConnManager.getTetheredIfacePairs()).andReturn(tetherIfacePairs).anyTimes();
- expect(mNetManager.getNetworkStatsTethering(eq(tetherIfacePairs)))
- .andReturn(tetherStats).anyTimes();
}
private void assertStatsFilesExist(boolean exist) {
- final File networkFile = new File(mStatsDir, "netstats.bin");
- final File uidFile = new File(mStatsDir, "netstats_uid.bin");
+ final File basePath = new File(mStatsDir, "netstats");
if (exist) {
- assertTrue(networkFile.exists());
- assertTrue(uidFile.exists());
+ assertTrue(basePath.list().length > 0);
} else {
- assertFalse(networkFile.exists());
- assertFalse(uidFile.exists());
+ assertTrue(basePath.list().length == 0);
}
}
diff --git a/services/tests/servicestests/src/com/android/server/net/NetworkStatsCollectionTest.java b/services/tests/servicestests/src/com/android/server/net/NetworkStatsCollectionTest.java
new file mode 100644
index 0000000..7f05f56
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/net/NetworkStatsCollectionTest.java
@@ -0,0 +1,175 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.net;
+
+import static android.net.NetworkTemplate.buildTemplateMobileAll;
+import static android.text.format.DateUtils.MINUTE_IN_MILLIS;
+
+import android.content.res.Resources;
+import android.net.ConnectivityManager;
+import android.net.NetworkIdentity;
+import android.net.NetworkStats;
+import android.net.NetworkTemplate;
+import android.test.AndroidTestCase;
+import android.test.suitebuilder.annotation.MediumTest;
+
+import com.android.frameworks.servicestests.R;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.DataOutputStream;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.InputStream;
+import java.io.OutputStream;
+
+import libcore.io.IoUtils;
+import libcore.io.Streams;
+
+/**
+ * Tests for {@link NetworkStatsCollection}.
+ */
+@MediumTest
+public class NetworkStatsCollectionTest extends AndroidTestCase {
+
+ private static final String TEST_FILE = "test.bin";
+ private static final String TEST_IMSI = "310260000000000";
+
+ public void testReadLegacyNetwork() throws Exception {
+ final File testFile = new File(getContext().getFilesDir(), TEST_FILE);
+ stageFile(R.raw.netstats_v1, testFile);
+
+ final NetworkStatsCollection collection = new NetworkStatsCollection(30 * MINUTE_IN_MILLIS);
+ collection.readLegacyNetwork(testFile);
+
+ // verify that history read correctly
+ assertSummaryTotal(collection, buildTemplateMobileAll(TEST_IMSI),
+ 636014522L, 709291L, 88037144L, 518820L);
+
+ // now export into a unified format
+ final ByteArrayOutputStream bos = new ByteArrayOutputStream();
+ collection.write(new DataOutputStream(bos));
+
+ // clear structure completely
+ collection.reset();
+ assertSummaryTotal(collection, buildTemplateMobileAll(TEST_IMSI),
+ 0L, 0L, 0L, 0L);
+
+ // and read back into structure, verifying that totals are same
+ collection.read(new ByteArrayInputStream(bos.toByteArray()));
+ assertSummaryTotal(collection, buildTemplateMobileAll(TEST_IMSI),
+ 636014522L, 709291L, 88037144L, 518820L);
+ }
+
+ public void testReadLegacyUid() throws Exception {
+ final File testFile = new File(getContext().getFilesDir(), TEST_FILE);
+ stageFile(R.raw.netstats_uid_v4, testFile);
+
+ final NetworkStatsCollection collection = new NetworkStatsCollection(30 * MINUTE_IN_MILLIS);
+ collection.readLegacyUid(testFile, false);
+
+ // verify that history read correctly
+ assertSummaryTotal(collection, buildTemplateMobileAll(TEST_IMSI),
+ 637073904L, 711398L, 88342093L, 521006L);
+
+ // now export into a unified format
+ final ByteArrayOutputStream bos = new ByteArrayOutputStream();
+ collection.write(new DataOutputStream(bos));
+
+ // clear structure completely
+ collection.reset();
+ assertSummaryTotal(collection, buildTemplateMobileAll(TEST_IMSI),
+ 0L, 0L, 0L, 0L);
+
+ // and read back into structure, verifying that totals are same
+ collection.read(new ByteArrayInputStream(bos.toByteArray()));
+ assertSummaryTotal(collection, buildTemplateMobileAll(TEST_IMSI),
+ 637073904L, 711398L, 88342093L, 521006L);
+ }
+
+ public void testReadLegacyUidTags() throws Exception {
+ final File testFile = new File(getContext().getFilesDir(), TEST_FILE);
+ stageFile(R.raw.netstats_uid_v4, testFile);
+
+ final NetworkStatsCollection collection = new NetworkStatsCollection(30 * MINUTE_IN_MILLIS);
+ collection.readLegacyUid(testFile, true);
+
+ // verify that history read correctly
+ assertSummaryTotalIncludingTags(collection, buildTemplateMobileAll(TEST_IMSI),
+ 77017831L, 100995L, 35436758L, 92344L);
+
+ // now export into a unified format
+ final ByteArrayOutputStream bos = new ByteArrayOutputStream();
+ collection.write(new DataOutputStream(bos));
+
+ // clear structure completely
+ collection.reset();
+ assertSummaryTotalIncludingTags(collection, buildTemplateMobileAll(TEST_IMSI),
+ 0L, 0L, 0L, 0L);
+
+ // and read back into structure, verifying that totals are same
+ collection.read(new ByteArrayInputStream(bos.toByteArray()));
+ assertSummaryTotalIncludingTags(collection, buildTemplateMobileAll(TEST_IMSI),
+ 77017831L, 100995L, 35436758L, 92344L);
+ }
+
+ /**
+ * Copy a {@link Resources#openRawResource(int)} into {@link File} for
+ * testing purposes.
+ */
+ private void stageFile(int rawId, File file) throws Exception {
+ new File(file.getParent()).mkdirs();
+ InputStream in = null;
+ OutputStream out = null;
+ try {
+ in = getContext().getResources().openRawResource(rawId);
+ out = new FileOutputStream(file);
+ Streams.copy(in, out);
+ } finally {
+ IoUtils.closeQuietly(in);
+ IoUtils.closeQuietly(out);
+ }
+ }
+
+ public static NetworkIdentitySet buildWifiIdent() {
+ final NetworkIdentitySet set = new NetworkIdentitySet();
+ set.add(new NetworkIdentity(ConnectivityManager.TYPE_WIFI, 0, null, false));
+ return set;
+ }
+
+ private static void assertSummaryTotal(NetworkStatsCollection collection,
+ NetworkTemplate template, long rxBytes, long rxPackets, long txBytes, long txPackets) {
+ final NetworkStats.Entry entry = collection.getSummary(
+ template, Long.MIN_VALUE, Long.MAX_VALUE).getTotal(null);
+ assertEntry(entry, rxBytes, rxPackets, txBytes, txPackets);
+ }
+
+ private static void assertSummaryTotalIncludingTags(NetworkStatsCollection collection,
+ NetworkTemplate template, long rxBytes, long rxPackets, long txBytes, long txPackets) {
+ final NetworkStats.Entry entry = collection.getSummary(
+ template, Long.MIN_VALUE, Long.MAX_VALUE).getTotalIncludingTags(null);
+ assertEntry(entry, rxBytes, rxPackets, txBytes, txPackets);
+ }
+
+ private static void assertEntry(
+ NetworkStats.Entry entry, long rxBytes, long rxPackets, long txBytes, long txPackets) {
+ assertEquals("unexpected rxBytes", rxBytes, entry.rxBytes);
+ assertEquals("unexpected rxPackets", rxPackets, entry.rxPackets);
+ assertEquals("unexpected txBytes", txBytes, entry.txBytes);
+ assertEquals("unexpected txPackets", txPackets, entry.txPackets);
+ }
+}
diff --git a/telephony/java/android/telephony/SignalStrength.java b/telephony/java/android/telephony/SignalStrength.java
index 3128592..1a4b574 100644
--- a/telephony/java/android/telephony/SignalStrength.java
+++ b/telephony/java/android/telephony/SignalStrength.java
@@ -47,6 +47,9 @@
"none", "poor", "moderate", "good", "great"
};
+ /** @hide */
+ public static final int INVALID_SNR = 0x7FFFFFFF;
+
private int mGsmSignalStrength; // Valid values are (0-31, 99) as defined in TS 27.007 8.5
private int mGsmBitErrorRate; // bit error rate (0-7, 99) as defined in TS 27.007 8.5
private int mCdmaDbm; // This value is the RSSI value
@@ -96,7 +99,7 @@
mLteSignalStrength = -1;
mLteRsrp = -1;
mLteRsrq = -1;
- mLteRssnr = -1;
+ mLteRssnr = INVALID_SNR;
mLteCqi = -1;
isGsm = true;
}
@@ -136,7 +139,8 @@
int evdoDbm, int evdoEcio, int evdoSnr,
boolean gsm) {
this(gsmSignalStrength, gsmBitErrorRate, cdmaDbm, cdmaEcio,
- evdoDbm, evdoEcio, evdoSnr, -1, -1, -1, -1, -1, gsm);
+ evdoDbm, evdoEcio, evdoSnr, -1, -1,
+ -1, INVALID_SNR, -1, gsm);
}
/**
@@ -292,7 +296,7 @@
if ((mLteSignalStrength == -1)
&& (mLteRsrp == -1)
&& (mLteRsrq == -1)
- && (mLteRssnr == -1)
+ && (mLteRssnr == INVALID_SNR)
&& (mLteCqi == -1)) {
level = getGsmLevel();
} else {
@@ -327,7 +331,7 @@
if ((mLteSignalStrength == -1)
&& (mLteRsrp == -1)
&& (mLteRsrq == -1)
- && (mLteRssnr == -1)
+ && (mLteRssnr == INVALID_SNR)
&& (mLteCqi == -1)) {
asuLevel = getGsmAsuLevel();
} else {
@@ -363,7 +367,7 @@
if ((mLteSignalStrength == -1)
&& (mLteRsrp == -1)
&& (mLteRsrq == -1)
- && (mLteRssnr == -1)
+ && (mLteRssnr == INVALID_SNR)
&& (mLteCqi == -1)) {
dBm = getGsmDbm();
} else {
@@ -566,16 +570,31 @@
*/
public int getLteLevel() {
int levelLteRsrp = 0;
+ int levelLteRssnr = 0;
if (mLteRsrp == -1) levelLteRsrp = 0;
- else if (mLteRsrp >= -90) levelLteRsrp = SIGNAL_STRENGTH_GREAT;
- else if (mLteRsrp >= -100) levelLteRsrp = SIGNAL_STRENGTH_GOOD;
- else if (mLteRsrp >= -110) levelLteRsrp = SIGNAL_STRENGTH_MODERATE;
- else if (mLteRsrp >= -118) levelLteRsrp = SIGNAL_STRENGTH_POOR;
- else levelLteRsrp = 0;
+ else if (mLteRsrp >= -95) levelLteRsrp = SIGNAL_STRENGTH_GREAT;
+ else if (mLteRsrp >= -105) levelLteRsrp = SIGNAL_STRENGTH_GOOD;
+ else if (mLteRsrp >= -115) levelLteRsrp = SIGNAL_STRENGTH_MODERATE;
+ else levelLteRsrp = SIGNAL_STRENGTH_POOR;
- if (DBG) log("Lte level: "+levelLteRsrp);
- return levelLteRsrp;
+ if (mLteRssnr == INVALID_SNR) levelLteRssnr = 0;
+ else if (mLteRssnr >= 45) levelLteRssnr = SIGNAL_STRENGTH_GREAT;
+ else if (mLteRssnr >= 10) levelLteRssnr = SIGNAL_STRENGTH_GOOD;
+ else if (mLteRssnr >= -30) levelLteRssnr = SIGNAL_STRENGTH_MODERATE;
+ else levelLteRssnr = SIGNAL_STRENGTH_POOR;
+
+ int level;
+ if (mLteRsrp == -1)
+ level = levelLteRssnr;
+ else if (mLteRssnr == INVALID_SNR)
+ level = levelLteRsrp;
+ else
+ level = (levelLteRssnr < levelLteRsrp) ? levelLteRssnr : levelLteRsrp;
+
+ if (DBG) log("Lte rsrp level: "+levelLteRsrp
+ + " snr level: " + levelLteRssnr + " level: " + level);
+ return level;
}
/**
diff --git a/telephony/java/com/android/internal/telephony/CallManager.java b/telephony/java/com/android/internal/telephony/CallManager.java
index 3dd57ee..f825f31 100644
--- a/telephony/java/com/android/internal/telephony/CallManager.java
+++ b/telephony/java/com/android/internal/telephony/CallManager.java
@@ -373,10 +373,19 @@
AudioManager audioManager = (AudioManager)
context.getSystemService(Context.AUDIO_SERVICE);
- int mode = AudioManager.MODE_NORMAL;
+ // change the audio mode and request/abandon audio focus according to phone state,
+ // but only on audio mode transitions
switch (getState()) {
case RINGING:
- mode = AudioManager.MODE_RINGTONE;
+ if (audioManager.getMode() != AudioManager.MODE_RINGTONE) {
+ // only request audio focus if the ringtone is going to be heard
+ if (audioManager.getStreamVolume(AudioManager.STREAM_RING) > 0) {
+ if (VDBG) Log.d(LOG_TAG, "requestAudioFocus on STREAM_RING");
+ audioManager.requestAudioFocusForCall(AudioManager.STREAM_RING,
+ AudioManager.AUDIOFOCUS_GAIN_TRANSIENT);
+ }
+ audioManager.setMode(AudioManager.MODE_RINGTONE);
+ }
break;
case OFFHOOK:
Phone offhookPhone = getFgPhone();
@@ -386,18 +395,28 @@
offhookPhone = getBgPhone();
}
+ int newAudioMode = AudioManager.MODE_IN_CALL;
if (offhookPhone instanceof SipPhone) {
- // enable IN_COMMUNICATION audio mode for sipPhone
- mode = AudioManager.MODE_IN_COMMUNICATION;
- } else {
- // enable IN_CALL audio mode for telephony
- mode = AudioManager.MODE_IN_CALL;
+ // enable IN_COMMUNICATION audio mode instead for sipPhone
+ newAudioMode = AudioManager.MODE_IN_COMMUNICATION;
+ }
+ if (audioManager.getMode() != newAudioMode) {
+ // request audio focus before setting the new mode
+ if (VDBG) Log.d(LOG_TAG, "requestAudioFocus on STREAM_VOICE_CALL");
+ audioManager.requestAudioFocusForCall(AudioManager.STREAM_VOICE_CALL,
+ AudioManager.AUDIOFOCUS_GAIN_TRANSIENT);
+ audioManager.setMode(newAudioMode);
+ }
+ break;
+ case IDLE:
+ if (audioManager.getMode() != AudioManager.MODE_NORMAL) {
+ audioManager.setMode(AudioManager.MODE_NORMAL);
+ if (VDBG) Log.d(LOG_TAG, "abandonAudioFocus");
+ // abandon audio focus after the mode has been set back to normal
+ audioManager.abandonAudioFocusForCall();
}
break;
}
- // calling audioManager.setMode() multiple times in a short period of
- // time seems to break the audio recorder in in-call mode
- if (audioManager.getMode() != mode) audioManager.setMode(mode);
}
private Context getContext() {
diff --git a/telephony/java/com/android/internal/telephony/CommandsInterface.java b/telephony/java/com/android/internal/telephony/CommandsInterface.java
index ee39850..a0efab2 100644
--- a/telephony/java/com/android/internal/telephony/CommandsInterface.java
+++ b/telephony/java/com/android/internal/telephony/CommandsInterface.java
@@ -93,11 +93,6 @@
static final int USSD_MODE_NOTIFY = 0;
static final int USSD_MODE_REQUEST = 1;
- // SIM Refresh results, passed up from RIL.
- static final int SIM_REFRESH_FILE_UPDATED = 0; // Single file updated
- static final int SIM_REFRESH_INIT = 1; // SIM initialized; reload all
- static final int SIM_REFRESH_RESET = 2; // SIM reset; may be locked
-
// GSM SMS fail cause for acknowledgeLastIncomingSMS. From TS 23.040, 9.2.3.22.
static final int GSM_SMS_FAIL_CAUSE_MEMORY_CAPACITY_EXCEEDED = 0xD3;
static final int GSM_SMS_FAIL_CAUSE_USIM_APP_TOOLKIT_BUSY = 0xD4;
@@ -764,6 +759,15 @@
* retMsg.obj = AsyncResult ar
* ar.exception carries exception on failure
* ar.userObject contains the orignal value of result.obj
+ * ar.result is String containing IMSI on success
+ */
+ void getIMSIForApp(String aid, Message result);
+
+ /**
+ * returned message
+ * retMsg.obj = AsyncResult ar
+ * ar.exception carries exception on failure
+ * ar.userObject contains the orignal value of result.obj
* ar.result is String containing IMEI on success
*/
void getIMEI(Message result);
@@ -1055,6 +1059,14 @@
String data, String pin2, Message response);
/**
+ * parameters equivalent to 27.007 AT+CRSM command
+ * response.obj will be an AsyncResult
+ * response.obj.userObj will be a IccIoResult on success
+ */
+ void iccIOForApp (int command, int fileid, String path, int p1, int p2, int p3,
+ String data, String pin2, String aid, Message response);
+
+ /**
* (AsyncResult)response.obj).result is an int[] with element [0] set to
* 1 for "CLIP is provisioned", and 0 for "CLIP is not provisioned".
*
diff --git a/telephony/java/com/android/internal/telephony/DataConnection.java b/telephony/java/com/android/internal/telephony/DataConnection.java
index 1336818..d0e304f 100644
--- a/telephony/java/com/android/internal/telephony/DataConnection.java
+++ b/telephony/java/com/android/internal/telephony/DataConnection.java
@@ -328,8 +328,11 @@
String reason = null;
if (dp.onCompletedMsg != null) {
+ // Get ApnContext, but only valid on GSM devices this is a string on CDMA devices.
Message msg = dp.onCompletedMsg;
- alreadySent = (ApnContext)msg.obj;
+ if (msg.obj instanceof ApnContext) {
+ alreadySent = (ApnContext)msg.obj;
+ }
reason = dp.reason;
if (VDBG) {
log(String.format("msg=%s msg.obj=%s", msg.toString(),
diff --git a/telephony/java/com/android/internal/telephony/IccCard.java b/telephony/java/com/android/internal/telephony/IccCard.java
index f4308a0..a9ef762 100644
--- a/telephony/java/com/android/internal/telephony/IccCard.java
+++ b/telephony/java/com/android/internal/telephony/IccCard.java
@@ -48,7 +48,7 @@
protected String mLogTag;
protected boolean mDbg;
- private IccCardStatus mIccCardStatus = null;
+ protected IccCardStatus mIccCardStatus = null;
protected State mState = null;
private final Object mStateMonitor = new Object();
@@ -911,4 +911,24 @@
private void log(String msg) {
Log.d(mLogTag, "[IccCard] " + msg);
}
+
+ protected abstract int getCurrentApplicationIndex();
+
+ public String getAid() {
+ String aid = "";
+ int appIndex = getCurrentApplicationIndex();
+
+ if (appIndex >= 0 && appIndex < IccCardStatus.CARD_MAX_APPS) {
+ IccCardApplication app = mIccCardStatus.getApplication(appIndex);
+ if (app != null) {
+ aid = app.aid;
+ } else {
+ Log.e(mLogTag, "[IccCard] getAid: no current application index=" + appIndex);
+ }
+ } else {
+ Log.e(mLogTag, "[IccCard] getAid: Invalid Subscription Application index=" + appIndex);
+ }
+
+ return aid;
+ }
}
diff --git a/telephony/java/com/android/internal/telephony/IccCardStatus.java b/telephony/java/com/android/internal/telephony/IccCardStatus.java
index c751a21..a3bdd76 100644
--- a/telephony/java/com/android/internal/telephony/IccCardStatus.java
+++ b/telephony/java/com/android/internal/telephony/IccCardStatus.java
@@ -24,7 +24,7 @@
* {@hide}
*/
public class IccCardStatus {
- static final int CARD_MAX_APPS = 8;
+ public static final int CARD_MAX_APPS = 8;
public enum CardState {
CARDSTATE_ABSENT,
diff --git a/telephony/java/com/android/internal/telephony/IccFileHandler.java b/telephony/java/com/android/internal/telephony/IccFileHandler.java
index 93b9b79..380bfd1 100644
--- a/telephony/java/com/android/internal/telephony/IccFileHandler.java
+++ b/telephony/java/com/android/internal/telephony/IccFileHandler.java
@@ -145,8 +145,9 @@
= obtainMessage(EVENT_GET_RECORD_SIZE_DONE,
new LoadLinearFixedContext(fileid, recordNum, onLoaded));
- phone.mCM.iccIO(COMMAND_GET_RESPONSE, fileid, getEFPath(fileid),
- 0, 0, GET_RESPONSE_EF_SIZE_BYTES, null, null, response);
+ phone.mCM.iccIOForApp(COMMAND_GET_RESPONSE, fileid, getEFPath(fileid),
+ 0, 0, GET_RESPONSE_EF_SIZE_BYTES, null, null,
+ phone.getIccCard().getAid(), response);
}
/**
@@ -164,9 +165,10 @@
onLoaded));
// TODO(): Verify when path changes are done.
- phone.mCM.iccIO(COMMAND_GET_RESPONSE, IccConstants.EF_IMG, "img",
+ phone.mCM.iccIOForApp(COMMAND_GET_RESPONSE, IccConstants.EF_IMG, "img",
recordNum, READ_RECORD_MODE_ABSOLUTE,
- GET_RESPONSE_EF_IMG_SIZE_BYTES, null, null, response);
+ GET_RESPONSE_EF_IMG_SIZE_BYTES, null, null,
+ phone.getIccCard().getAid(), response);
}
/**
@@ -182,8 +184,9 @@
Message response
= obtainMessage(EVENT_GET_EF_LINEAR_RECORD_SIZE_DONE,
new LoadLinearFixedContext(fileid, onLoaded));
- phone.mCM.iccIO(COMMAND_GET_RESPONSE, fileid, getEFPath(fileid),
- 0, 0, GET_RESPONSE_EF_SIZE_BYTES, null, null, response);
+ phone.mCM.iccIOForApp(COMMAND_GET_RESPONSE, fileid, getEFPath(fileid),
+ 0, 0, GET_RESPONSE_EF_SIZE_BYTES, null, null, phone.getIccCard().getAid(),
+ response);
}
/**
@@ -199,8 +202,9 @@
Message response = obtainMessage(EVENT_GET_RECORD_SIZE_DONE,
new LoadLinearFixedContext(fileid,onLoaded));
- phone.mCM.iccIO(COMMAND_GET_RESPONSE, fileid, getEFPath(fileid),
- 0, 0, GET_RESPONSE_EF_SIZE_BYTES, null, null, response);
+ phone.mCM.iccIOForApp(COMMAND_GET_RESPONSE, fileid, getEFPath(fileid),
+ 0, 0, GET_RESPONSE_EF_SIZE_BYTES, null, null,
+ phone.getIccCard().getAid(), response);
}
/**
@@ -217,8 +221,9 @@
Message response = obtainMessage(EVENT_GET_BINARY_SIZE_DONE,
fileid, 0, onLoaded);
- phone.mCM.iccIO(COMMAND_GET_RESPONSE, fileid, getEFPath(fileid),
- 0, 0, GET_RESPONSE_EF_SIZE_BYTES, null, null, response);
+ phone.mCM.iccIOForApp(COMMAND_GET_RESPONSE, fileid, getEFPath(fileid),
+ 0, 0, GET_RESPONSE_EF_SIZE_BYTES, null, null,
+ phone.getIccCard().getAid(), response);
}
/**
@@ -236,8 +241,8 @@
Message response = obtainMessage(EVENT_READ_ICON_DONE, fileid, 0,
onLoaded);
- phone.mCM.iccIO(COMMAND_READ_BINARY, fileid, "img", highOffset, lowOffset,
- length, null, null, response);
+ phone.mCM.iccIOForApp(COMMAND_READ_BINARY, fileid, "img", highOffset, lowOffset,
+ length, null, null, phone.getIccCard().getAid(), response);
}
/**
@@ -251,9 +256,10 @@
*/
public void updateEFLinearFixed(int fileid, int recordNum, byte[] data,
String pin2, Message onComplete) {
- phone.mCM.iccIO(COMMAND_UPDATE_RECORD, fileid, getEFPath(fileid),
+ phone.mCM.iccIOForApp(COMMAND_UPDATE_RECORD, fileid, getEFPath(fileid),
recordNum, READ_RECORD_MODE_ABSOLUTE, data.length,
- IccUtils.bytesToHexString(data), pin2, onComplete);
+ IccUtils.bytesToHexString(data), pin2,
+ phone.getIccCard().getAid(), onComplete);
}
/**
@@ -262,9 +268,10 @@
* @param data must be exactly as long as the EF
*/
public void updateEFTransparent(int fileid, byte[] data, Message onComplete) {
- phone.mCM.iccIO(COMMAND_UPDATE_BINARY, fileid, getEFPath(fileid),
+ phone.mCM.iccIOForApp(COMMAND_UPDATE_BINARY, fileid, getEFPath(fileid),
0, 0, data.length,
- IccUtils.bytesToHexString(data), null, onComplete);
+ IccUtils.bytesToHexString(data), null,
+ phone.getIccCard().getAid(), onComplete);
}
@@ -395,10 +402,11 @@
lc.results = new ArrayList<byte[]>(lc.countRecords);
}
- phone.mCM.iccIO(COMMAND_READ_RECORD, lc.efid, getEFPath(lc.efid),
+ phone.mCM.iccIOForApp(COMMAND_READ_RECORD, lc.efid, getEFPath(lc.efid),
lc.recordNum,
READ_RECORD_MODE_ABSOLUTE,
lc.recordSize, null, null,
+ phone.getIccCard().getAid(),
obtainMessage(EVENT_READ_RECORD_DONE, lc));
break;
case EVENT_GET_BINARY_SIZE_DONE:
@@ -433,8 +441,9 @@
size = ((data[RESPONSE_DATA_FILE_SIZE_1] & 0xff) << 8)
+ (data[RESPONSE_DATA_FILE_SIZE_2] & 0xff);
- phone.mCM.iccIO(COMMAND_READ_BINARY, fileid, getEFPath(fileid),
+ phone.mCM.iccIOForApp(COMMAND_READ_BINARY, fileid, getEFPath(fileid),
0, 0, size, null, null,
+ phone.getIccCard().getAid(),
obtainMessage(EVENT_READ_BINARY_DONE,
fileid, 0, response));
break;
@@ -468,10 +477,11 @@
if (lc.recordNum > lc.countRecords) {
sendResult(response, lc.results, null);
} else {
- phone.mCM.iccIO(COMMAND_READ_RECORD, lc.efid, getEFPath(lc.efid),
+ phone.mCM.iccIOForApp(COMMAND_READ_RECORD, lc.efid, getEFPath(lc.efid),
lc.recordNum,
READ_RECORD_MODE_ABSOLUTE,
lc.recordSize, null, null,
+ phone.getIccCard().getAid(),
obtainMessage(EVENT_READ_RECORD_DONE, lc));
}
}
diff --git a/telephony/java/com/android/internal/telephony/IccRefreshResponse.java b/telephony/java/com/android/internal/telephony/IccRefreshResponse.java
new file mode 100644
index 0000000..6806703
--- /dev/null
+++ b/telephony/java/com/android/internal/telephony/IccRefreshResponse.java
@@ -0,0 +1,42 @@
+/*
+ * 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.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.telephony;
+
+/**
+ * See also RIL_SimRefresh in include/telephony/ril.h
+ *
+ * {@hide}
+ */
+
+public class IccRefreshResponse {
+
+ public static final int REFRESH_RESULT_FILE_UPDATE = 0; /* Single file was updated */
+ public static final int REFRESH_RESULT_INIT = 1; /* The Icc has been initialized */
+ public static final int REFRESH_RESULT_RESET = 2; /* The Icc was reset */
+
+ public int refreshResult; /* Sim Refresh result */
+ public int efId; /* EFID */
+ public String aid; /* null terminated string, e.g.,
+ from 0xA0, 0x00 -> 0x41,
+ 0x30, 0x30, 0x30 */
+ /* Example: a0000000871002f310ffff89080000ff */
+
+ @Override
+ public String toString() {
+ return "{" + refreshResult + ", " + aid +", " + efId + "}";
+ }
+}
diff --git a/telephony/java/com/android/internal/telephony/RIL.java b/telephony/java/com/android/internal/telephony/RIL.java
index 718a4fd..f587fe1 100644
--- a/telephony/java/com/android/internal/telephony/RIL.java
+++ b/telephony/java/com/android/internal/telephony/RIL.java
@@ -52,6 +52,7 @@
import com.android.internal.telephony.gsm.SuppServiceNotification;
import com.android.internal.telephony.cdma.CdmaCallWaitingNotification;
import com.android.internal.telephony.cdma.CdmaInformationRecords;
+import com.android.internal.telephony.IccRefreshResponse;
import java.io.ByteArrayInputStream;
import java.io.DataInputStream;
@@ -879,9 +880,19 @@
public void
getIMSI(Message result) {
+ getIMSIForApp(null, result);
+ }
+
+ public void
+ getIMSIForApp(String aid, Message result) {
RILRequest rr = RILRequest.obtain(RIL_REQUEST_GET_IMSI, result);
- if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest));
+ rr.mp.writeInt(1);
+ rr.mp.writeString(aid);
+
+ if (RILJ_LOGD) riljLog(rr.serialString() +
+ "> getIMSI: " + requestToString(rr.mRequest)
+ + " aid: " + aid);
send(rr);
}
@@ -1434,6 +1445,11 @@
public void
iccIO (int command, int fileid, String path, int p1, int p2, int p3,
String data, String pin2, Message result) {
+ iccIOForApp(command, fileid, path, p1, p2, p3, data, pin2, null, result);
+ }
+ public void
+ iccIOForApp (int command, int fileid, String path, int p1, int p2, int p3,
+ String data, String pin2, String aid, Message result) {
//Note: This RIL request has not been renamed to ICC,
// but this request is also valid for SIM and RUIM
RILRequest rr
@@ -1447,12 +1463,15 @@
rr.mp.writeInt(p3);
rr.mp.writeString(data);
rr.mp.writeString(pin2);
+ rr.mp.writeString(aid);
- if (RILJ_LOGD) riljLog(rr.serialString() + "> iccIO: " + requestToString(rr.mRequest)
+ if (RILJ_LOGD) riljLog(rr.serialString() + "> iccIO: "
+ + requestToString(rr.mRequest)
+ " 0x" + Integer.toHexString(command)
+ " 0x" + Integer.toHexString(fileid) + " "
+ " path: " + path + ","
- + p1 + "," + p2 + "," + p3);
+ + p1 + "," + p2 + "," + p3
+ + " aid: " + aid);
send(rr);
}
@@ -2419,7 +2438,7 @@
case RIL_UNSOL_STK_EVENT_NOTIFY: ret = responseString(p); break;
case RIL_UNSOL_STK_CALL_SETUP: ret = responseInts(p); break;
case RIL_UNSOL_SIM_SMS_STORAGE_FULL: ret = responseVoid(p); break;
- case RIL_UNSOL_SIM_REFRESH: ret = responseInts(p); break;
+ case RIL_UNSOL_SIM_REFRESH: ret = responseSimRefresh(p); break;
case RIL_UNSOL_CALL_RING: ret = responseCallRing(p); break;
case RIL_UNSOL_RESTRICTED_STATE_CHANGED: ret = responseInts(p); break;
case RIL_UNSOL_RESPONSE_SIM_STATUS_CHANGED: ret = responseVoid(p); break;
@@ -2976,6 +2995,16 @@
}
private Object
+ responseSimRefresh(Parcel p) {
+ IccRefreshResponse response = new IccRefreshResponse();
+
+ response.refreshResult = p.readInt();
+ response.efId = p.readInt();
+ response.aid = p.readString();
+ return response;
+ }
+
+ private Object
responseCallList(Parcel p) {
int num;
int voiceSettings;
diff --git a/telephony/java/com/android/internal/telephony/cat/BerTlv.java b/telephony/java/com/android/internal/telephony/cat/BerTlv.java
index 774bfa3..095e65b 100644
--- a/telephony/java/com/android/internal/telephony/cat/BerTlv.java
+++ b/telephony/java/com/android/internal/telephony/cat/BerTlv.java
@@ -81,12 +81,18 @@
temp = data[curIndex++] & 0xff;
if (temp < 0x80) {
throw new ResultException(
- ResultCode.CMD_DATA_NOT_UNDERSTOOD);
+ ResultCode.CMD_DATA_NOT_UNDERSTOOD,
+ "length < 0x80 length=" + Integer.toHexString(length) +
+ " curIndex=" + curIndex + " endIndex=" + endIndex);
+
}
length = temp;
} else {
throw new ResultException(
- ResultCode.CMD_DATA_NOT_UNDERSTOOD);
+ ResultCode.CMD_DATA_NOT_UNDERSTOOD,
+ "Expected first byte to be length or a length tag and < 0x81" +
+ " byte= " + Integer.toHexString(temp) + " curIndex=" + curIndex +
+ " endIndex=" + endIndex);
}
} else {
if (ComprehensionTlvTag.COMMAND_DETAILS.value() == (tag & ~0x80)) {
@@ -95,14 +101,18 @@
}
}
} catch (IndexOutOfBoundsException e) {
- throw new ResultException(ResultCode.REQUIRED_VALUES_MISSING);
+ throw new ResultException(ResultCode.REQUIRED_VALUES_MISSING,
+ "IndexOutOfBoundsException " +
+ " curIndex=" + curIndex + " endIndex=" + endIndex);
} catch (ResultException e) {
- throw new ResultException(ResultCode.CMD_DATA_NOT_UNDERSTOOD);
+ throw new ResultException(ResultCode.CMD_DATA_NOT_UNDERSTOOD, e.explanation());
}
/* COMPREHENSION-TLVs */
if (endIndex - curIndex < length) {
- throw new ResultException(ResultCode.CMD_DATA_NOT_UNDERSTOOD);
+ throw new ResultException(ResultCode.CMD_DATA_NOT_UNDERSTOOD,
+ "Command had extra data endIndex=" + endIndex + " curIndex=" + curIndex +
+ " length=" + length);
}
List<ComprehensionTlv> ctlvs = ComprehensionTlv.decodeMany(data,
diff --git a/telephony/java/com/android/internal/telephony/cat/CatService.java b/telephony/java/com/android/internal/telephony/cat/CatService.java
index 97fb73d..2b37072 100644
--- a/telephony/java/com/android/internal/telephony/cat/CatService.java
+++ b/telephony/java/com/android/internal/telephony/cat/CatService.java
@@ -427,11 +427,11 @@
}
break;
default:
- CatLog.d(this, "encodeOptionalTags() Unsupported Cmd:" + cmdDet.typeOfCommand);
+ CatLog.d(this, "encodeOptionalTags() Unsupported Cmd details=" + cmdDet);
break;
}
} else {
- CatLog.d(this, "encodeOptionalTags() bad Cmd:" + cmdDet.typeOfCommand);
+ CatLog.d(this, "encodeOptionalTags() bad Cmd details=" + cmdDet);
}
}
diff --git a/telephony/java/com/android/internal/telephony/cat/CommandDetails.java b/telephony/java/com/android/internal/telephony/cat/CommandDetails.java
index e3f0798..8579535 100644
--- a/telephony/java/com/android/internal/telephony/cat/CommandDetails.java
+++ b/telephony/java/com/android/internal/telephony/cat/CommandDetails.java
@@ -74,6 +74,14 @@
public int describeContents() {
return 0;
}
+
+ @Override
+ public String toString() {
+ return "CmdDetails: compRequired=" + compRequired +
+ " commandNumber=" + commandNumber +
+ " typeOfCommand=" + typeOfCommand +
+ " commandQualifier=" + commandQualifier;
+ }
}
class DeviceIdentities extends ValueObject {
diff --git a/telephony/java/com/android/internal/telephony/cat/CommandParams.java b/telephony/java/com/android/internal/telephony/cat/CommandParams.java
index 959c9e2..79f6ad2 100644
--- a/telephony/java/com/android/internal/telephony/cat/CommandParams.java
+++ b/telephony/java/com/android/internal/telephony/cat/CommandParams.java
@@ -34,6 +34,11 @@
}
boolean setIcon(Bitmap icon) { return true; }
+
+ @Override
+ public String toString() {
+ return cmdDet.toString();
+ }
}
class DisplayTextParams extends CommandParams {
diff --git a/telephony/java/com/android/internal/telephony/cat/CommandParamsFactory.java b/telephony/java/com/android/internal/telephony/cat/CommandParamsFactory.java
index 89c1329..a554012 100644
--- a/telephony/java/com/android/internal/telephony/cat/CommandParamsFactory.java
+++ b/telephony/java/com/android/internal/telephony/cat/CommandParamsFactory.java
@@ -83,7 +83,8 @@
try {
cmdDet = ValueParser.retrieveCommandDetails(ctlvCmdDet);
} catch (ResultException e) {
- CatLog.d(this, "Failed to procees command details");
+ CatLog.d(this,
+ "processCommandDetails: Failed to procees command details e=" + e);
}
}
}
@@ -178,6 +179,7 @@
return;
}
} catch (ResultException e) {
+ CatLog.d(this, "make: caught ResultException e=" + e);
mCmdParams = new CommandParams(cmdDet);
sendCmdParams(e.result());
return;
diff --git a/telephony/java/com/android/internal/telephony/cat/ComprehensionTlv.java b/telephony/java/com/android/internal/telephony/cat/ComprehensionTlv.java
index ab26d13..22cd5a4 100644
--- a/telephony/java/com/android/internal/telephony/cat/ComprehensionTlv.java
+++ b/telephony/java/com/android/internal/telephony/cat/ComprehensionTlv.java
@@ -16,6 +16,8 @@
package com.android.internal.telephony.cat;
+import android.util.Log;
+
import java.util.ArrayList;
import java.util.List;
@@ -94,7 +96,6 @@
startIndex = ctlv.mValueIndex + ctlv.mLength;
} else {
CatLog.d(LOG_TAG, "decodeMany: ctlv is null, stop decoding");
- items.clear();
break;
}
}
@@ -112,10 +113,10 @@
*/
public static ComprehensionTlv decode(byte[] data, int startIndex)
throws ResultException {
- try {
- int curIndex = startIndex;
- int endIndex = data.length;
+ int curIndex = startIndex;
+ int endIndex = data.length;
+ try {
/* tag */
int tag;
boolean cr; // Comprehension required flag
@@ -124,9 +125,11 @@
case 0:
case 0xff:
case 0x80:
- // for error handling
- // these one make exception while decoding the abnormal command.
- // (in case of Ghana MTN simcard , JDI simcard)
+ Log.d("CAT ", "decode: unexpected first tag byte=" + Integer.toHexString(temp) +
+ ", startIndex=" + startIndex + " curIndex=" + curIndex +
+ " endIndex=" + endIndex);
+ // Return null which will stop decoding, this has occurred
+ // with Ghana MTN simcard and JDI simcard.
return null;
case 0x7f: // tag is in three-byte format
@@ -153,7 +156,10 @@
length = data[curIndex++] & 0xff;
if (length < 0x80) {
throw new ResultException(
- ResultCode.CMD_DATA_NOT_UNDERSTOOD);
+ ResultCode.CMD_DATA_NOT_UNDERSTOOD,
+ "length < 0x80 length=" + Integer.toHexString(length) +
+ " startIndex=" + startIndex + " curIndex=" + curIndex +
+ " endIndex=" + endIndex);
}
} else if (temp == 0x82) {
length = ((data[curIndex] & 0xff) << 8)
@@ -161,7 +167,10 @@
curIndex += 2;
if (length < 0x100) {
throw new ResultException(
- ResultCode.CMD_DATA_NOT_UNDERSTOOD);
+ ResultCode.CMD_DATA_NOT_UNDERSTOOD,
+ "two byte length < 0x100 length=" + Integer.toHexString(length) +
+ " startIndex=" + startIndex + " curIndex=" + curIndex +
+ " endIndex=" + endIndex);
}
} else if (temp == 0x83) {
length = ((data[curIndex] & 0xff) << 16)
@@ -170,16 +179,25 @@
curIndex += 3;
if (length < 0x10000) {
throw new ResultException(
- ResultCode.CMD_DATA_NOT_UNDERSTOOD);
+ ResultCode.CMD_DATA_NOT_UNDERSTOOD,
+ "three byte length < 0x10000 length=0x" + Integer.toHexString(length) +
+ " startIndex=" + startIndex + " curIndex=" + curIndex +
+ " endIndex=" + endIndex);
}
} else {
- throw new ResultException(ResultCode.CMD_DATA_NOT_UNDERSTOOD);
+ throw new ResultException(ResultCode.CMD_DATA_NOT_UNDERSTOOD,
+ "Bad length modifer=" + temp +
+ " startIndex=" + startIndex + " curIndex=" + curIndex +
+ " endIndex=" + endIndex);
+
}
return new ComprehensionTlv(tag, cr, length, data, curIndex);
} catch (IndexOutOfBoundsException e) {
- throw new ResultException(ResultCode.CMD_DATA_NOT_UNDERSTOOD);
+ throw new ResultException(ResultCode.CMD_DATA_NOT_UNDERSTOOD,
+ "IndexOutOfBoundsException" + " startIndex=" + startIndex +
+ " curIndex=" + curIndex + " endIndex=" + endIndex);
}
}
}
diff --git a/telephony/java/com/android/internal/telephony/cat/ResultException.java b/telephony/java/com/android/internal/telephony/cat/ResultException.java
index 1c2cb63..84879c2 100644
--- a/telephony/java/com/android/internal/telephony/cat/ResultException.java
+++ b/telephony/java/com/android/internal/telephony/cat/ResultException.java
@@ -25,6 +25,7 @@
public class ResultException extends CatException {
private ResultCode mResult;
private int mAdditionalInfo;
+ private String mExplanation;
public ResultException(ResultCode result) {
super();
@@ -48,20 +49,30 @@
mResult = result;
mAdditionalInfo = -1;
+ mExplanation = "";
+ }
+
+ public ResultException(ResultCode result, String explanation) {
+ this(result);
+ mExplanation = explanation;
}
public ResultException(ResultCode result, int additionalInfo) {
- super();
+ this(result);
if (additionalInfo < 0) {
throw new AssertionError(
"Additional info must be greater than zero!");
}
- mResult = result;
mAdditionalInfo = additionalInfo;
}
+ public ResultException(ResultCode result, int additionalInfo, String explanation) {
+ this(result, additionalInfo);
+ mExplanation = explanation;
+ }
+
public ResultCode result() {
return mResult;
}
@@ -73,4 +84,14 @@
public int additionalInfo() {
return mAdditionalInfo;
}
+
+ public String explanation() {
+ return mExplanation;
+ }
+
+ @Override
+ public String toString() {
+ return "result=" + mResult + " additionalInfo=" + mAdditionalInfo +
+ " explantion=" + mExplanation;
+ }
}
diff --git a/telephony/java/com/android/internal/telephony/cat/RilMessageDecoder.java b/telephony/java/com/android/internal/telephony/cat/RilMessageDecoder.java
index 2a1f508..fb33a8e 100644
--- a/telephony/java/com/android/internal/telephony/cat/RilMessageDecoder.java
+++ b/telephony/java/com/android/internal/telephony/cat/RilMessageDecoder.java
@@ -162,6 +162,7 @@
decodingStarted = true;
} catch (ResultException e) {
// send to Service for proper RIL communication.
+ CatLog.d(this, "decodeMessageParams: caught ResultException e=" + e);
mCurrentRilMessage.mResCode = e.result();
sendCmdForExecution(mCurrentRilMessage);
decodingStarted = false;
diff --git a/telephony/java/com/android/internal/telephony/cdma/CdmaLteServiceStateTracker.java b/telephony/java/com/android/internal/telephony/cdma/CdmaLteServiceStateTracker.java
index 6b73cc5..7da23d0 100644
--- a/telephony/java/com/android/internal/telephony/cdma/CdmaLteServiceStateTracker.java
+++ b/telephony/java/com/android/internal/telephony/cdma/CdmaLteServiceStateTracker.java
@@ -124,7 +124,9 @@
@Override
protected void setSignalStrengthDefaultValues() {
- mSignalStrength = new SignalStrength(99, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, false);
+ // TODO Make a constructor only has boolean gsm as parameter
+ mSignalStrength = new SignalStrength(99, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, SignalStrength.INVALID_SNR, -1, false);
}
@Override
@@ -429,8 +431,13 @@
setSignalStrengthDefaultValues();
} else {
int[] ints = (int[])ar.result;
- int lteCqi = 99, lteRsrp = -1;
- int lteRssi = 99;
+
+ int lteRssi = -1;
+ int lteRsrp = -1;
+ int lteRsrq = -1;
+ int lteRssnr = SignalStrength.INVALID_SNR;
+ int lteCqi = -1;
+
int offset = 2;
int cdmaDbm = (ints[offset] > 0) ? -ints[offset] : -120;
int cdmaEcio = (ints[offset + 1] > 0) ? -ints[offset + 1] : -160;
@@ -438,10 +445,13 @@
int evdoEcio = (ints[offset + 3] > 0) ? -ints[offset + 3] : -1;
int evdoSnr = ((ints[offset + 4] > 0) && (ints[offset + 4] <= 8)) ? ints[offset + 4]
: -1;
+
if (networkType == ServiceState.RADIO_TECHNOLOGY_LTE) {
- lteRssi = (ints[offset + 5] >= 0) ? ints[offset + 5] : 99;
- lteRsrp = (ints[offset + 6] < 0) ? ints[offset + 6] : -1;
- lteCqi = (ints[offset + 7] >= 0) ? ints[offset + 7] : 99;
+ lteRssi = ints[offset+5];
+ lteRsrp = ints[offset+6];
+ lteRsrq = ints[offset+7];
+ lteRssnr = ints[offset+8];
+ lteCqi = ints[offset+9];
}
if (networkType != ServiceState.RADIO_TECHNOLOGY_LTE) {
@@ -449,7 +459,7 @@
evdoSnr, false);
} else {
mSignalStrength = new SignalStrength(99, -1, cdmaDbm, cdmaEcio, evdoRssi, evdoEcio,
- evdoSnr, lteRssi, lteRsrp, -1, -1, lteCqi, true);
+ evdoSnr, lteRssi, lteRsrp, lteRsrq, lteRssnr, lteCqi, true);
}
}
diff --git a/telephony/java/com/android/internal/telephony/cdma/CdmaLteUiccFileHandler.java b/telephony/java/com/android/internal/telephony/cdma/CdmaLteUiccFileHandler.java
index b57af0e..8375fd0 100644
--- a/telephony/java/com/android/internal/telephony/cdma/CdmaLteUiccFileHandler.java
+++ b/telephony/java/com/android/internal/telephony/cdma/CdmaLteUiccFileHandler.java
@@ -55,8 +55,8 @@
if (fileid == EF_CSIM_EPRL) {
// Entire PRL could be huge. We are only interested in
// the first 4 bytes of the record.
- phone.mCM.iccIO(COMMAND_READ_BINARY, fileid, getEFPath(fileid),
- 0, 0, 4, null, null,
+ phone.mCM.iccIOForApp(COMMAND_READ_BINARY, fileid, getEFPath(fileid),
+ 0, 0, 4, null, null, phone.getIccCard().getAid(),
obtainMessage(EVENT_READ_BINARY_DONE,
fileid, 0, onLoaded));
} else {
diff --git a/telephony/java/com/android/internal/telephony/cdma/RuimCard.java b/telephony/java/com/android/internal/telephony/cdma/RuimCard.java
index 02eb86d..674fada 100644
--- a/telephony/java/com/android/internal/telephony/cdma/RuimCard.java
+++ b/telephony/java/com/android/internal/telephony/cdma/RuimCard.java
@@ -44,5 +44,13 @@
public String getServiceProviderName () {
return mPhone.mIccRecords.getServiceProviderName();
}
+
+ @Override
+ protected int getCurrentApplicationIndex() {
+ if (mIccCardStatus == null) {
+ return -1;
+ }
+ return mIccCardStatus.getCdmaSubscriptionAppIndex();
+ }
}
diff --git a/telephony/java/com/android/internal/telephony/cdma/RuimFileHandler.java b/telephony/java/com/android/internal/telephony/cdma/RuimFileHandler.java
index 3e2a29b..375cc07 100644
--- a/telephony/java/com/android/internal/telephony/cdma/RuimFileHandler.java
+++ b/telephony/java/com/android/internal/telephony/cdma/RuimFileHandler.java
@@ -57,8 +57,9 @@
Message response = obtainMessage(EVENT_READ_ICON_DONE, fileid, 0,
onLoaded);
- phone.mCM.iccIO(COMMAND_GET_RESPONSE, fileid, "img", 0, 0,
- GET_RESPONSE_EF_IMG_SIZE_BYTES, null, null, response);
+ phone.mCM.iccIOForApp(COMMAND_GET_RESPONSE, fileid, "img", 0, 0,
+ GET_RESPONSE_EF_IMG_SIZE_BYTES, null, null,
+ phone.getIccCard().getAid(), response);
}
@Override
diff --git a/telephony/java/com/android/internal/telephony/cdma/RuimRecords.java b/telephony/java/com/android/internal/telephony/cdma/RuimRecords.java
index b057e46..17a200e 100755
--- a/telephony/java/com/android/internal/telephony/cdma/RuimRecords.java
+++ b/telephony/java/com/android/internal/telephony/cdma/RuimRecords.java
@@ -29,6 +29,7 @@
import com.android.internal.telephony.AdnRecordCache;
import com.android.internal.telephony.AdnRecordLoader;
import com.android.internal.telephony.CommandsInterface;
+import com.android.internal.telephony.IccRefreshResponse;
import com.android.internal.telephony.TelephonyProperties;
import com.android.internal.telephony.cdma.RuimCard;
import com.android.internal.telephony.MccTable;
@@ -300,7 +301,7 @@
isRecordLoadResponse = false;
ar = (AsyncResult)msg.obj;
if (ar.exception == null) {
- handleRuimRefresh((int[])(ar.result));
+ handleRuimRefresh((IccRefreshResponse)ar.result);
}
break;
@@ -409,24 +410,30 @@
((CDMAPhone) phone).notifyMessageWaitingIndicator();
}
- private void handleRuimRefresh(int[] result) {
- if (result == null || result.length == 0) {
- if (DBG) log("handleRuimRefresh without input");
+ private void handleRuimRefresh(IccRefreshResponse refreshResponse) {
+ if (refreshResponse == null) {
+ if (DBG) log("handleRuimRefresh received without input");
return;
}
- switch ((result[0])) {
- case CommandsInterface.SIM_REFRESH_FILE_UPDATED:
+ if (refreshResponse.aid != null &&
+ !refreshResponse.aid.equals(phone.getIccCard().getAid())) {
+ // This is for different app. Ignore.
+ return;
+ }
+
+ switch (refreshResponse.refreshResult) {
+ case IccRefreshResponse.REFRESH_RESULT_FILE_UPDATE:
if (DBG) log("handleRuimRefresh with SIM_REFRESH_FILE_UPDATED");
adnCache.reset();
fetchRuimRecords();
break;
- case CommandsInterface.SIM_REFRESH_INIT:
+ case IccRefreshResponse.REFRESH_RESULT_INIT:
if (DBG) log("handleRuimRefresh with SIM_REFRESH_INIT");
// need to reload all files (that we care about)
fetchRuimRecords();
break;
- case CommandsInterface.SIM_REFRESH_RESET:
+ case IccRefreshResponse.REFRESH_RESULT_RESET:
if (DBG) log("handleRuimRefresh with SIM_REFRESH_RESET");
phone.mCM.setRadioPower(false, null);
/* Note: no need to call setRadioPower(true). Assuming the desired
diff --git a/telephony/java/com/android/internal/telephony/gsm/GsmServiceStateTracker.java b/telephony/java/com/android/internal/telephony/gsm/GsmServiceStateTracker.java
index 92e16ce..0ebeabe 100644
--- a/telephony/java/com/android/internal/telephony/gsm/GsmServiceStateTracker.java
+++ b/telephony/java/com/android/internal/telephony/gsm/GsmServiceStateTracker.java
@@ -675,7 +675,9 @@
}
private void setSignalStrengthDefaultValues() {
- mSignalStrength = new SignalStrength(99, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, true);
+ // TODO Make a constructor only has boolean gsm as parameter
+ mSignalStrength = new SignalStrength(99, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, SignalStrength.INVALID_SNR, -1, true);
}
/**
@@ -1013,7 +1015,7 @@
int lteSignalStrength = -1;
int lteRsrp = -1;
int lteRsrq = -1;
- int lteRssnr = -1;
+ int lteRssnr = SignalStrength.INVALID_SNR;
int lteCqi = -1;
if (ar.exception != null) {
diff --git a/telephony/java/com/android/internal/telephony/gsm/SIMRecords.java b/telephony/java/com/android/internal/telephony/gsm/SIMRecords.java
index 7c423c7..de8401e 100755
--- a/telephony/java/com/android/internal/telephony/gsm/SIMRecords.java
+++ b/telephony/java/com/android/internal/telephony/gsm/SIMRecords.java
@@ -39,6 +39,7 @@
import com.android.internal.telephony.Phone;
import com.android.internal.telephony.PhoneBase;
import com.android.internal.telephony.SmsMessageBase;
+import com.android.internal.telephony.IccRefreshResponse;
import java.util.ArrayList;
@@ -1049,7 +1050,7 @@
ar = (AsyncResult)msg.obj;
if (DBG) log("Sim REFRESH with exception: " + ar.exception);
if (ar.exception == null) {
- handleSimRefresh((int[])(ar.result));
+ handleSimRefresh((IccRefreshResponse)ar.result);
}
break;
case EVENT_GET_CFIS_DONE:
@@ -1130,27 +1131,31 @@
}
}
- private void handleSimRefresh(int[] result) {
- if (result == null || result.length == 0) {
- if (DBG) log("handleSimRefresh without input");
+ private void handleSimRefresh(IccRefreshResponse refreshResponse){
+ if (refreshResponse == null) {
+ if (DBG) log("handleSimRefresh received without input");
return;
}
- switch ((result[0])) {
- case CommandsInterface.SIM_REFRESH_FILE_UPDATED:
- if (DBG) log("handleSimRefresh with SIM_REFRESH_FILE_UPDATED");
- // result[1] contains the EFID of the updated file.
- int efid = result[1];
- handleFileUpdate(efid);
+ if (refreshResponse.aid != null &&
+ !refreshResponse.aid.equals(phone.getIccCard().getAid())) {
+ // This is for different app. Ignore.
+ return;
+ }
+
+ switch (refreshResponse.refreshResult) {
+ case IccRefreshResponse.REFRESH_RESULT_FILE_UPDATE:
+ if (DBG) log("handleSimRefresh with SIM_FILE_UPDATED");
+ handleFileUpdate(refreshResponse.efId);
break;
- case CommandsInterface.SIM_REFRESH_INIT:
- if (DBG) log("handleSimRefresh with SIM_REFRESH_INIT");
+ case IccRefreshResponse.REFRESH_RESULT_INIT:
+ if (DBG) log("handleSimRefresh with SIM_REFRESH_INIT");
// need to reload all files (that we care about)
adnCache.reset();
fetchSimRecords();
break;
- case CommandsInterface.SIM_REFRESH_RESET:
- if (DBG) log("handleSimRefresh with SIM_REFRESH_RESET");
+ case IccRefreshResponse.REFRESH_RESULT_RESET:
+ if (DBG) log("handleSimRefresh with SIM_REFRESH_RESET");
phone.mCM.setRadioPower(false, null);
/* Note: no need to call setRadioPower(true). Assuming the desired
* radio power state is still ON (as tracked by ServiceStateTracker),
@@ -1162,7 +1167,7 @@
break;
default:
// unknown refresh operation
- if (DBG) log("handleSimRefresh with unknown operation");
+ if (DBG) log("handleSimRefresh with unknown operation");
break;
}
}
@@ -1304,7 +1309,7 @@
logv("fetchSimRecords " + recordsToLoad);
- phone.mCM.getIMSI(obtainMessage(EVENT_GET_IMSI_DONE));
+ phone.mCM.getIMSIForApp(phone.getIccCard().getAid(), obtainMessage(EVENT_GET_IMSI_DONE));
recordsToLoad++;
iccFh.loadEFTransparent(EF_ICCID, obtainMessage(EVENT_GET_ICCID_DONE));
diff --git a/telephony/java/com/android/internal/telephony/gsm/SimCard.java b/telephony/java/com/android/internal/telephony/gsm/SimCard.java
index e34e10a..0e68e07 100644
--- a/telephony/java/com/android/internal/telephony/gsm/SimCard.java
+++ b/telephony/java/com/android/internal/telephony/gsm/SimCard.java
@@ -39,4 +39,11 @@
return mPhone.mIccRecords.getServiceProviderName();
}
+ @Override
+ protected int getCurrentApplicationIndex() {
+ if (mIccCardStatus == null) {
+ return -1;
+ }
+ return mIccCardStatus.getGsmUmtsSubscriptionAppIndex();
+ }
}
diff --git a/telephony/java/com/android/internal/telephony/sip/SipCommandInterface.java b/telephony/java/com/android/internal/telephony/sip/SipCommandInterface.java
index 9201984..99f4e0f 100644
--- a/telephony/java/com/android/internal/telephony/sip/SipCommandInterface.java
+++ b/telephony/java/com/android/internal/telephony/sip/SipCommandInterface.java
@@ -84,6 +84,9 @@
public void getIMSI(Message result) {
}
+ public void getIMSIForApp(String aid, Message result) {
+ }
+
public void getIMEI(Message result) {
}
@@ -213,6 +216,9 @@
public void iccIO (int command, int fileid, String path, int p1, int p2,
int p3, String data, String pin2, Message result) {
}
+ public void iccIOForApp (int command, int fileid, String path, int p1, int p2,
+ int p3, String data, String pin2, String aid, Message result) {
+ }
public void getCLIR(Message result) {
}
diff --git a/telephony/java/com/android/internal/telephony/test/SimulatedCommands.java b/telephony/java/com/android/internal/telephony/test/SimulatedCommands.java
index 60d9d24..4f61509 100644
--- a/telephony/java/com/android/internal/telephony/test/SimulatedCommands.java
+++ b/telephony/java/com/android/internal/telephony/test/SimulatedCommands.java
@@ -504,6 +504,9 @@
resultSuccess(result, null);
}
+ public void getIMSI(Message result) {
+ getIMSIForApp(null, result);
+ }
/**
* returned message
* retMsg.obj = AsyncResult ar
@@ -511,7 +514,7 @@
* ar.userObject contains the original value of result.obj
* ar.result is String containing IMSI on success
*/
- public void getIMSI(Message result) {
+ public void getIMSIForApp(String aid, Message result) {
resultSuccess(result, "012345678901234");
}
@@ -1042,13 +1045,18 @@
unimplemented(result);
}
+ public void iccIO(int command, int fileid, String path, int p1, int p2, int p3, String data,
+ String pin2, Message response) {
+ iccIOForApp(command, fileid, path, p1, p2, p3, data,pin2, null, response);
+ }
+
/**
* parameters equivalent to 27.007 AT+CRSM command
* response.obj will be an AsyncResult
* response.obj.userObj will be a SimIoResult on success
*/
- public void iccIO (int command, int fileid, String path, int p1, int p2,
- int p3, String data, String pin2, Message result) {
+ public void iccIOForApp (int command, int fileid, String path, int p1, int p2,
+ int p3, String data, String pin2, String aid, Message result) {
unimplemented(result);
}
diff --git a/telephony/tests/telephonytests/src/com/android/internal/telephony/PhoneNumberUtilsTest.java b/telephony/tests/telephonytests/src/com/android/internal/telephony/PhoneNumberUtilsTest.java
index a385f55..5b76272 100644
--- a/telephony/tests/telephonytests/src/com/android/internal/telephony/PhoneNumberUtilsTest.java
+++ b/telephony/tests/telephonytests/src/com/android/internal/telephony/PhoneNumberUtilsTest.java
@@ -511,8 +511,9 @@
@SmallTest
public void testFormatNumber() {
assertEquals("(650) 291-0000", PhoneNumberUtils.formatNumber("650 2910000", "US"));
- assertEquals("123-4567", PhoneNumberUtils.formatNumber("1234567", "US"));
- assertEquals("(800) 466-4114", PhoneNumberUtils.formatNumber("800-GOOG-114", "US"));
+ assertEquals("223-4567", PhoneNumberUtils.formatNumber("2234567", "US"));
+ // formatNumber doesn't format alpha numbers, but keep them as they are.
+ assertEquals("800-GOOG-114", PhoneNumberUtils.formatNumber("800-GOOG-114", "US"));
}
@SmallTest
@@ -592,9 +593,12 @@
// addressing that, they are also classified as "potential" emergency numbers in the US.
assertTrue(PhoneNumberUtils.isPotentialEmergencyNumber("91112345", "US"));
assertTrue(PhoneNumberUtils.isPotentialEmergencyNumber("11212345", "US"));
+
// A valid mobile phone number from Singapore shouldn't be classified as an emergency number
// in Singapore, as 911 is not an emergency number there.
- assertFalse(PhoneNumberUtils.isPotentialEmergencyNumber("91121234", "SG"));
+ // This test fails on devices that have ecclist property preloaded with 911.
+ // assertFalse(PhoneNumberUtils.isPotentialEmergencyNumber("91121234", "SG"));
+
// A valid fixed-line phone number from Brazil shouldn't be classified as an emergency number
// in Brazil, as 112 is not an emergency number there.
assertFalse(PhoneNumberUtils.isPotentialEmergencyNumber("1121234567", "BR"));
diff --git a/telephony/tests/telephonytests/src/com/android/internal/telephony/PhoneNumberWatcherTest.java b/telephony/tests/telephonytests/src/com/android/internal/telephony/PhoneNumberWatcherTest.java
index d2e573c..6f0175e 100644
--- a/telephony/tests/telephonytests/src/com/android/internal/telephony/PhoneNumberWatcherTest.java
+++ b/telephony/tests/telephonytests/src/com/android/internal/telephony/PhoneNumberWatcherTest.java
@@ -64,7 +64,7 @@
assertEquals(result1, number.toString());
assertEquals(result1.length(), Selection.getSelectionEnd(number));
// Remove last 5 chars
- final String result2 = "(650) 123";
+ final String result2 = "650-123";
textWatcher.beforeTextChanged(number, number.length() - 4, 4, 0);
number.delete(number.length() - 5, number.length());
Selection.setSelection(number, number.length());
@@ -75,26 +75,26 @@
}
public void testInsertChars() {
- final String init = "(650) 23";
- final String expected1 = "(650) 123";
+ final String init = "650-23";
+ final String expected1 = "650-123";
TextWatcher textWatcher = getTextWatcher();
// Insert one char
SpannableStringBuilder number = new SpannableStringBuilder(init);
- textWatcher.beforeTextChanged(number, 4, 0, 1);
- number.insert(4, "1"); // (6501) 23
- Selection.setSelection(number, 5); // make the cursor at right of 1
- textWatcher.onTextChanged(number, 4, 0, 1);
+ textWatcher.beforeTextChanged(number, 3, 0, 1);
+ number.insert(3, "1"); // 6501-23
+ Selection.setSelection(number, 4); // make the cursor at right of 1
+ textWatcher.onTextChanged(number, 3, 0, 1);
textWatcher.afterTextChanged(number);
assertEquals(expected1, number.toString());
// the cursor should still at the right of '1'
- assertEquals(7, Selection.getSelectionEnd(number));
+ assertEquals(5, Selection.getSelectionEnd(number));
// Insert multiple chars
final String expected2 = "(650) 145-6723";
- textWatcher.beforeTextChanged(number, 7, 0, 4);
- number.insert(7, "4567"); // change to (650) 1456723
- Selection.setSelection(number, 11); // the cursor is at the right of '7'.
+ textWatcher.beforeTextChanged(number, 5, 0, 4);
+ number.insert(5, "4567"); // change to 650-1456723
+ Selection.setSelection(number, 9); // the cursor is at the right of '7'.
textWatcher.onTextChanged(number, 7, 0, 4);
textWatcher.afterTextChanged(number);
assertEquals(expected2, number.toString());
@@ -168,7 +168,7 @@
textWatcher.onTextChanged(number, 0, len, 0);
textWatcher.afterTextChanged(number);
- final String expected2 = "(650) 123-4";
+ final String expected2 = "650-1234";
number = new SpannableStringBuilder(init);
textWatcher.beforeTextChanged(number, 9, 0, 1);
number.insert(9, "4"); // (650) 1234
diff --git a/telephony/tests/telephonytests/src/com/android/internal/telephony/gsm/UsimDataDownloadCommands.java b/telephony/tests/telephonytests/src/com/android/internal/telephony/gsm/UsimDataDownloadCommands.java
index b385cee..ea6836d 100644
--- a/telephony/tests/telephonytests/src/com/android/internal/telephony/gsm/UsimDataDownloadCommands.java
+++ b/telephony/tests/telephonytests/src/com/android/internal/telephony/gsm/UsimDataDownloadCommands.java
@@ -612,4 +612,13 @@
@Override
public void getVoiceRadioTechnology(Message response) {
}
+
+ @Override
+ public void getIMSIForApp(String aid, Message result) {
+ }
+
+ @Override
+ public void iccIOForApp(int command, int fileid, String path, int p1, int p2, int p3,
+ String data, String pin2, String aid, Message response) {
+ }
}
diff --git a/test-runner/src/android/test/mock/MockContentProvider.java b/test-runner/src/android/test/mock/MockContentProvider.java
index e0ce322..a8c388e 100644
--- a/test-runner/src/android/test/mock/MockContentProvider.java
+++ b/test-runner/src/android/test/mock/MockContentProvider.java
@@ -21,6 +21,7 @@
import android.content.ContentProviderResult;
import android.content.ContentValues;
import android.content.Context;
+import android.content.ICancellationSignal;
import android.content.IContentProvider;
import android.content.OperationApplicationException;
import android.content.pm.PathPermission;
@@ -92,7 +93,7 @@
@Override
public Cursor query(Uri url, String[] projection, String selection, String[] selectionArgs,
- String sortOrder) throws RemoteException {
+ String sortOrder, ICancellationSignal cancellationSignal) throws RemoteException {
return MockContentProvider.this.query(url, projection, selection,
selectionArgs, sortOrder);
}
@@ -124,6 +125,11 @@
throws RemoteException, FileNotFoundException {
return MockContentProvider.this.openTypedAssetFile(url, mimeType, opts);
}
+
+ @Override
+ public ICancellationSignal createCancellationSignal() throws RemoteException {
+ return null;
+ }
}
private final InversionIContentProvider mIContentProvider = new InversionIContentProvider();
diff --git a/test-runner/src/android/test/mock/MockIContentProvider.java b/test-runner/src/android/test/mock/MockIContentProvider.java
index b7733a4..1aa0448 100644
--- a/test-runner/src/android/test/mock/MockIContentProvider.java
+++ b/test-runner/src/android/test/mock/MockIContentProvider.java
@@ -21,6 +21,7 @@
import android.content.ContentValues;
import android.content.EntityIterator;
import android.content.IContentProvider;
+import android.content.ICancellationSignal;
import android.content.res.AssetFileDescriptor;
import android.database.Cursor;
import android.net.Uri;
@@ -72,7 +73,7 @@
}
public Cursor query(Uri url, String[] projection, String selection, String[] selectionArgs,
- String sortOrder) {
+ String sortOrder, ICancellationSignal cancellationSignal) {
throw new UnsupportedOperationException("unimplemented mock method");
}
@@ -103,4 +104,9 @@
throws RemoteException, FileNotFoundException {
throw new UnsupportedOperationException("unimplemented mock method");
}
+
+ @Override
+ public ICancellationSignal createCancellationSignal() throws RemoteException {
+ throw new UnsupportedOperationException("unimplemented mock method");
+ }
}
diff --git a/tests/ActivityTests/res/anim/slow_enter.xml b/tests/ActivityTests/res/anim/slow_enter.xml
new file mode 100644
index 0000000..0309643
--- /dev/null
+++ b/tests/ActivityTests/res/anim/slow_enter.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** Copyright 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.
+** 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.
+*/
+-->
+
+<set xmlns:android="http://schemas.android.com/apk/res/android"
+ android:shareInterpolator="false" >
+ <scale android:fromXScale="0.9" android:toXScale="1.5"
+ android:fromYScale="0.9" android:toYScale="1.5"
+ android:pivotX="50%" android:pivotY="50%"
+ android:interpolator="@interpolator/slow_enter"
+ android:duration="40000" />
+ <alpha android:fromAlpha="0.0" android:toAlpha="1.0"
+ android:interpolator="@android:interpolator/decelerate_cubic"
+ android:duration="1000" />
+</set>
diff --git a/tests/ActivityTests/res/anim/slow_exit.xml b/tests/ActivityTests/res/anim/slow_exit.xml
new file mode 100644
index 0000000..6cd3114
--- /dev/null
+++ b/tests/ActivityTests/res/anim/slow_exit.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** Copyright 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.
+** 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.
+*/
+-->
+
+<set xmlns:android="http://schemas.android.com/apk/res/android"
+ android:shareInterpolator="false" >
+ <scale android:fromXScale="1.0" android:toXScale="0.9"
+ android:fromYScale="1.0" android:toYScale="0.9"
+ android:pivotX="50%" android:pivotY="50%"
+ android:interpolator="@android:interpolator/decelerate_quint"
+ android:duration="300" />
+ <alpha android:fromAlpha="1.0" android:toAlpha="0.0"
+ android:interpolator="@android:interpolator/decelerate_cubic"
+ android:duration="300"/>
+</set>
diff --git a/tests/ActivityTests/res/interpolator/slow_enter.xml b/tests/ActivityTests/res/interpolator/slow_enter.xml
new file mode 100644
index 0000000..ddab1aa
--- /dev/null
+++ b/tests/ActivityTests/res/interpolator/slow_enter.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 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.
+** 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.
+*/
+-->
+
+<cycleInterpolator xmlns:android="http://schemas.android.com/apk/res/android"
+ android:cycles="10" />
diff --git a/tests/ActivityTests/res/values/themes.xml b/tests/ActivityTests/res/values/themes.xml
new file mode 100644
index 0000000..67f5938
--- /dev/null
+++ b/tests/ActivityTests/res/values/themes.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<resources>
+ <style name="SlowDialog" parent="@android:style/Theme.Holo.Dialog">
+ <item name="android:windowAnimationStyle">@style/SlowDialog</item>
+ </style>
+ <style name="SlowDialog">
+ <item name="android:windowEnterAnimation">@anim/slow_enter</item>
+ <item name="android:windowExitAnimation">@anim/slow_exit</item>
+ </style>
+</resources>
diff --git a/tests/ActivityTests/src/com/google/android/test/activity/ActivityTestMain.java b/tests/ActivityTests/src/com/google/android/test/activity/ActivityTestMain.java
index 583c13c..ae42e29 100644
--- a/tests/ActivityTests/src/com/google/android/test/activity/ActivityTestMain.java
+++ b/tests/ActivityTests/src/com/google/android/test/activity/ActivityTestMain.java
@@ -22,6 +22,7 @@
import android.app.Activity;
import android.app.ActivityManager;
import android.app.ActivityThread;
+import android.app.AlertDialog;
import android.app.Application;
import android.content.ActivityNotFoundException;
import android.os.Bundle;
@@ -35,6 +36,8 @@
import android.widget.TextView;
import android.widget.ScrollView;
import android.view.LayoutInflater;
+import android.view.Menu;
+import android.view.MenuItem;
import android.view.View;
import android.content.Context;
import android.content.pm.ApplicationInfo;
@@ -101,6 +104,20 @@
}
@Override
+ public boolean onCreateOptionsMenu(Menu menu) {
+ menu.add("Animate!").setOnMenuItemClickListener(new MenuItem.OnMenuItemClickListener() {
+ @Override public boolean onMenuItemClick(MenuItem item) {
+ AlertDialog.Builder builder = new AlertDialog.Builder(ActivityTestMain.this,
+ R.style.SlowDialog);
+ builder.setTitle("This is a title");
+ builder.show();
+ return true;
+ }
+ });
+ return true;
+ }
+
+ @Override
protected void onStart() {
super.onStart();
buildUi();
diff --git a/tests/BiDiTests/res/layout/basic.xml b/tests/BiDiTests/res/layout/basic.xml
index f503658..7d4d4db 100644
--- a/tests/BiDiTests/res/layout/basic.xml
+++ b/tests/BiDiTests/res/layout/basic.xml
@@ -19,6 +19,10 @@
android:layout_width="fill_parent"
android:layout_height="fill_parent">
+ <ScrollView
+ android:layout_width="fill_parent"
+ android:layout_height="fill_parent">
+
<LinearLayout android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
@@ -131,4 +135,6 @@
</LinearLayout>
+ </ScrollView>
+
</FrameLayout>
diff --git a/tests/BiDiTests/res/values/strings.xml b/tests/BiDiTests/res/values/strings.xml
index 1d4fc84..233cd0d 100644
--- a/tests/BiDiTests/res/values/strings.xml
+++ b/tests/BiDiTests/res/values/strings.xml
@@ -24,11 +24,11 @@
<string name="button_before_text">Start</string>
<string name="button_requestlayout_text">Request Layout</string>
<string name="button_alert_dialog_text">AlertDialog</string>
- <string name="textview_text">This is a text for a TextView</string>
- <string name="textview_ltr_text">This is a text for a LTR TextView</string>
- <string name="textview_rtl_text">This is a text for a RTL TextView</string>
- <string name="textview_default_text">This is a text for a default TextView</string>
- <string name="textview_password_default_text">This is a text for a password TextView</string>
+ <string name="textview_text">TextView</string>
+ <string name="textview_ltr_text">LTR TextView</string>
+ <string name="textview_rtl_text">RTL TextView</string>
+ <string name="textview_default_text">Default TextView</string>
+ <string name="textview_password_default_text">Password TextView</string>
<string name="edittext_text">mmmmmmmmmmmmmmmmmmmmmmmm</string>
<string name="normal_text">Normal String</string>
<string name="normal_long_text">mmmmmmmmmmmmmmmmmmmmmmmm</string>
diff --git a/tests/DumpRenderTree/src/com/android/dumprendertree/FsUtils.java b/tests/DumpRenderTree/src/com/android/dumprendertree/FsUtils.java
index 5e2a9fd..b7d2c26 100644
--- a/tests/DumpRenderTree/src/com/android/dumprendertree/FsUtils.java
+++ b/tests/DumpRenderTree/src/com/android/dumprendertree/FsUtils.java
@@ -141,7 +141,7 @@
} else if (!path.startsWith(HTTP_LOCAL_TESTS_PREFIX)
&& !path.startsWith(HTTP_MEDIA_TESTS_PREFIX)
&& !path.startsWith(HTTP_WML_TESTS_PREFIX)) {
- url = "http://127.0.0.1:18000/" + path.substring(HTTP_TESTS_PREFIX.length());
+ url = "http://127.0.0.1:8000/" + path.substring(HTTP_TESTS_PREFIX.length());
} else {
url = "file://" + path;
}
diff --git a/tests/DumpRenderTree/src/com/android/dumprendertree/forwarder/ForwardService.java b/tests/DumpRenderTree/src/com/android/dumprendertree/forwarder/ForwardService.java
index 7a277d7..25dd04fd 100644
--- a/tests/DumpRenderTree/src/com/android/dumprendertree/forwarder/ForwardService.java
+++ b/tests/DumpRenderTree/src/com/android/dumprendertree/forwarder/ForwardService.java
@@ -26,7 +26,7 @@
public class ForwardService {
- private ForwardServer fs18000, fs8080, fs8443;
+ private ForwardServer fs8000, fs8080, fs8443;
private static ForwardService inst;
@@ -40,7 +40,7 @@
private ForwardService() {
int addr = getForwardHostAddr();
if (addr != -1) {
- fs18000 = new ForwardServer(18000, addr, 8000);
+ fs8000 = new ForwardServer(8000, addr, 8000);
fs8080 = new ForwardServer(8080, addr, 8080);
fs8443 = new ForwardServer(8443, addr, 8443);
}
@@ -55,8 +55,8 @@
public void startForwardService() {
try {
- if (fs18000 != null)
- fs18000.start();
+ if (fs8000 != null)
+ fs8000.start();
if (fs8080 != null)
fs8080.start();
if (fs8443 != null)
@@ -68,9 +68,9 @@
}
public void stopForwardService() {
- if (fs18000 != null) {
- fs18000.stop();
- fs18000 = null;
+ if (fs8000 != null) {
+ fs8000.stop();
+ fs8000 = null;
}
if (fs8080 != null) {
fs8080.stop();
diff --git a/tests/HwAccelerationTest/AndroidManifest.xml b/tests/HwAccelerationTest/AndroidManifest.xml
index 112c606..643cb8d 100644
--- a/tests/HwAccelerationTest/AndroidManifest.xml
+++ b/tests/HwAccelerationTest/AndroidManifest.xml
@@ -30,6 +30,17 @@
android:label="HwUi"
android:hardwareAccelerated="true">
+ <meta-data android:name="android.graphics.renderThread" android:value="true" />
+
+ <activity
+ android:name="PaintDrawFilterActivity"
+ android:label="_DrawFilter">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.LAUNCHER" />
+ </intent-filter>
+ </activity>
+
<activity
android:name="DisplayListLayersActivity"
android:label="__DisplayListLayers">
diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/PaintDrawFilterActivity.java b/tests/HwAccelerationTest/src/com/android/test/hwui/PaintDrawFilterActivity.java
new file mode 100644
index 0000000..8523272
--- /dev/null
+++ b/tests/HwAccelerationTest/src/com/android/test/hwui/PaintDrawFilterActivity.java
@@ -0,0 +1,64 @@
+/*
+ * 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.
+ */
+
+package com.android.test.hwui;
+
+import android.app.Activity;
+import android.content.Context;
+import android.graphics.Canvas;
+import android.graphics.Paint;
+import android.graphics.PaintFlagsDrawFilter;
+import android.os.Bundle;
+import android.view.View;
+
+@SuppressWarnings({"UnusedDeclaration"})
+public class PaintDrawFilterActivity extends Activity {
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ setContentView(new CustomTextView(this));
+ }
+
+ static class CustomTextView extends View {
+ private final Paint mMediumPaint;
+ private final PaintFlagsDrawFilter mDrawFilter;
+
+ CustomTextView(Context c) {
+ super(c);
+
+ mMediumPaint = new Paint();
+ mMediumPaint.setAntiAlias(true);
+ mMediumPaint.setColor(0xff000000);
+ mMediumPaint.setFakeBoldText(true);
+ mMediumPaint.setTextSize(24.0f);
+
+ mDrawFilter = new PaintFlagsDrawFilter(
+ Paint.FAKE_BOLD_TEXT_FLAG, Paint.UNDERLINE_TEXT_FLAG);
+ }
+
+ @Override
+ protected void onDraw(Canvas canvas) {
+ super.onDraw(canvas);
+ canvas.drawRGB(255, 255, 255);
+
+ canvas.setDrawFilter(null);
+ canvas.drawText("Hello OpenGL renderer!", 100, 120, mMediumPaint);
+ canvas.setDrawFilter(mDrawFilter);
+ canvas.drawText("Hello OpenGL renderer!", 100, 220, mMediumPaint);
+ }
+ }
+}
diff --git a/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/ImageProcessingTest.java b/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/ImageProcessingTest.java
index f96e68b..912d863 100644
--- a/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/ImageProcessingTest.java
+++ b/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/ImageProcessingTest.java
@@ -84,7 +84,7 @@
Log.v(TAG, "RenderScript framew time core: " + t + " ms");
}
long avgValue = sum/ITERATION;
- rsWriter.write("Averge frame time: " + avgValue + " ms\n");
+ rsWriter.write("Average frame time: " + avgValue + " ms\n");
Log.v(TAG, "Average frame time: " + avgValue + " ms");
rsWriter.close();
} catch (IOException e) {
diff --git a/tests/RenderScriptTests/tests/src/com/android/rs/test/RSTestCore.java b/tests/RenderScriptTests/tests/src/com/android/rs/test/RSTestCore.java
index c038478..2293678 100644
--- a/tests/RenderScriptTests/tests/src/com/android/rs/test/RSTestCore.java
+++ b/tests/RenderScriptTests/tests/src/com/android/rs/test/RSTestCore.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2008-2011 The Android Open Source Project
+ * Copyright (C) 2008-2012 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -65,6 +65,7 @@
unitTests = new ArrayList<UnitTest>();
unitTests.add(new UT_primitives(this, mRes, mCtx));
+ unitTests.add(new UT_constant(this, mRes, mCtx));
unitTests.add(new UT_vector(this, mRes, mCtx));
unitTests.add(new UT_rsdebug(this, mRes, mCtx));
unitTests.add(new UT_rstime(this, mRes, mCtx));
@@ -72,6 +73,8 @@
unitTests.add(new UT_alloc(this, mRes, mCtx));
unitTests.add(new UT_refcount(this, mRes, mCtx));
unitTests.add(new UT_foreach(this, mRes, mCtx));
+ unitTests.add(new UT_atomic(this, mRes, mCtx));
+ unitTests.add(new UT_struct(this, mRes, mCtx));
unitTests.add(new UT_math(this, mRes, mCtx));
unitTests.add(new UT_fp_mad(this, mRes, mCtx));
/*
@@ -91,7 +94,7 @@
for (int i = 0; i < uta.length; i++) {
ScriptField_ListAllocs_s.Item listElem = new ScriptField_ListAllocs_s.Item();
listElem.text = Allocation.createFromString(mRS, uta[i].name, Allocation.USAGE_SCRIPT);
- listElem.result = uta[i].result;
+ listElem.result = uta[i].getResult();
mListAllocs.set(listElem, i, false);
uta[i].setItem(listElem);
}
diff --git a/tests/RenderScriptTests/tests/src/com/android/rs/test/UT_atomic.java b/tests/RenderScriptTests/tests/src/com/android/rs/test/UT_atomic.java
new file mode 100644
index 0000000..267c5b2
--- /dev/null
+++ b/tests/RenderScriptTests/tests/src/com/android/rs/test/UT_atomic.java
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.rs.test;
+
+import android.content.Context;
+import android.content.res.Resources;
+import android.renderscript.*;
+
+public class UT_atomic extends UnitTest {
+ private Resources mRes;
+
+ protected UT_atomic(RSTestCore rstc, Resources res, Context ctx) {
+ super(rstc, "Atomics", ctx);
+ mRes = res;
+ }
+
+ public void run() {
+ RenderScript pRS = RenderScript.create(mCtx);
+ ScriptC_atomic s = new ScriptC_atomic(pRS, mRes, R.raw.atomic);
+ pRS.setMessageHandler(mRsMessage);
+ s.invoke_atomic_test();
+ pRS.finish();
+ waitForMessage();
+ pRS.destroy();
+ }
+}
diff --git a/tests/RenderScriptTests/tests/src/com/android/rs/test/UT_constant.java b/tests/RenderScriptTests/tests/src/com/android/rs/test/UT_constant.java
new file mode 100644
index 0000000..adda5a3
--- /dev/null
+++ b/tests/RenderScriptTests/tests/src/com/android/rs/test/UT_constant.java
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.rs.test;
+
+import android.content.Context;
+import android.content.res.Resources;
+import android.renderscript.*;
+
+public class UT_constant extends UnitTest {
+ private Resources mRes;
+
+ protected UT_constant(RSTestCore rstc, Resources res, Context ctx) {
+ super(rstc, "Const", ctx);
+ mRes = res;
+ }
+
+ private void Assert(boolean b) {
+ if (!b) {
+ failTest();
+ }
+ }
+
+ public void run() {
+ Assert(ScriptC_constant.const_floatTest == 1.99f);
+ Assert(ScriptC_constant.const_doubleTest == 2.05);
+ Assert(ScriptC_constant.const_charTest == -8);
+ Assert(ScriptC_constant.const_shortTest == -16);
+ Assert(ScriptC_constant.const_intTest == -32);
+ Assert(ScriptC_constant.const_longTest == 17179869184l);
+ Assert(ScriptC_constant.const_longlongTest == 68719476736l);
+
+ Assert(ScriptC_constant.const_ucharTest == 8);
+ Assert(ScriptC_constant.const_ushortTest == 16);
+ Assert(ScriptC_constant.const_uintTest == 32);
+ Assert(ScriptC_constant.const_ulongTest == 4611686018427387904L);
+ Assert(ScriptC_constant.const_int64_tTest == -17179869184l);
+ Assert(ScriptC_constant.const_uint64_tTest == 117179869184l);
+
+ Assert(ScriptC_constant.const_boolTest == true);
+
+ passTest();
+ }
+}
diff --git a/tests/RenderScriptTests/tests/src/com/android/rs/test/UT_primitives.java b/tests/RenderScriptTests/tests/src/com/android/rs/test/UT_primitives.java
index b7a65a5..18829c2 100644
--- a/tests/RenderScriptTests/tests/src/com/android/rs/test/UT_primitives.java
+++ b/tests/RenderScriptTests/tests/src/com/android/rs/test/UT_primitives.java
@@ -92,8 +92,7 @@
ScriptC_primitives s = new ScriptC_primitives(pRS, mRes, R.raw.primitives);
pRS.setMessageHandler(mRsMessage);
if (!initializeGlobals(s)) {
- // initializeGlobals failed
- result = -1;
+ failTest();
} else {
s.invoke_primitives_test(0, 0);
pRS.finish();
diff --git a/tests/RenderScriptTests/tests/src/com/android/rs/test/UT_struct.java b/tests/RenderScriptTests/tests/src/com/android/rs/test/UT_struct.java
new file mode 100644
index 0000000..2a55686
--- /dev/null
+++ b/tests/RenderScriptTests/tests/src/com/android/rs/test/UT_struct.java
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.rs.test;
+
+import android.content.Context;
+import android.content.res.Resources;
+import android.renderscript.*;
+
+public class UT_struct extends UnitTest {
+ private Resources mRes;
+
+ protected UT_struct(RSTestCore rstc, Resources res, Context ctx) {
+ super(rstc, "Struct", ctx);
+ mRes = res;
+ }
+
+ public void run() {
+ RenderScript pRS = RenderScript.create(mCtx);
+ ScriptC_struct s = new ScriptC_struct(pRS, mRes, R.raw.struct);
+ pRS.setMessageHandler(mRsMessage);
+
+ ScriptField_Point2 p = new ScriptField_Point2(pRS, 1);
+ ScriptField_Point2.Item i = new ScriptField_Point2.Item();
+ int val = 100;
+ i.x = val;
+ i.y = val;
+ p.set(i, 0, true);
+ s.bind_point2(p);
+ s.invoke_struct_test(val);
+ pRS.finish();
+ waitForMessage();
+
+ val = 200;
+ p.set_x(0, val, true);
+ p.set_y(0, val, true);
+ s.invoke_struct_test(val);
+ pRS.finish();
+ waitForMessage();
+ pRS.destroy();
+ }
+}
diff --git a/tests/RenderScriptTests/tests/src/com/android/rs/test/UT_vector.java b/tests/RenderScriptTests/tests/src/com/android/rs/test/UT_vector.java
index 748701d..0ac09ca 100644
--- a/tests/RenderScriptTests/tests/src/com/android/rs/test/UT_vector.java
+++ b/tests/RenderScriptTests/tests/src/com/android/rs/test/UT_vector.java
@@ -307,7 +307,7 @@
ScriptC_vector s = new ScriptC_vector(pRS, mRes, R.raw.vector);
pRS.setMessageHandler(mRsMessage);
if (!initializeGlobals(s)) {
- result = -1;
+ failTest();
} else {
s.invoke_vector_test();
pRS.finish();
diff --git a/tests/RenderScriptTests/tests/src/com/android/rs/test/UnitTest.java b/tests/RenderScriptTests/tests/src/com/android/rs/test/UnitTest.java
index a97ffa7..edff83f 100644
--- a/tests/RenderScriptTests/tests/src/com/android/rs/test/UnitTest.java
+++ b/tests/RenderScriptTests/tests/src/com/android/rs/test/UnitTest.java
@@ -21,7 +21,7 @@
public class UnitTest extends Thread {
public String name;
- public int result;
+ private int result;
private ScriptField_ListAllocs_s.Item mItem;
private RSTestCore mRSTC;
private boolean msgHandled;
@@ -63,7 +63,7 @@
}
}
- protected void updateUI() {
+ private void updateUI() {
if (mItem != null) {
mItem.result = result;
msgHandled = true;
@@ -104,6 +104,22 @@
}
}
+ public int getResult() {
+ return result;
+ }
+
+ public void failTest() {
+ result = -1;
+ updateUI();
+ }
+
+ public void passTest() {
+ if (result != -1) {
+ result = 1;
+ }
+ updateUI();
+ }
+
public void setItem(ScriptField_ListAllocs_s.Item item) {
mItem = item;
}
diff --git a/tests/RenderScriptTests/tests/src/com/android/rs/test/atomic.rs b/tests/RenderScriptTests/tests/src/com/android/rs/test/atomic.rs
new file mode 100644
index 0000000..f0a5041
--- /dev/null
+++ b/tests/RenderScriptTests/tests/src/com/android/rs/test/atomic.rs
@@ -0,0 +1,77 @@
+#include "shared.rsh"
+
+// Testing atomic operations
+static bool testUMax(uint32_t dst, uint32_t src) {
+ bool failed = false;
+ uint32_t old = dst;
+ uint32_t expect = (dst > src ? dst : src);
+ uint32_t ret = rsAtomicMax(&dst, src);
+ _RS_ASSERT(old == ret);
+ _RS_ASSERT(dst == expect);
+ return failed;
+}
+
+static bool testUMin(uint32_t dst, uint32_t src) {
+ bool failed = false;
+ uint32_t old = dst;
+ uint32_t expect = (dst < src ? dst : src);
+ uint32_t ret = rsAtomicMin(&dst, src);
+ _RS_ASSERT(old == ret);
+ _RS_ASSERT(dst == expect);
+ return failed;
+}
+
+static bool testUCas(uint32_t dst, uint32_t cmp, uint32_t swp) {
+ bool failed = false;
+ uint32_t old = dst;
+ uint32_t expect = (dst == cmp ? swp : dst);
+ uint32_t ret = rsAtomicCas(&dst, cmp, swp);
+ _RS_ASSERT(old == ret);
+ _RS_ASSERT(dst == expect);
+ return failed;
+}
+
+static bool test_atomics() {
+ bool failed = false;
+
+ failed |= testUMax(5, 6);
+ failed |= testUMax(6, 5);
+ failed |= testUMax(5, 0xf0000006);
+ failed |= testUMax(0xf0000006, 5);
+
+ failed |= testUMin(5, 6);
+ failed |= testUMin(6, 5);
+ failed |= testUMin(5, 0xf0000006);
+ failed |= testUMin(0xf0000006, 5);
+
+ failed |= testUCas(4, 4, 5);
+ failed |= testUCas(4, 5, 5);
+ failed |= testUCas(5, 5, 4);
+ failed |= testUCas(5, 4, 4);
+ failed |= testUCas(0xf0000004, 0xf0000004, 0xf0000005);
+ failed |= testUCas(0xf0000004, 0xf0000005, 0xf0000005);
+ failed |= testUCas(0xf0000005, 0xf0000005, 0xf0000004);
+ failed |= testUCas(0xf0000005, 0xf0000004, 0xf0000004);
+
+ if (failed) {
+ rsDebug("test_atomics FAILED", 0);
+ }
+ else {
+ rsDebug("test_atomics PASSED", 0);
+ }
+
+ return failed;
+}
+
+void atomic_test() {
+ bool failed = false;
+ failed |= test_atomics();
+
+ if (failed) {
+ rsSendToClientBlocking(RS_MSG_TEST_FAILED);
+ }
+ else {
+ rsSendToClientBlocking(RS_MSG_TEST_PASSED);
+ }
+}
+
diff --git a/tests/RenderScriptTests/tests/src/com/android/rs/test/constant.rs b/tests/RenderScriptTests/tests/src/com/android/rs/test/constant.rs
new file mode 100644
index 0000000..732eaef
--- /dev/null
+++ b/tests/RenderScriptTests/tests/src/com/android/rs/test/constant.rs
@@ -0,0 +1,19 @@
+#include "shared.rsh"
+
+const float floatTest = 1.99f;
+const double doubleTest = 2.05;
+const char charTest = -8;
+const short shortTest = -16;
+const int intTest = -32;
+const long longTest = 17179869184l; // 1 << 34
+const long long longlongTest = 68719476736l; // 1 << 36
+
+const uchar ucharTest = 8;
+const ushort ushortTest = 16;
+const uint uintTest = 32;
+const ulong ulongTest = 4611686018427387904L;
+const int64_t int64_tTest = -17179869184l; // - 1 << 34
+const uint64_t uint64_tTest = 117179869184l;
+
+const bool boolTest = true;
+
diff --git a/tests/RenderScriptTests/tests/src/com/android/rs/test/struct.rs b/tests/RenderScriptTests/tests/src/com/android/rs/test/struct.rs
new file mode 100644
index 0000000..1cd728e
--- /dev/null
+++ b/tests/RenderScriptTests/tests/src/com/android/rs/test/struct.rs
@@ -0,0 +1,37 @@
+#include "shared.rsh"
+
+typedef struct Point2 {
+ int x;
+ int y;
+} Point_2;
+Point_2 *point2;
+
+static bool test_Point_2(int expected) {
+ bool failed = false;
+
+ rsDebug("Point: ", point2[0].x, point2[0].y);
+ _RS_ASSERT(point2[0].x == expected);
+ _RS_ASSERT(point2[0].y == expected);
+
+ if (failed) {
+ rsDebug("test_Point_2 FAILED", 0);
+ }
+ else {
+ rsDebug("test_Point_2 PASSED", 0);
+ }
+
+ return failed;
+}
+
+void struct_test(int expected) {
+ bool failed = false;
+ failed |= test_Point_2(expected);
+
+ if (failed) {
+ rsSendToClientBlocking(RS_MSG_TEST_FAILED);
+ }
+ else {
+ rsSendToClientBlocking(RS_MSG_TEST_PASSED);
+ }
+}
+
diff --git a/tests/TileBenchmark/res/values/strings.xml b/tests/TileBenchmark/res/values/strings.xml
index 5af52dc..6c7055b 100644
--- a/tests/TileBenchmark/res/values/strings.xml
+++ b/tests/TileBenchmark/res/values/strings.xml
@@ -49,8 +49,9 @@
<!-- Drop down menu entry - automatically scroll to the end of the page
with scrollBy() [CHAR LIMIT=15] -->
<string name="movement_auto_scroll">Auto-scroll</string>
- <!-- Drop down menu entry - [CHAR LIMIT=15] -->
- <string name="movement_auto_fling">Auto-fling</string>
+ <!-- Drop down menu entry - automatically record for a set time before
+ stopping [CHAR LIMIT=15] -->
+ <string name="movement_timed">Timed</string>
<!-- Drop down menu entry - manually navigate the page(s), hit 'capture'
button [CHAR LIMIT=15] -->
<string name="movement_manual">Manual</string>
@@ -67,14 +68,21 @@
<!-- 75th percentile - 75% of frames fall below this value [CHAR LIMIT=12]
-->
<string name="percentile_75">75%ile</string>
+ <!-- standard deviation [CHAR LIMIT=12] -->
+ <string name="std_dev">StdDev</string>
+ <!-- mean [CHAR LIMIT=12] -->
+ <string name="mean">mean</string>
+
+
+
<!-- Frame rate [CHAR LIMIT=15] -->
<string name="frames_per_second">Frames/sec</string>
<!-- Portion of viewport covered by good tiles [CHAR LIMIT=15] -->
<string name="viewport_coverage">Coverage</string>
<!-- Milliseconds taken to inval, and re-render the page [CHAR LIMIT=15] -->
<string name="render_millis">RenderMillis</string>
- <!-- Number of rendering stalls while running the test [CHAR LIMIT=15] -->
- <string name="render_stalls">Stalls</string>
+ <!-- Animation Framerate [CHAR LIMIT=15] -->
+ <string name="animation_framerate">AnimFramerate</string>
<!-- Format string for stat value overlay [CHAR LIMIT=15] -->
<string name="format_stat">%4.4f</string>
diff --git a/tests/TileBenchmark/src/com/test/tilebenchmark/PerformanceTest.java b/tests/TileBenchmark/src/com/test/tilebenchmark/PerformanceTest.java
index cc39b75..6356cc1 100644
--- a/tests/TileBenchmark/src/com/test/tilebenchmark/PerformanceTest.java
+++ b/tests/TileBenchmark/src/com/test/tilebenchmark/PerformanceTest.java
@@ -27,17 +27,57 @@
import android.os.Environment;
import android.test.ActivityInstrumentationTestCase2;
import android.util.Log;
+import android.webkit.WebSettings;
+import android.widget.Spinner;
public class PerformanceTest extends
ActivityInstrumentationTestCase2<ProfileActivity> {
+ public static class AnimStat {
+ double aggVal = 0;
+ double aggSqrVal = 0;
+ double count = 0;
+ }
+
private class StatAggregator extends PlaybackGraphs {
private HashMap<String, Double> mDataMap = new HashMap<String, Double>();
+ private HashMap<String, AnimStat> mAnimDataMap = new HashMap<String, AnimStat>();
private int mCount = 0;
+
public void aggregate() {
+ boolean inAnimTests = mAnimTests != null;
+ Resources resources = mWeb.getResources();
+ String animFramerateString = resources.getString(R.string.animation_framerate);
+ for (Map.Entry<String, Double> e : mSingleStats.entrySet()) {
+ String name = e.getKey();
+ if (inAnimTests) {
+ if (name.equals(animFramerateString)) {
+ // in animation testing phase, record animation framerate and aggregate
+ // stats, differentiating on values of mAnimTestNr and mDoubleBuffering
+ String fullName = ANIM_TEST_NAMES[mAnimTestNr] + " " + name;
+ fullName += mDoubleBuffering ? " tiled" : " webkit";
+
+ if (!mAnimDataMap.containsKey(fullName)) {
+ mAnimDataMap.put(fullName, new AnimStat());
+ }
+ AnimStat statVals = mAnimDataMap.get(fullName);
+ statVals.aggVal += e.getValue();
+ statVals.aggSqrVal += e.getValue() * e.getValue();
+ statVals.count += 1;
+ }
+ } else {
+ double aggVal = mDataMap.containsKey(name)
+ ? mDataMap.get(name) : 0;
+ mDataMap.put(name, aggVal + e.getValue());
+ }
+ }
+
+ if (inAnimTests) {
+ return;
+ }
+
mCount++;
- Resources resources = mView.getResources();
for (int metricIndex = 0; metricIndex < Metrics.length; metricIndex++) {
for (int statIndex = 0; statIndex < Stats.length; statIndex++) {
String metricLabel = resources.getString(
@@ -53,34 +93,47 @@
mDataMap.put(label, aggVal);
}
}
- for (Map.Entry<String, Double> e : mSingleStats.entrySet()) {
- double aggVal = mDataMap.containsKey(e.getKey())
- ? mDataMap.get(e.getKey()) : 0;
- mDataMap.put(e.getKey(), aggVal + e.getValue());
- }
+
}
+ // build the final bundle of results
public Bundle getBundle() {
Bundle b = new Bundle();
- int count = 0 == mCount ? Integer.MAX_VALUE : mCount;
+ int count = (0 == mCount) ? Integer.MAX_VALUE : mCount;
for (Map.Entry<String, Double> e : mDataMap.entrySet()) {
b.putDouble(e.getKey(), e.getValue() / count);
}
+
+ for (Map.Entry<String, AnimStat> e : mAnimDataMap.entrySet()) {
+ String statName = e.getKey();
+ AnimStat statVals = e.getValue();
+
+ double avg = statVals.aggVal/statVals.count;
+ double stdDev = Math.sqrt((statVals.aggSqrVal / statVals.count) - avg * avg);
+
+ b.putDouble(statName, avg);
+ b.putDouble(statName + " STD DEV", stdDev);
+ }
+
return b;
}
}
ProfileActivity mActivity;
- ProfiledWebView mView;
- StatAggregator mStats = new StatAggregator();
+ ProfiledWebView mWeb;
+ Spinner mMovementSpinner;
+ StatAggregator mStats;
private static final String LOGTAG = "PerformanceTest";
private static final String TEST_LOCATION = "webkit/page_cycler";
private static final String URL_PREFIX = "file://";
private static final String URL_POSTFIX = "/index.html?skip=true";
private static final int MAX_ITERATIONS = 4;
- private static final String TEST_DIRS[] = {
- "alexa25_2011"//, "alexa_us", "android", "dom", "intl2", "moz", "moz2"
+ private static final String SCROLL_TEST_DIRS[] = {
+ "alexa25_2011"
+ };
+ private static final String ANIM_TEST_DIRS[] = {
+ "dhtml"
};
public PerformanceTest() {
@@ -91,7 +144,22 @@
protected void setUp() throws Exception {
super.setUp();
mActivity = getActivity();
- mView = (ProfiledWebView) mActivity.findViewById(R.id.web);
+ mWeb = (ProfiledWebView) mActivity.findViewById(R.id.web);
+ mMovementSpinner = (Spinner) mActivity.findViewById(R.id.movement);
+ mStats = new StatAggregator();
+
+ // use mStats as a condition variable between the UI thread and
+ // this(the testing) thread
+ mActivity.setCallback(new ProfileCallback() {
+ @Override
+ public void profileCallback(RunData data) {
+ mStats.setData(data);
+ synchronized (mStats) {
+ mStats.notify();
+ }
+ }
+ });
+
}
private boolean loadUrl(final String url) {
@@ -100,12 +168,13 @@
mActivity.runOnUiThread(new Runnable() {
@Override
public void run() {
- mView.loadUrl(url);
+ mWeb.loadUrl(url);
}
});
synchronized (mStats) {
mStats.wait();
}
+
mStats.aggregate();
} catch (InterruptedException e) {
e.printStackTrace();
@@ -114,15 +183,30 @@
return true;
}
- private boolean runIteration() {
+ private boolean validTest(String nextTest) {
+ // if testing animations, test must be in mAnimTests
+ if (mAnimTests == null)
+ return true;
+
+ for (String test : mAnimTests) {
+ if (test.equals(nextTest)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ private boolean runIteration(String[] testDirs) {
File sdFile = Environment.getExternalStorageDirectory();
- for (String testDirName : TEST_DIRS) {
+ for (String testDirName : testDirs) {
File testDir = new File(sdFile, TEST_LOCATION + "/" + testDirName);
Log.d(LOGTAG, "Testing dir: '" + testDir.getAbsolutePath()
+ "', exists=" + testDir.exists());
+
for (File siteDir : testDir.listFiles()) {
- if (!siteDir.isDirectory())
+ if (!siteDir.isDirectory() || !validTest(siteDir.getName())) {
continue;
+ }
if (!loadUrl(URL_PREFIX + siteDir.getAbsolutePath()
+ URL_POSTFIX)) {
@@ -133,7 +217,44 @@
return true;
}
- public void testMetrics() {
+ private boolean runTestDirs(String[] testDirs) {
+ for (int i = 0; i < MAX_ITERATIONS; i++)
+ if (!runIteration(testDirs)) {
+ return false;
+ }
+ return true;
+ }
+
+ private void pushDoubleBuffering() {
+ getInstrumentation().runOnMainSync(new Runnable() {
+ public void run() {
+ mWeb.setDoubleBuffering(mDoubleBuffering);
+ }
+ });
+ }
+
+ private void setScrollingTestingMode(final boolean scrolled) {
+ getInstrumentation().runOnMainSync(new Runnable() {
+ public void run() {
+ mMovementSpinner.setSelection(scrolled ? 0 : 2);
+ }
+ });
+ }
+
+
+ private String[] mAnimTests = null;
+ private int mAnimTestNr = -1;
+ private boolean mDoubleBuffering = true;
+ private static final String[] ANIM_TEST_NAMES = {
+ "slow", "fast"
+ };
+ private static final String[][] ANIM_TESTS = {
+ {"scrolling", "replaceimages", "layers5", "layers1"},
+ {"slidingballs", "meter", "slidein", "fadespacing", "colorfade",
+ "mozilla", "movingtext", "diagball", "zoom", "imageslide"},
+ };
+
+ private boolean checkMedia() {
String state = Environment.getExternalStorageState();
if (!Environment.MEDIA_MOUNTED.equals(state)
@@ -141,27 +262,43 @@
Log.d(LOGTAG, "ARG Can't access sd card!");
// Can't read the SD card, fail and die!
getInstrumentation().sendStatus(1, null);
- return;
+ return false;
}
+ return true;
+ }
- // use mGraphs as a condition variable between the UI thread and
- // this(the testing) thread
- mActivity.setCallback(new ProfileCallback() {
- @Override
- public void profileCallback(RunData data) {
- Log.d(LOGTAG, "test completion callback");
- mStats.setData(data);
- synchronized (mStats) {
- mStats.notify();
+ public void testMetrics() {
+ setScrollingTestingMode(true);
+ if (checkMedia() && runTestDirs(SCROLL_TEST_DIRS)) {
+ getInstrumentation().sendStatus(0, mStats.getBundle());
+ } else {
+ getInstrumentation().sendStatus(1, null);
+ }
+ }
+
+ private boolean runAnimationTests() {
+ for (int doubleBuffer = 0; doubleBuffer <= 1; doubleBuffer++) {
+ mDoubleBuffering = doubleBuffer == 1;
+ pushDoubleBuffering();
+ for (mAnimTestNr = 0; mAnimTestNr < ANIM_TESTS.length; mAnimTestNr++) {
+ mAnimTests = ANIM_TESTS[mAnimTestNr];
+ if (!runTestDirs(ANIM_TEST_DIRS)) {
+ return false;
}
}
- });
+ }
+ return true;
+ }
- for (int i = 0; i < MAX_ITERATIONS; i++)
- if (!runIteration()) {
- getInstrumentation().sendStatus(1, null);
- return;
- }
- getInstrumentation().sendStatus(0, mStats.getBundle());
+ public void testAnimations() {
+ // instead of autoscrolling, load each page until either an timer fires,
+ // or the animation signals complete via javascript
+ setScrollingTestingMode(false);
+
+ if (checkMedia() && runAnimationTests()) {
+ getInstrumentation().sendStatus(0, mStats.getBundle());
+ } else {
+ getInstrumentation().sendStatus(1, null);
+ }
}
}
diff --git a/tests/TileBenchmark/src/com/test/tilebenchmark/PlaybackGraphs.java b/tests/TileBenchmark/src/com/test/tilebenchmark/PlaybackGraphs.java
index 9ea90f8..a3ae9be 100644
--- a/tests/TileBenchmark/src/com/test/tilebenchmark/PlaybackGraphs.java
+++ b/tests/TileBenchmark/src/com/test/tilebenchmark/PlaybackGraphs.java
@@ -80,7 +80,7 @@
for (int tileID = 1; tileID < frame.length; tileID++) {
TileData data = frame[tileID];
double coverage = viewportCoverage(frame[0], data);
- total += coverage * (data.isReady ? 1 : 0);
+ total += coverage * (data.isReady ? 100 : 0);
totalCount += coverage;
}
if (totalCount == 0) {
@@ -91,7 +91,7 @@
@Override
public double getMax() {
- return 1;
+ return 100;
}
@Override
@@ -108,6 +108,9 @@
}
public static double getPercentile(double sortedValues[], double ratioAbove) {
+ if (sortedValues.length == 0)
+ return -1;
+
double index = ratioAbove * (sortedValues.length - 1);
int intIndex = (int) Math.floor(index);
if (index == intIndex) {
@@ -118,6 +121,31 @@
+ sortedValues[intIndex + 1] * (alpha);
}
+ public static double getMean(double sortedValues[]) {
+ if (sortedValues.length == 0)
+ return -1;
+
+ double agg = 0;
+ for (double val : sortedValues) {
+ agg += val;
+ }
+ return agg / sortedValues.length;
+ }
+
+ public static double getStdDev(double sortedValues[]) {
+ if (sortedValues.length == 0)
+ return -1;
+
+ double agg = 0;
+ double sqrAgg = 0;
+ for (double val : sortedValues) {
+ agg += val;
+ sqrAgg += val*val;
+ }
+ double mean = agg / sortedValues.length;
+ return Math.sqrt((sqrAgg / sortedValues.length) - (mean * mean));
+ }
+
protected static StatGen[] Stats = new StatGen[] {
new StatGen() {
@Override
@@ -149,6 +177,26 @@
public int getLabelId() {
return R.string.percentile_75;
}
+ }, new StatGen() {
+ @Override
+ public double getValue(double[] sortedValues) {
+ return getStdDev(sortedValues);
+ }
+
+ @Override
+ public int getLabelId() {
+ return R.string.std_dev;
+ }
+ }, new StatGen() {
+ @Override
+ public double getValue(double[] sortedValues) {
+ return getMean(sortedValues);
+ }
+
+ @Override
+ public int getLabelId() {
+ return R.string.mean;
+ }
},
};
@@ -159,40 +207,47 @@
}
private ArrayList<ShapeDrawable> mShapes = new ArrayList<ShapeDrawable>();
- protected double[][] mStats = new double[Metrics.length][Stats.length];
+ protected final double[][] mStats = new double[Metrics.length][Stats.length];
protected HashMap<String, Double> mSingleStats;
+ private void gatherFrameMetric(int metricIndex, double metricValues[], RunData data) {
+ // create graph out of rectangles, one per frame
+ int lastBar = 0;
+ for (int frameIndex = 0; frameIndex < data.frames.length; frameIndex++) {
+ TileData frame[] = data.frames[frameIndex];
+ int newBar = (frame[0].top + frame[0].bottom) / 2;
+
+ MetricGen s = Metrics[metricIndex];
+ double absoluteValue = s.getValue(frame);
+ double relativeValue = absoluteValue / s.getMax();
+ relativeValue = Math.min(1,relativeValue);
+ relativeValue = Math.max(0,relativeValue);
+ int rightPos = (int) (-BAR_WIDTH * metricIndex);
+ int leftPos = (int) (-BAR_WIDTH * (metricIndex + relativeValue));
+
+ ShapeDrawable graphBar = new ShapeDrawable();
+ graphBar.getPaint().setColor(Color.BLUE);
+ graphBar.setBounds(leftPos, lastBar, rightPos, newBar);
+
+ mShapes.add(graphBar);
+ metricValues[frameIndex] = absoluteValue;
+ lastBar = newBar;
+ }
+ }
+
public void setData(RunData data) {
mShapes.clear();
double metricValues[] = new double[data.frames.length];
+ mSingleStats = data.singleStats;
+
if (data.frames.length == 0) {
return;
}
for (int metricIndex = 0; metricIndex < Metrics.length; metricIndex++) {
- // create graph out of rectangles, one per frame
- int lastBar = 0;
- for (int frameIndex = 0; frameIndex < data.frames.length; frameIndex++) {
- TileData frame[] = data.frames[frameIndex];
- int newBar = (frame[0].top + frame[0].bottom) / 2;
-
- MetricGen s = Metrics[metricIndex];
- double absoluteValue = s.getValue(frame);
- double relativeValue = absoluteValue / s.getMax();
- relativeValue = Math.min(1,relativeValue);
- relativeValue = Math.max(0,relativeValue);
- int rightPos = (int) (-BAR_WIDTH * metricIndex);
- int leftPos = (int) (-BAR_WIDTH * (metricIndex + relativeValue));
-
- ShapeDrawable graphBar = new ShapeDrawable();
- graphBar.getPaint().setColor(Color.BLUE);
- graphBar.setBounds(leftPos, lastBar, rightPos, newBar);
-
- mShapes.add(graphBar);
- metricValues[frameIndex] = absoluteValue;
- lastBar = newBar;
- }
+ // calculate metric based on list of frames
+ gatherFrameMetric(metricIndex, metricValues, data);
// store aggregate statistics per metric (median, and similar)
Arrays.sort(metricValues);
@@ -200,8 +255,6 @@
mStats[metricIndex][statIndex] =
Stats[statIndex].getValue(metricValues);
}
-
- mSingleStats = data.singleStats;
}
}
diff --git a/tests/TileBenchmark/src/com/test/tilebenchmark/ProfileActivity.java b/tests/TileBenchmark/src/com/test/tilebenchmark/ProfileActivity.java
index d38d006..2e77157 100644
--- a/tests/TileBenchmark/src/com/test/tilebenchmark/ProfileActivity.java
+++ b/tests/TileBenchmark/src/com/test/tilebenchmark/ProfileActivity.java
@@ -22,11 +22,12 @@
import android.graphics.Bitmap;
import android.os.AsyncTask;
import android.os.Bundle;
+import android.os.CountDownTimer;
+import android.util.Log;
import android.util.Pair;
import android.view.KeyEvent;
import android.view.View;
import android.view.View.OnClickListener;
-import android.webkit.WebSettings;
import android.webkit.WebView;
import android.webkit.WebViewClient;
import android.widget.AdapterView;
@@ -49,6 +50,8 @@
*/
public class ProfileActivity extends Activity {
+ private static final int TIMED_RECORD_MILLIS = 2000;
+
public interface ProfileCallback {
public void profileCallback(RunData data);
}
@@ -65,6 +68,7 @@
LoggingWebViewClient mLoggingWebViewClient = new LoggingWebViewClient();
AutoLoggingWebViewClient mAutoLoggingWebViewClient = new AutoLoggingWebViewClient();
+ TimedLoggingWebViewClient mTimedLoggingWebViewClient = new TimedLoggingWebViewClient();
private enum TestingState {
NOT_TESTING,
@@ -93,18 +97,18 @@
public void onItemSelected(AdapterView<?> parent, View view,
int position, long id) {
String movementStr = parent.getItemAtPosition(position).toString();
- if (movementStr == getResources().getString(
- R.string.movement_auto_scroll)
- || movementStr == getResources().getString(
- R.string.movement_auto_fling)) {
+ if (movementStr == getResources().getString(R.string.movement_auto_scroll)) {
mWeb.setWebViewClient(mAutoLoggingWebViewClient);
mCaptureButton.setEnabled(false);
mVelocitySpinner.setEnabled(true);
- } else if (movementStr == getResources().getString(
- R.string.movement_manual)) {
+ } else if (movementStr == getResources().getString(R.string.movement_manual)) {
mWeb.setWebViewClient(mLoggingWebViewClient);
mCaptureButton.setEnabled(true);
mVelocitySpinner.setEnabled(false);
+ } else if (movementStr == getResources().getString(R.string.movement_timed)) {
+ mWeb.setWebViewClient(mTimedLoggingWebViewClient);
+ mCaptureButton.setEnabled(false);
+ mVelocitySpinner.setEnabled(false);
}
}
@@ -124,15 +128,19 @@
super.onPageStarted(view, url, favicon);
mUrl.setText(url);
}
- }
-
- private class AutoLoggingWebViewClient extends LoggingWebViewClient {
@Override
public void onPageFinished(WebView view, String url) {
super.onPageFinished(view, url);
view.requestFocus();
+ ((ProfiledWebView)view).onPageFinished();
+ }
+ }
+ private class AutoLoggingWebViewClient extends LoggingWebViewClient {
+ @Override
+ public void onPageFinished(WebView view, String url) {
+ super.onPageFinished(view, url);
startViewProfiling(true);
}
@@ -143,6 +151,32 @@
}
}
+ private class TimedLoggingWebViewClient extends LoggingWebViewClient {
+ @Override
+ public void onPageFinished(WebView view, String url) {
+ super.onPageFinished(view, url);
+ startViewProfiling(false);
+
+ // after a fixed time after page finished, stop testing
+ new CountDownTimer(TIMED_RECORD_MILLIS, TIMED_RECORD_MILLIS) {
+ @Override
+ public void onTick(long millisUntilFinished) {
+ }
+
+ @Override
+ public void onFinish() {
+ mWeb.stopScrollTest();
+ }
+ }.start();
+ }
+
+ @Override
+ public void onPageStarted(WebView view, String url, Bitmap favicon) {
+ super.onPageStarted(view, url, favicon);
+ setTestingState(TestingState.PRE_TESTING);
+ }
+ }
+
private class StoreFileTask extends
AsyncTask<Pair<String, RunData>, Void, Void> {
@@ -178,11 +212,13 @@
mMovementSpinner.setEnabled(false);
break;
case START_TESTING:
+ mCaptureButton.setChecked(true);
mUrl.setBackgroundResource(R.color.background_start_testing);
mInspectButton.setEnabled(false);
mMovementSpinner.setEnabled(false);
break;
case STOP_TESTING:
+ mCaptureButton.setChecked(false);
mUrl.setBackgroundResource(R.color.background_stop_testing);
break;
case SAVED_TESTING:
@@ -195,7 +231,6 @@
/** auto - automatically scroll. */
private void startViewProfiling(boolean auto) {
// toggle capture button to indicate capture state to user
- mCaptureButton.setChecked(true);
mWeb.startScrollTest(mCallback, auto);
setTestingState(TestingState.START_TESTING);
}
@@ -217,7 +252,7 @@
public void profileCallback(RunData data) {
new StoreFileTask().execute(new Pair<String, RunData>(
TEMP_FILENAME, data));
- mCaptureButton.setChecked(false);
+ Log.d("ProfileActivity", "stored " + data.frames.length + " frames in file");
setTestingState(TestingState.STOP_TESTING);
}
});
@@ -245,8 +280,8 @@
// Movement spinner
String content[] = {
getResources().getString(R.string.movement_auto_scroll),
- getResources().getString(R.string.movement_auto_fling),
- getResources().getString(R.string.movement_manual)
+ getResources().getString(R.string.movement_manual),
+ getResources().getString(R.string.movement_timed)
};
adapter = new ArrayAdapter<CharSequence>(this,
android.R.layout.simple_spinner_item, content);
@@ -270,13 +305,7 @@
});
// Custom profiling WebView
- WebSettings settings = mWeb.getSettings();
- settings.setJavaScriptEnabled(true);
- settings.setSupportZoom(true);
- settings.setEnableSmoothTransition(true);
- settings.setBuiltInZoomControls(true);
- settings.setLoadWithOverviewMode(true);
- settings.setProperty("use_minimal_memory", "false"); // prefetch tiles, as browser does
+ mWeb.init(this);
mWeb.setWebViewClient(new LoggingWebViewClient());
// URL text entry
diff --git a/tests/TileBenchmark/src/com/test/tilebenchmark/ProfiledWebView.java b/tests/TileBenchmark/src/com/test/tilebenchmark/ProfiledWebView.java
index 83f1668..a706f78 100644
--- a/tests/TileBenchmark/src/com/test/tilebenchmark/ProfiledWebView.java
+++ b/tests/TileBenchmark/src/com/test/tilebenchmark/ProfiledWebView.java
@@ -20,21 +20,28 @@
import android.os.CountDownTimer;
import android.util.AttributeSet;
import android.util.Log;
+import android.webkit.WebSettings;
import android.webkit.WebView;
+import android.widget.Toast;
+
+import java.util.ArrayList;
import com.test.tilebenchmark.ProfileActivity.ProfileCallback;
import com.test.tilebenchmark.RunData.TileData;
public class ProfiledWebView extends WebView {
+ private static final String LOGTAG = "ProfiledWebView";
+
private int mSpeed;
private boolean mIsTesting = false;
private boolean mIsScrolling = false;
private ProfileCallback mCallback;
private long mContentInvalMillis;
- private boolean mHadToBeForced = false;
private static final int LOAD_STALL_MILLIS = 2000; // nr of millis after load,
// before test is forced
+ private double mLoadTime;
+ private double mAnimationTime;
public ProfiledWebView(Context context) {
super(context);
@@ -53,6 +60,39 @@
super(context, attrs, defStyle, privateBrowsing);
}
+ private class JavaScriptInterface {
+ Context mContext;
+
+ /** Instantiate the interface and set the context */
+ JavaScriptInterface(Context c) {
+ mContext = c;
+ }
+
+ /** Show a toast from the web page */
+ public void animationComplete() {
+ Toast.makeText(mContext, "Animation complete!", Toast.LENGTH_SHORT).show();
+ //Log.d(LOGTAG, "anim complete");
+ mAnimationTime = System.currentTimeMillis();
+ }
+ }
+
+ public void init(Context c) {
+ WebSettings settings = getSettings();
+ settings.setJavaScriptEnabled(true);
+ settings.setSupportZoom(true);
+ settings.setEnableSmoothTransition(true);
+ settings.setBuiltInZoomControls(true);
+ settings.setLoadWithOverviewMode(true);
+ settings.setProperty("use_minimal_memory", "false"); // prefetch tiles, as browser does
+ addJavascriptInterface(new JavaScriptInterface(c), "Android");
+ mAnimationTime = 0;
+ mLoadTime = 0;
+ }
+
+ public void onPageFinished() {
+ mLoadTime = System.currentTimeMillis();
+ }
+
@Override
protected void onDraw(android.graphics.Canvas canvas) {
if (mIsTesting && mIsScrolling) {
@@ -72,9 +112,12 @@
* scrolling, invalidate all content and redraw it, measuring time taken.
*/
public void startScrollTest(ProfileCallback callback, boolean autoScrolling) {
- mIsScrolling = autoScrolling;
mCallback = callback;
mIsTesting = false;
+ mIsScrolling = false;
+ WebSettings settings = getSettings();
+ settings.setProperty("tree_updates", "0");
+
if (autoScrolling) {
// after a while, force it to start even if the pages haven't swapped
@@ -86,13 +129,18 @@
@Override
public void onFinish() {
// invalidate all content, and kick off redraw
+ Log.d("ProfiledWebView",
+ "kicking off test with callback registration, and tile discard...");
registerPageSwapCallback();
discardAllTextures();
invalidate();
-
+ mIsScrolling = true;
mContentInvalMillis = System.currentTimeMillis();
}
}.start();
+ } else {
+ mIsTesting = true;
+ tileProfilingStart();
}
}
@@ -102,13 +150,35 @@
*/
@Override
protected void pageSwapCallback(boolean startAnim) {
- mContentInvalMillis = System.currentTimeMillis() - mContentInvalMillis;
- super.pageSwapCallback(startAnim);
- Log.d("ProfiledWebView", "REDRAW TOOK " + mContentInvalMillis
- + "millis");
- mIsTesting = true;
- invalidate(); // ensure a redraw so that auto-scrolling can occur
- tileProfilingStart();
+ if (!mIsTesting && mIsScrolling) {
+ // kick off testing
+ mContentInvalMillis = System.currentTimeMillis() - mContentInvalMillis;
+ super.pageSwapCallback(startAnim);
+ Log.d("ProfiledWebView", "REDRAW TOOK " + mContentInvalMillis + "millis");
+ mIsTesting = true;
+ invalidate(); // ensure a redraw so that auto-scrolling can occur
+ tileProfilingStart();
+ }
+ }
+
+ private double animFramerate() {
+ WebSettings settings = getSettings();
+ String updatesString = settings.getProperty("tree_updates");
+ int updates = (updatesString == null) ? -1 : Integer.parseInt(updatesString);
+
+ double animationTime;
+ if (mAnimationTime == 0) {
+ animationTime = System.currentTimeMillis() - mLoadTime;
+ } else {
+ animationTime = mAnimationTime - mLoadTime;
+ }
+
+ return updates * 1000 / animationTime;
+ }
+
+ public void setDoubleBuffering(boolean useDoubleBuffering) {
+ WebSettings settings = getSettings();
+ settings.setProperty("use_double_buffering", useDoubleBuffering ? "true" : "false");
}
/*
@@ -127,11 +197,12 @@
// record the time spent (before scrolling) rendering the page
data.singleStats.put(getResources().getString(R.string.render_millis),
(double)mContentInvalMillis);
- // record if the page render timed out
- Log.d("ProfiledWebView", "hadtobeforced = " + mHadToBeForced);
- data.singleStats.put(getResources().getString(R.string.render_stalls),
- mHadToBeForced ? 1.0 : 0.0);
- mHadToBeForced = false;
+
+ // record framerate
+ double framerate = animFramerate();
+ Log.d(LOGTAG, "anim framerate was "+framerate);
+ data.singleStats.put(getResources().getString(R.string.animation_framerate),
+ framerate);
for (int frame = 0; frame < data.frames.length; frame++) {
data.frames[frame] = new TileData[
@@ -159,6 +230,8 @@
@Override
public void loadUrl(String url) {
+ mAnimationTime = 0;
+ mLoadTime = 0;
if (!url.startsWith("http://") && !url.startsWith("file://")) {
url = "http://" + url;
}
diff --git a/tools/aapt/AaptAssets.cpp b/tools/aapt/AaptAssets.cpp
index f0c215e..6ce665b 100644
--- a/tools/aapt/AaptAssets.cpp
+++ b/tools/aapt/AaptAssets.cpp
@@ -1084,12 +1084,17 @@
if (out) out->density = ResTable_config::DENSITY_HIGH;
return true;
}
-
+
if (strcmp(name, "xhdpi") == 0) {
- if (out) out->density = ResTable_config::DENSITY_MEDIUM*2;
+ if (out) out->density = ResTable_config::DENSITY_XHIGH;
return true;
}
-
+
+ if (strcmp(name, "xxhdpi") == 0) {
+ if (out) out->density = ResTable_config::DENSITY_XXHIGH;
+ return true;
+ }
+
char* c = (char*)name;
while (*c >= '0' && *c <= '9') {
c++;
diff --git a/tools/aapt/AaptAssets.h b/tools/aapt/AaptAssets.h
index d5345b2..c5a397c 100644
--- a/tools/aapt/AaptAssets.h
+++ b/tools/aapt/AaptAssets.h
@@ -53,17 +53,6 @@
AXIS_END = AXIS_VERSION,
};
-enum {
- SDK_CUPCAKE = 3,
- SDK_DONUT = 4,
- SDK_ECLAIR = 5,
- SDK_ECLAIR_0_1 = 6,
- SDK_MR1 = 7,
- SDK_FROYO = 8,
- SDK_HONEYCOMB_MR2 = 13,
- SDK_ICE_CREAM_SANDWICH = 14,
-};
-
/**
* This structure contains a specific variation of a single file out
* of all the variations it can have that we can have.
diff --git a/tools/aapt/Bundle.h b/tools/aapt/Bundle.h
index 2d1060b..8e3a1c9 100644
--- a/tools/aapt/Bundle.h
+++ b/tools/aapt/Bundle.h
@@ -14,6 +14,18 @@
#include <utils/String8.h>
#include <utils/Vector.h>
+enum {
+ SDK_CUPCAKE = 3,
+ SDK_DONUT = 4,
+ SDK_ECLAIR = 5,
+ SDK_ECLAIR_0_1 = 6,
+ SDK_MR1 = 7,
+ SDK_FROYO = 8,
+ SDK_HONEYCOMB_MR2 = 13,
+ SDK_ICE_CREAM_SANDWICH = 14,
+ SDK_ICE_CREAM_SANDWICH_MR1 = 15,
+};
+
/*
* Things we can do.
*/
@@ -82,7 +94,6 @@
void setRequireLocalization(bool val) { mRequireLocalization = val; }
bool getPseudolocalize(void) const { return mPseudolocalize; }
void setPseudolocalize(bool val) { mPseudolocalize = val; }
- bool getWantUTF16(void) const { return mWantUTF16; }
void setWantUTF16(bool val) { mWantUTF16 = val; }
bool getValues(void) const { return mValues; }
void setValues(bool val) { mValues = val; }
@@ -103,6 +114,10 @@
bool getGenDependencies() { return mGenDependencies; }
void setGenDependencies(bool val) { mGenDependencies = val; }
+ bool getUTF16StringsOption() {
+ return mWantUTF16 || !isMinSdkAtLeast(SDK_FROYO);
+ }
+
/*
* Input options.
*/
diff --git a/tools/aapt/Command.cpp b/tools/aapt/Command.cpp
index 89942de..607056a 100644
--- a/tools/aapt/Command.cpp
+++ b/tools/aapt/Command.cpp
@@ -479,6 +479,11 @@
#ifndef HAVE_ANDROID_OS
res.print(bundle->getValues());
#endif
+
+ } else if (strcmp("strings", option) == 0) {
+ const ResStringPool* pool = res.getTableStringBlock(0);
+ printStringPool(pool);
+
} else if (strcmp("xmltree", option) == 0) {
if (bundle->getFileSpecCount() < 3) {
fprintf(stderr, "ERROR: no dump xmltree resource file specified\n");
@@ -1382,7 +1387,7 @@
delete dir;
}
} else if (strcmp("badger", option) == 0) {
- printf(CONSOLE_DATA);
+ printf("%s", CONSOLE_DATA);
} else if (strcmp("configurations", option) == 0) {
Vector<ResTable_config> configs;
res.getConfigurations(&configs);
diff --git a/tools/aapt/Resource.cpp b/tools/aapt/Resource.cpp
index 1ecf7da..c0fe538 100644
--- a/tools/aapt/Resource.cpp
+++ b/tools/aapt/Resource.cpp
@@ -847,8 +847,7 @@
* request UTF-16 encoding and the parameters of this package
* allow UTF-8 to be used.
*/
- if (!bundle->getWantUTF16()
- && bundle->isMinSdkAtLeast(SDK_FROYO)) {
+ if (!bundle->getUTF16StringsOption()) {
xmlFlags |= XML_COMPILE_UTF8;
}
diff --git a/tools/aapt/ResourceTable.cpp b/tools/aapt/ResourceTable.cpp
index fdb39ca..f59bba2 100644
--- a/tools/aapt/ResourceTable.cpp
+++ b/tools/aapt/ResourceTable.cpp
@@ -2047,7 +2047,8 @@
uint32_t attrID,
const Vector<StringPool::entry_style_span>* style,
String16* outStr, void* accessorCookie,
- uint32_t attrType)
+ uint32_t attrType, const String8* configTypeName,
+ const ConfigDescription* config)
{
String16 finalStr;
@@ -2075,10 +2076,19 @@
if (outValue->dataType == outValue->TYPE_STRING) {
// Should do better merging styles.
if (pool) {
- if (style != NULL && style->size() > 0) {
- outValue->data = pool->add(finalStr, *style);
+ String8 configStr;
+ if (config != NULL) {
+ configStr = config->toString();
} else {
- outValue->data = pool->add(finalStr, true);
+ configStr = "(null)";
+ }
+ NOISY(printf("Adding to pool string style #%d config %s: %s\n",
+ style != NULL ? style->size() : 0,
+ configStr.string(), String8(finalStr).string()));
+ if (style != NULL && style->size() > 0) {
+ outValue->data = pool->add(finalStr, *style, configTypeName, config);
+ } else {
+ outValue->data = pool->add(finalStr, true, configTypeName, config);
}
} else {
// Caller will fill this in later.
@@ -2537,16 +2547,19 @@
return err;
}
+ const ConfigDescription nullConfig;
+
const size_t N = mOrderedPackages.size();
size_t pi;
const static String16 mipmap16("mipmap");
- bool useUTF8 = !bundle->getWantUTF16() && bundle->isMinSdkAtLeast(SDK_FROYO);
+ bool useUTF8 = !bundle->getUTF16StringsOption();
// Iterate through all data, collecting all values (strings,
// references, etc).
StringPool valueStrings = StringPool(false, useUTF8);
+ Vector<sp<Entry> > allEntries;
for (pi=0; pi<N; pi++) {
sp<Package> p = mOrderedPackages.itemAt(pi);
if (p->getTypes().size() == 0) {
@@ -2567,6 +2580,19 @@
const String16 typeName(t->getName());
typeStrings.add(typeName, false);
+ // This is a hack to tweak the sorting order of the final strings,
+ // to put stuff that is generally not language-specific first.
+ String8 configTypeName(typeName);
+ if (configTypeName == "drawable" || configTypeName == "layout"
+ || configTypeName == "color" || configTypeName == "anim"
+ || configTypeName == "interpolator" || configTypeName == "animator"
+ || configTypeName == "xml" || configTypeName == "menu"
+ || configTypeName == "mipmap" || configTypeName == "raw") {
+ configTypeName = "1complex";
+ } else {
+ configTypeName = "2value";
+ }
+
const bool filterable = (typeName != mipmap16);
const size_t N = t->getOrderedConfigs().size();
@@ -2586,10 +2612,21 @@
continue;
}
e->setNameIndex(keyStrings.add(e->getName(), true));
- status_t err = e->prepareFlatten(&valueStrings, this);
+
+ // If this entry has no values for other configs,
+ // and is the default config, then it is special. Otherwise
+ // we want to add it with the config info.
+ ConfigDescription* valueConfig = NULL;
+ if (N != 1 || config == nullConfig) {
+ valueConfig = &config;
+ }
+
+ status_t err = e->prepareFlatten(&valueStrings, this,
+ &configTypeName, &config);
if (err != NO_ERROR) {
return err;
}
+ allEntries.add(e);
}
}
}
@@ -2598,6 +2635,17 @@
p->setKeyStrings(keyStrings.createStringBlock());
}
+ if (bundle->getOutputAPKFile() != NULL) {
+ // Now we want to sort the value strings for better locality. This will
+ // cause the positions of the strings to change, so we need to go back
+ // through out resource entries and update them accordingly. Only need
+ // to do this if actually writing the output file.
+ valueStrings.sortByConfig();
+ for (pi=0; pi<allEntries.size(); pi++) {
+ allEntries[pi]->remapStringValue(&valueStrings);
+ }
+ }
+
ssize_t strAmt = 0;
// Now build the array of package chunks.
@@ -3137,14 +3185,16 @@
return hasErrors ? UNKNOWN_ERROR : NO_ERROR;
}
-status_t ResourceTable::Entry::prepareFlatten(StringPool* strings, ResourceTable* table)
+status_t ResourceTable::Entry::prepareFlatten(StringPool* strings, ResourceTable* table,
+ const String8* configTypeName, const ConfigDescription* config)
{
if (mType == TYPE_ITEM) {
Item& it = mItem;
AccessorCookie ac(it.sourcePos, String8(mName), String8(it.value));
if (!table->stringToValue(&it.parsedValue, strings,
it.value, false, true, 0,
- &it.style, NULL, &ac, mItemFormat)) {
+ &it.style, NULL, &ac, mItemFormat,
+ configTypeName, config)) {
return UNKNOWN_ERROR;
}
} else if (mType == TYPE_BAG) {
@@ -3155,7 +3205,8 @@
AccessorCookie ac(it.sourcePos, String8(key), String8(it.value));
if (!table->stringToValue(&it.parsedValue, strings,
it.value, false, true, it.bagKeyId,
- &it.style, NULL, &ac, it.format)) {
+ &it.style, NULL, &ac, it.format,
+ configTypeName, config)) {
return UNKNOWN_ERROR;
}
}
@@ -3167,6 +3218,29 @@
return NO_ERROR;
}
+status_t ResourceTable::Entry::remapStringValue(StringPool* strings)
+{
+ if (mType == TYPE_ITEM) {
+ Item& it = mItem;
+ if (it.parsedValue.dataType == Res_value::TYPE_STRING) {
+ it.parsedValue.data = strings->mapOriginalPosToNewPos(it.parsedValue.data);
+ }
+ } else if (mType == TYPE_BAG) {
+ const size_t N = mBag.size();
+ for (size_t i=0; i<N; i++) {
+ Item& it = mBag.editValueAt(i);
+ if (it.parsedValue.dataType == Res_value::TYPE_STRING) {
+ it.parsedValue.data = strings->mapOriginalPosToNewPos(it.parsedValue.data);
+ }
+ }
+ } else {
+ mPos.error("Error: entry %s is not a single item or a bag.\n",
+ String8(mName).string());
+ return UNKNOWN_ERROR;
+ }
+ return NO_ERROR;
+}
+
ssize_t ResourceTable::Entry::flatten(Bundle* bundle, const sp<AaptFile>& data, bool isPublic)
{
size_t amt = 0;
diff --git a/tools/aapt/ResourceTable.h b/tools/aapt/ResourceTable.h
index 8123bb3..a3e0666 100644
--- a/tools/aapt/ResourceTable.h
+++ b/tools/aapt/ResourceTable.h
@@ -76,6 +76,37 @@
class Type;
class Entry;
+ struct ConfigDescription : public ResTable_config {
+ ConfigDescription() {
+ memset(this, 0, sizeof(*this));
+ size = sizeof(ResTable_config);
+ }
+ ConfigDescription(const ResTable_config&o) {
+ *static_cast<ResTable_config*>(this) = o;
+ size = sizeof(ResTable_config);
+ }
+ ConfigDescription(const ConfigDescription&o) {
+ *static_cast<ResTable_config*>(this) = o;
+ }
+
+ ConfigDescription& operator=(const ResTable_config& o) {
+ *static_cast<ResTable_config*>(this) = o;
+ size = sizeof(ResTable_config);
+ return *this;
+ }
+ ConfigDescription& operator=(const ConfigDescription& o) {
+ *static_cast<ResTable_config*>(this) = o;
+ return *this;
+ }
+
+ inline bool operator<(const ConfigDescription& o) const { return compare(o) < 0; }
+ inline bool operator<=(const ConfigDescription& o) const { return compare(o) <= 0; }
+ inline bool operator==(const ConfigDescription& o) const { return compare(o) == 0; }
+ inline bool operator!=(const ConfigDescription& o) const { return compare(o) != 0; }
+ inline bool operator>=(const ConfigDescription& o) const { return compare(o) >= 0; }
+ inline bool operator>(const ConfigDescription& o) const { return compare(o) > 0; }
+ };
+
ResourceTable(Bundle* bundle, const String16& assetsPackage);
status_t addIncludedResources(Bundle* bundle, const sp<AaptAssets>& assets);
@@ -183,7 +214,9 @@
uint32_t attrID,
const Vector<StringPool::entry_style_span>* style = NULL,
String16* outStr = NULL, void* accessorCookie = NULL,
- uint32_t attrType = ResTable_map::TYPE_ANY);
+ uint32_t attrType = ResTable_map::TYPE_ANY,
+ const String8* configTypeName = NULL,
+ const ConfigDescription* config = NULL);
status_t assignResourceIds();
status_t addSymbols(const sp<AaptSymbols>& outSymbols = NULL);
@@ -305,7 +338,10 @@
status_t assignResourceIds(ResourceTable* table,
const String16& package);
- status_t prepareFlatten(StringPool* strings, ResourceTable* table);
+ status_t prepareFlatten(StringPool* strings, ResourceTable* table,
+ const String8* configTypeName, const ConfigDescription* config);
+
+ status_t remapStringValue(StringPool* strings);
ssize_t flatten(Bundle*, const sp<AaptFile>& data, bool isPublic);
@@ -322,37 +358,6 @@
uint32_t mParentId;
SourcePos mPos;
};
-
- struct ConfigDescription : public ResTable_config {
- ConfigDescription() {
- memset(this, 0, sizeof(*this));
- size = sizeof(ResTable_config);
- }
- ConfigDescription(const ResTable_config&o) {
- *static_cast<ResTable_config*>(this) = o;
- size = sizeof(ResTable_config);
- }
- ConfigDescription(const ConfigDescription&o) {
- *static_cast<ResTable_config*>(this) = o;
- }
-
- ConfigDescription& operator=(const ResTable_config& o) {
- *static_cast<ResTable_config*>(this) = o;
- size = sizeof(ResTable_config);
- return *this;
- }
- ConfigDescription& operator=(const ConfigDescription& o) {
- *static_cast<ResTable_config*>(this) = o;
- return *this;
- }
-
- inline bool operator<(const ConfigDescription& o) const { return compare(o) < 0; }
- inline bool operator<=(const ConfigDescription& o) const { return compare(o) <= 0; }
- inline bool operator==(const ConfigDescription& o) const { return compare(o) == 0; }
- inline bool operator!=(const ConfigDescription& o) const { return compare(o) != 0; }
- inline bool operator>=(const ConfigDescription& o) const { return compare(o) >= 0; }
- inline bool operator>(const ConfigDescription& o) const { return compare(o) > 0; }
- };
class ConfigList : public RefBase {
public:
diff --git a/tools/aapt/StringPool.cpp b/tools/aapt/StringPool.cpp
index 9a0a1c4..fe88e37 100644
--- a/tools/aapt/StringPool.cpp
+++ b/tools/aapt/StringPool.cpp
@@ -5,8 +5,10 @@
//
#include "StringPool.h"
+#include "ResourceTable.h"
#include <utils/ByteOrder.h>
+#include <utils/SortedVector.h>
#if HAVE_PRINTF_ZD
# define ZD "%zd"
@@ -30,31 +32,87 @@
void printStringPool(const ResStringPool* pool)
{
+ SortedVector<const void*> uniqueStrings;
+ const size_t N = pool->size();
+ for (size_t i=0; i<N; i++) {
+ size_t len;
+ if (pool->isUTF8()) {
+ uniqueStrings.add(pool->string8At(i, &len));
+ } else {
+ uniqueStrings.add(pool->stringAt(i, &len));
+ }
+ }
+
+ printf("String pool of " ZD " unique %s %s strings, " ZD " entries and "
+ ZD " styles using " ZD " bytes:\n",
+ (ZD_TYPE)uniqueStrings.size(), pool->isUTF8() ? "UTF-8" : "UTF-16",
+ pool->isSorted() ? "sorted" : "non-sorted",
+ (ZD_TYPE)N, (ZD_TYPE)pool->styleCount(), (ZD_TYPE)pool->bytes());
+
const size_t NS = pool->size();
for (size_t s=0; s<NS; s++) {
- size_t len;
- const char *str = (const char*)pool->string8At(s, &len);
- if (str == NULL) {
- str = String8(pool->stringAt(s, &len)).string();
- }
-
- printf("String #" ZD ": %s\n", (ZD_TYPE) s, str);
+ String8 str = pool->string8ObjectAt(s);
+ printf("String #" ZD ": %s\n", (ZD_TYPE) s, str.string());
}
}
+String8 StringPool::entry::makeConfigsString() const {
+ String8 configStr(configTypeName);
+ if (configStr.size() > 0) configStr.append(" ");
+ if (configs.size() > 0) {
+ for (size_t j=0; j<configs.size(); j++) {
+ if (j > 0) configStr.append(", ");
+ configStr.append(configs[j].toString());
+ }
+ } else {
+ configStr = "(none)";
+ }
+ return configStr;
+}
+
+int StringPool::entry::compare(const entry& o) const {
+ // Strings with styles go first, to reduce the size of the
+ // styles array.
+ if (hasStyles) {
+ return o.hasStyles ? 0 : -1;
+ }
+ if (o.hasStyles) {
+ return 1;
+ }
+ int comp = configTypeName.compare(o.configTypeName);
+ if (comp != 0) {
+ return comp;
+ }
+ const size_t LHN = configs.size();
+ const size_t RHN = o.configs.size();
+ size_t i=0;
+ while (i < LHN && i < RHN) {
+ comp = configs[i].compareLogical(o.configs[i]);
+ if (comp != 0) {
+ return comp;
+ }
+ i++;
+ }
+ if (LHN < RHN) return -1;
+ else if (LHN > RHN) return 1;
+ return 0;
+}
+
StringPool::StringPool(bool sorted, bool utf8)
: mSorted(sorted), mUTF8(utf8), mValues(-1), mIdents(-1)
{
}
-ssize_t StringPool::add(const String16& value, bool mergeDuplicates)
+ssize_t StringPool::add(const String16& value, bool mergeDuplicates,
+ const String8* configTypeName, const ResTable_config* config)
{
- return add(String16(), value, mergeDuplicates);
+ return add(String16(), value, mergeDuplicates, configTypeName, config);
}
-ssize_t StringPool::add(const String16& value, const Vector<entry_style_span>& spans)
+ssize_t StringPool::add(const String16& value, const Vector<entry_style_span>& spans,
+ const String8* configTypeName, const ResTable_config* config)
{
- ssize_t res = add(String16(), value, false);
+ ssize_t res = add(String16(), value, false, configTypeName, config);
if (res >= 0) {
addStyleSpans(res, spans);
}
@@ -62,7 +120,7 @@
}
ssize_t StringPool::add(const String16& ident, const String16& value,
- bool mergeDuplicates)
+ bool mergeDuplicates, const String8* configTypeName, const ResTable_config* config)
{
if (ident.size() > 0) {
ssize_t idx = mIdents.valueFor(ident);
@@ -84,20 +142,43 @@
}
}
+ if (configTypeName != NULL) {
+ entry& ent = mEntries.editItemAt(eidx);
+ NOISY(printf("*** adding config type name %s, was %s\n",
+ configTypeName->string(), ent.configTypeName.string()));
+ if (ent.configTypeName.size() <= 0) {
+ ent.configTypeName = *configTypeName;
+ } else if (ent.configTypeName != *configTypeName) {
+ ent.configTypeName = " ";
+ }
+ }
+
+ if (config != NULL) {
+ // Add this to the set of configs associated with the string.
+ entry& ent = mEntries.editItemAt(eidx);
+ size_t addPos;
+ for (addPos=0; addPos<ent.configs.size(); addPos++) {
+ int cmp = ent.configs.itemAt(addPos).compareLogical(*config);
+ if (cmp >= 0) {
+ if (cmp > 0) {
+ NOISY(printf("*** inserting config: %s\n", config->toString().string()));
+ ent.configs.insertAt(*config, addPos);
+ }
+ break;
+ }
+ }
+ if (addPos >= ent.configs.size()) {
+ NOISY(printf("*** adding config: %s\n", config->toString().string()));
+ ent.configs.add(*config);
+ }
+ }
+
const bool first = vidx < 0;
if (first || !mergeDuplicates) {
pos = mEntryArray.add(eidx);
if (first) {
vidx = mValues.add(value, pos);
- const size_t N = mEntryArrayToValues.size();
- for (size_t i=0; i<N; i++) {
- size_t& e = mEntryArrayToValues.editItemAt(i);
- if ((ssize_t)e >= vidx) {
- e++;
- }
- }
}
- mEntryArrayToValues.add(vidx);
if (!mSorted) {
entry& ent = mEntries.editItemAt(eidx);
ent.indices.add(pos);
@@ -147,6 +228,7 @@
entry_style& style = mEntryStyleArray.editItemAt(idx);
style.spans.add(span);
+ mEntries.editItemAt(mEntryArray[idx]).hasStyles = true;
return NO_ERROR;
}
@@ -169,6 +251,132 @@
return mIdents.size();
}
+int StringPool::config_sort(const size_t* lhs, const size_t* rhs, void* state)
+{
+ StringPool* pool = (StringPool*)state;
+ const entry& lhe = pool->mEntries[pool->mEntryArray[*lhs]];
+ const entry& rhe = pool->mEntries[pool->mEntryArray[*rhs]];
+ return lhe.compare(rhe);
+}
+
+void StringPool::sortByConfig()
+{
+ LOG_ALWAYS_FATAL_IF(mSorted, "Can't sort string pool containing identifiers.");
+ LOG_ALWAYS_FATAL_IF(mIdents.size() > 0, "Can't sort string pool containing identifiers.");
+ LOG_ALWAYS_FATAL_IF(mOriginalPosToNewPos.size() > 0, "Can't sort string pool after already sorted.");
+
+ const size_t N = mEntryArray.size();
+
+ // This is a vector that starts out with a 1:1 mapping to entries
+ // in the array, which we will sort to come up with the desired order.
+ // At that point it maps from the new position in the array to the
+ // original position the entry appeared.
+ Vector<size_t> newPosToOriginalPos;
+ for (size_t i=0; i<mEntryArray.size(); i++) {
+ newPosToOriginalPos.add(i);
+ }
+
+ // Sort the array.
+ NOISY(printf("SORTING STRINGS BY CONFIGURATION...\n"));
+ newPosToOriginalPos.sort(config_sort, this);
+ NOISY(printf("DONE SORTING STRINGS BY CONFIGURATION.\n"));
+
+ // Create the reverse mapping from the original position in the array
+ // to the new position where it appears in the sorted array. This is
+ // so that clients can re-map any positions they had previously stored.
+ mOriginalPosToNewPos = newPosToOriginalPos;
+ for (size_t i=0; i<N; i++) {
+ mOriginalPosToNewPos.editItemAt(newPosToOriginalPos[i]) = i;
+ }
+
+#if 0
+ SortedVector<entry> entries;
+
+ for (size_t i=0; i<N; i++) {
+ printf("#%d was %d: %s\n", i, newPosToOriginalPos[i],
+ mEntries[mEntryArray[newPosToOriginalPos[i]]].makeConfigsString().string());
+ entries.add(mEntries[mEntryArray[i]]);
+ }
+
+ for (size_t i=0; i<entries.size(); i++) {
+ printf("Sorted config #%d: %s\n", i,
+ entries[i].makeConfigsString().string());
+ }
+#endif
+
+ // Now we rebuild the arrays.
+ Vector<entry> newEntries;
+ Vector<size_t> newEntryArray;
+ Vector<entry_style> newEntryStyleArray;
+ DefaultKeyedVector<size_t, size_t> origOffsetToNewOffset;
+
+ for (size_t i=0; i<N; i++) {
+ // We are filling in new offset 'i'; oldI is where we can find it
+ // in the original data structure.
+ size_t oldI = newPosToOriginalPos[i];
+ // This is the actual entry associated with the old offset.
+ const entry& oldEnt = mEntries[mEntryArray[oldI]];
+ // This is the same entry the last time we added it to the
+ // new entry array, if any.
+ ssize_t newIndexOfOffset = origOffsetToNewOffset.indexOfKey(oldI);
+ size_t newOffset;
+ if (newIndexOfOffset < 0) {
+ // This is the first time we have seen the entry, so add
+ // it.
+ newOffset = newEntries.add(oldEnt);
+ newEntries.editItemAt(newOffset).indices.clear();
+ } else {
+ // We have seen this entry before, use the existing one
+ // instead of adding it again.
+ newOffset = origOffsetToNewOffset.valueAt(newIndexOfOffset);
+ }
+ // Update the indices to include this new position.
+ newEntries.editItemAt(newOffset).indices.add(i);
+ // And add the offset of the entry to the new entry array.
+ newEntryArray.add(newOffset);
+ // Add any old style to the new style array.
+ if (mEntryStyleArray.size() > 0) {
+ if (oldI < mEntryStyleArray.size()) {
+ newEntryStyleArray.add(mEntryStyleArray[oldI]);
+ } else {
+ newEntryStyleArray.add(entry_style());
+ }
+ }
+ }
+
+ // Now trim any entries at the end of the new style array that are
+ // not needed.
+ for (ssize_t i=newEntryStyleArray.size()-1; i>=0; i--) {
+ const entry_style& style = newEntryStyleArray[i];
+ if (style.spans.size() > 0) {
+ // That's it.
+ break;
+ }
+ // This one is not needed; remove.
+ newEntryStyleArray.removeAt(i);
+ }
+
+ // All done, install the new data structures and upate mValues with
+ // the new positions.
+ mEntries = newEntries;
+ mEntryArray = newEntryArray;
+ mEntryStyleArray = newEntryStyleArray;
+ mValues.clear();
+ for (size_t i=0; i<mEntries.size(); i++) {
+ const entry& ent = mEntries[i];
+ mValues.add(ent.value, ent.indices[0]);
+ }
+
+#if 0
+ printf("FINAL SORTED STRING CONFIGS:\n");
+ for (size_t i=0; i<mEntries.size(); i++) {
+ const entry& ent = mEntries[i];
+ printf("#" ZD " %s: %s\n", (ZD_TYPE)i, ent.makeConfigsString().string(),
+ String8(ent.value).string());
+ }
+#endif
+}
+
sp<AaptFile> StringPool::createStringBlock()
{
sp<AaptFile> pool = new AaptFile(String8(), AaptGroupEntry(),
diff --git a/tools/aapt/StringPool.h b/tools/aapt/StringPool.h
index 7275259..255bdbf 100644
--- a/tools/aapt/StringPool.h
+++ b/tools/aapt/StringPool.h
@@ -40,12 +40,28 @@
public:
struct entry {
entry() : offset(0) { }
- entry(const String16& _value) : value(_value), offset(0) { }
- entry(const entry& o) : value(o.value), offset(o.offset), indices(o.indices) { }
+ entry(const String16& _value) : value(_value), offset(0), hasStyles(false) { }
+ entry(const entry& o) : value(o.value), offset(o.offset),
+ hasStyles(o.hasStyles), indices(o.indices),
+ configTypeName(o.configTypeName), configs(o.configs) { }
String16 value;
size_t offset;
+ bool hasStyles;
Vector<size_t> indices;
+ String8 configTypeName;
+ Vector<ResTable_config> configs;
+
+ String8 makeConfigsString() const;
+
+ int compare(const entry& o) const;
+
+ inline bool operator<(const entry& o) const { return compare(o) < 0; }
+ inline bool operator<=(const entry& o) const { return compare(o) <= 0; }
+ inline bool operator==(const entry& o) const { return compare(o) == 0; }
+ inline bool operator!=(const entry& o) const { return compare(o) != 0; }
+ inline bool operator>=(const entry& o) const { return compare(o) >= 0; }
+ inline bool operator>(const entry& o) const { return compare(o) > 0; }
};
struct entry_style_span {
@@ -84,12 +100,15 @@
* if this string pool is sorted, the returned index will not be valid
* when the pool is finally written.
*/
- ssize_t add(const String16& value, bool mergeDuplicates = false);
+ ssize_t add(const String16& value, bool mergeDuplicates = false,
+ const String8* configTypeName = NULL, const ResTable_config* config = NULL);
- ssize_t add(const String16& value, const Vector<entry_style_span>& spans);
+ ssize_t add(const String16& value, const Vector<entry_style_span>& spans,
+ const String8* configTypeName = NULL, const ResTable_config* config = NULL);
ssize_t add(const String16& ident, const String16& value,
- bool mergeDuplicates = false);
+ bool mergeDuplicates = false,
+ const String8* configTypeName = NULL, const ResTable_config* config = NULL);
status_t addStyleSpan(size_t idx, const String16& name,
uint32_t start, uint32_t end);
@@ -102,6 +121,18 @@
size_t countIdentifiers() const;
+ // Sort the contents of the string block by the configuration associated
+ // with each item. After doing this you can use mapOriginalPosToNewPos()
+ // to find out the new position given the position originall returned by
+ // add().
+ void sortByConfig();
+
+ // For use after sortByConfig() to map from the original position of
+ // a string to its new sorted position.
+ size_t mapOriginalPosToNewPos(size_t originalPos) const {
+ return mOriginalPosToNewPos.itemAt(originalPos);
+ }
+
sp<AaptFile> createStringBlock();
status_t writeStringBlock(const sp<AaptFile>& pool);
@@ -125,27 +156,41 @@
const Vector<size_t>* offsetsForString(const String16& val) const;
private:
+ static int config_sort(const size_t* lhs, const size_t* rhs, void* state);
+
const bool mSorted;
const bool mUTF8;
- // Raw array of unique strings, in some arbitrary order.
+
+ // The following data structures represent the actual structures
+ // that will be generated for the final string pool.
+
+ // Raw array of unique strings, in some arbitrary order. This is the
+ // actual strings that appear in the final string pool, in the order
+ // that they will be written.
Vector<entry> mEntries;
// Array of indices into mEntries, in the order they were
// added to the pool. This can be different than mEntries
// if the same string was added multiple times (it will appear
// once in mEntries, with multiple occurrences in this array).
+ // This is the lookup array that will be written for finding
+ // the string for each offset/position in the string pool.
Vector<size_t> mEntryArray;
// Optional style span information associated with each index of
// mEntryArray.
Vector<entry_style> mEntryStyleArray;
- // Mapping from indices in mEntryArray to indices in mValues.
- Vector<size_t> mEntryArrayToValues;
+
+ // The following data structures are used for book-keeping as the
+ // string pool is constructed.
+
// Unique set of all the strings added to the pool, mapped to
// the first index of mEntryArray where the value was added.
DefaultKeyedVector<String16, ssize_t> mValues;
// Unique set of all (optional) identifiers of strings in the
// pool, mapping to indices in mEntries.
DefaultKeyedVector<String16, ssize_t> mIdents;
-
+ // This array maps from the original position a string was placed at
+ // in mEntryArray to its new position after being sorted with sortByConfig().
+ Vector<size_t> mOriginalPosToNewPos;
};
#endif
diff --git a/tools/layoutlib/bridge/.settings/README.txt b/tools/layoutlib/bridge/.settings/README.txt
new file mode 100644
index 0000000..9120b20
--- /dev/null
+++ b/tools/layoutlib/bridge/.settings/README.txt
@@ -0,0 +1,2 @@
+Copy this in eclipse project as a .settings folder at the root.
+This ensure proper compilation compliance and warning/error levels.
\ No newline at end of file
diff --git a/tools/layoutlib/bridge/.settings/org.eclipse.jdt.core.prefs b/tools/layoutlib/bridge/.settings/org.eclipse.jdt.core.prefs
new file mode 100644
index 0000000..5381a0e
--- /dev/null
+++ b/tools/layoutlib/bridge/.settings/org.eclipse.jdt.core.prefs
@@ -0,0 +1,93 @@
+eclipse.preferences.version=1
+org.eclipse.jdt.core.compiler.annotation.nonnull=com.android.annotations.NonNull
+org.eclipse.jdt.core.compiler.annotation.nonnullbydefault=com.android.annotations.NonNullByDefault
+org.eclipse.jdt.core.compiler.annotation.nonnullisdefault=disabled
+org.eclipse.jdt.core.compiler.annotation.nullable=com.android.annotations.Nullable
+org.eclipse.jdt.core.compiler.annotation.nullanalysis=enabled
+org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
+org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6
+org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve
+org.eclipse.jdt.core.compiler.compliance=1.6
+org.eclipse.jdt.core.compiler.debug.lineNumber=generate
+org.eclipse.jdt.core.compiler.debug.localVariable=generate
+org.eclipse.jdt.core.compiler.debug.sourceFile=generate
+org.eclipse.jdt.core.compiler.problem.annotationSuperInterface=warning
+org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
+org.eclipse.jdt.core.compiler.problem.autoboxing=ignore
+org.eclipse.jdt.core.compiler.problem.comparingIdentical=warning
+org.eclipse.jdt.core.compiler.problem.deadCode=warning
+org.eclipse.jdt.core.compiler.problem.deprecation=warning
+org.eclipse.jdt.core.compiler.problem.deprecationInDeprecatedCode=disabled
+org.eclipse.jdt.core.compiler.problem.deprecationWhenOverridingDeprecatedMethod=disabled
+org.eclipse.jdt.core.compiler.problem.discouragedReference=warning
+org.eclipse.jdt.core.compiler.problem.emptyStatement=ignore
+org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
+org.eclipse.jdt.core.compiler.problem.explicitlyClosedAutoCloseable=ignore
+org.eclipse.jdt.core.compiler.problem.fallthroughCase=warning
+org.eclipse.jdt.core.compiler.problem.fatalOptionalError=enabled
+org.eclipse.jdt.core.compiler.problem.fieldHiding=warning
+org.eclipse.jdt.core.compiler.problem.finalParameterBound=warning
+org.eclipse.jdt.core.compiler.problem.finallyBlockNotCompletingNormally=warning
+org.eclipse.jdt.core.compiler.problem.forbiddenReference=error
+org.eclipse.jdt.core.compiler.problem.hiddenCatchBlock=warning
+org.eclipse.jdt.core.compiler.problem.includeNullInfoFromAsserts=enabled
+org.eclipse.jdt.core.compiler.problem.incompatibleNonInheritedInterfaceMethod=warning
+org.eclipse.jdt.core.compiler.problem.incompleteEnumSwitch=ignore
+org.eclipse.jdt.core.compiler.problem.indirectStaticAccess=ignore
+org.eclipse.jdt.core.compiler.problem.localVariableHiding=warning
+org.eclipse.jdt.core.compiler.problem.methodWithConstructorName=warning
+org.eclipse.jdt.core.compiler.problem.missingDeprecatedAnnotation=warning
+org.eclipse.jdt.core.compiler.problem.missingHashCodeMethod=warning
+org.eclipse.jdt.core.compiler.problem.missingOverrideAnnotation=error
+org.eclipse.jdt.core.compiler.problem.missingOverrideAnnotationForInterfaceMethodImplementation=enabled
+org.eclipse.jdt.core.compiler.problem.missingSerialVersion=warning
+org.eclipse.jdt.core.compiler.problem.missingSynchronizedOnInheritedMethod=ignore
+org.eclipse.jdt.core.compiler.problem.noEffectAssignment=warning
+org.eclipse.jdt.core.compiler.problem.noImplicitStringConversion=warning
+org.eclipse.jdt.core.compiler.problem.nonExternalizedStringLiteral=ignore
+org.eclipse.jdt.core.compiler.problem.nullReference=error
+org.eclipse.jdt.core.compiler.problem.nullSpecInsufficientInfo=warning
+org.eclipse.jdt.core.compiler.problem.nullSpecViolation=error
+org.eclipse.jdt.core.compiler.problem.overridingPackageDefaultMethod=warning
+org.eclipse.jdt.core.compiler.problem.parameterAssignment=ignore
+org.eclipse.jdt.core.compiler.problem.possibleAccidentalBooleanAssignment=warning
+org.eclipse.jdt.core.compiler.problem.potentialNullReference=warning
+org.eclipse.jdt.core.compiler.problem.potentialNullSpecViolation=error
+org.eclipse.jdt.core.compiler.problem.potentiallyUnclosedCloseable=warning
+org.eclipse.jdt.core.compiler.problem.rawTypeReference=warning
+org.eclipse.jdt.core.compiler.problem.redundantNullAnnotation=warning
+org.eclipse.jdt.core.compiler.problem.redundantNullCheck=ignore
+org.eclipse.jdt.core.compiler.problem.redundantSpecificationOfTypeArguments=ignore
+org.eclipse.jdt.core.compiler.problem.redundantSuperinterface=warning
+org.eclipse.jdt.core.compiler.problem.reportMethodCanBePotentiallyStatic=ignore
+org.eclipse.jdt.core.compiler.problem.reportMethodCanBeStatic=ignore
+org.eclipse.jdt.core.compiler.problem.specialParameterHidingField=disabled
+org.eclipse.jdt.core.compiler.problem.staticAccessReceiver=warning
+org.eclipse.jdt.core.compiler.problem.suppressOptionalErrors=disabled
+org.eclipse.jdt.core.compiler.problem.suppressWarnings=enabled
+org.eclipse.jdt.core.compiler.problem.syntheticAccessEmulation=ignore
+org.eclipse.jdt.core.compiler.problem.typeParameterHiding=warning
+org.eclipse.jdt.core.compiler.problem.unavoidableGenericTypeProblems=disabled
+org.eclipse.jdt.core.compiler.problem.uncheckedTypeOperation=warning
+org.eclipse.jdt.core.compiler.problem.unclosedCloseable=error
+org.eclipse.jdt.core.compiler.problem.undocumentedEmptyBlock=ignore
+org.eclipse.jdt.core.compiler.problem.unhandledWarningToken=warning
+org.eclipse.jdt.core.compiler.problem.unnecessaryElse=ignore
+org.eclipse.jdt.core.compiler.problem.unnecessaryTypeCheck=warning
+org.eclipse.jdt.core.compiler.problem.unqualifiedFieldAccess=ignore
+org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownException=warning
+org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionExemptExceptionAndThrowable=enabled
+org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionIncludeDocCommentReference=enabled
+org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionWhenOverriding=disabled
+org.eclipse.jdt.core.compiler.problem.unusedImport=warning
+org.eclipse.jdt.core.compiler.problem.unusedLabel=warning
+org.eclipse.jdt.core.compiler.problem.unusedLocal=warning
+org.eclipse.jdt.core.compiler.problem.unusedObjectAllocation=warning
+org.eclipse.jdt.core.compiler.problem.unusedParameter=ignore
+org.eclipse.jdt.core.compiler.problem.unusedParameterIncludeDocCommentReference=enabled
+org.eclipse.jdt.core.compiler.problem.unusedParameterWhenImplementingAbstract=disabled
+org.eclipse.jdt.core.compiler.problem.unusedParameterWhenOverridingConcrete=disabled
+org.eclipse.jdt.core.compiler.problem.unusedPrivateMember=warning
+org.eclipse.jdt.core.compiler.problem.unusedWarningToken=warning
+org.eclipse.jdt.core.compiler.problem.varargsArgumentNeedCast=warning
+org.eclipse.jdt.core.compiler.source=1.6
diff --git a/tools/layoutlib/bridge/src/android/animation/AnimationThread.java b/tools/layoutlib/bridge/src/android/animation/AnimationThread.java
index af83c61..b46134a 100644
--- a/tools/layoutlib/bridge/src/android/animation/AnimationThread.java
+++ b/tools/layoutlib/bridge/src/android/animation/AnimationThread.java
@@ -23,11 +23,10 @@
import com.android.layoutlib.bridge.Bridge;
import com.android.layoutlib.bridge.impl.RenderSessionImpl;
-import android.animation.ValueAnimator;
import android.os.Handler;
import android.os.Handler_Delegate;
-import android.os.Message;
import android.os.Handler_Delegate.IHandlerCallback;
+import android.os.Message;
import java.util.PriorityQueue;
import java.util.Queue;
@@ -57,6 +56,7 @@
mUptimeMillis = uptimeMillis;
}
+ @Override
public int compareTo(MessageBundle bundle) {
if (mUptimeMillis < bundle.mUptimeMillis) {
return -1;
@@ -85,6 +85,7 @@
Bridge.prepareThread();
try {
Handler_Delegate.setCallback(new IHandlerCallback() {
+ @Override
public void sendMessageAtTime(Handler handler, Message msg, long uptimeMillis) {
if (msg.what == ValueAnimator.ANIMATION_START /*||
FIXME: The ANIMATION_FRAME message no longer exists. Instead,
diff --git a/tools/layoutlib/bridge/src/android/graphics/BitmapShader_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/BitmapShader_Delegate.java
index 9a8cf04..65a75b0 100644
--- a/tools/layoutlib/bridge/src/android/graphics/BitmapShader_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/graphics/BitmapShader_Delegate.java
@@ -105,6 +105,7 @@
mTileModeY = tileModeY;
}
+ @Override
public java.awt.PaintContext createContext(
java.awt.image.ColorModel colorModel,
java.awt.Rectangle deviceBounds,
@@ -148,13 +149,16 @@
mColorModel = colorModel;
}
+ @Override
public void dispose() {
}
+ @Override
public java.awt.image.ColorModel getColorModel() {
return mColorModel;
}
+ @Override
public java.awt.image.Raster getRaster(int x, int y, int w, int h) {
java.awt.image.BufferedImage image = new java.awt.image.BufferedImage(w, h,
java.awt.image.BufferedImage.TYPE_INT_ARGB);
@@ -240,6 +244,7 @@
}
+ @Override
public int getTransparency() {
return java.awt.Paint.TRANSLUCENT;
}
diff --git a/tools/layoutlib/bridge/src/android/graphics/Canvas_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/Canvas_Delegate.java
index f797836..16f1575 100644
--- a/tools/layoutlib/bridge/src/android/graphics/Canvas_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/graphics/Canvas_Delegate.java
@@ -291,6 +291,7 @@
Paint paint) {
draw(thisCanvas.mNativeCanvas, paint.mNativePaint, false /*compositeOnly*/,
false /*forceSrcMode*/, new GcSnapshot.Drawable() {
+ @Override
public void draw(Graphics2D graphics, Paint_Delegate paintDelegate) {
for (int i = 0 ; i < count ; i += 4) {
graphics.drawLine((int)pts[i + offset], (int)pts[i + offset + 1],
@@ -619,6 +620,7 @@
final int h = canvasDelegate.mBitmap.getImage().getHeight();
draw(nativeCanvas, new GcSnapshot.Drawable() {
+ @Override
public void draw(Graphics2D graphics, Paint_Delegate paint) {
// reset its transform just in case
graphics.setTransform(new AffineTransform());
@@ -651,6 +653,7 @@
draw(nativeCanvas, paint, false /*compositeOnly*/, false /*forceSrcMode*/,
new GcSnapshot.Drawable() {
+ @Override
public void draw(Graphics2D graphics, Paint_Delegate paintDelegate) {
graphics.drawLine((int)startX, (int)startY, (int)stopX, (int)stopY);
}
@@ -669,6 +672,7 @@
draw(nativeCanvas, paint, false /*compositeOnly*/, false /*forceSrcMode*/,
new GcSnapshot.Drawable() {
+ @Override
public void draw(Graphics2D graphics, Paint_Delegate paintDelegate) {
int style = paintDelegate.getStyle();
@@ -693,6 +697,7 @@
if (oval.right > oval.left && oval.bottom > oval.top) {
draw(nativeCanvas, paint, false /*compositeOnly*/, false /*forceSrcMode*/,
new GcSnapshot.Drawable() {
+ @Override
public void draw(Graphics2D graphics, Paint_Delegate paintDelegate) {
int style = paintDelegate.getStyle();
@@ -728,6 +733,7 @@
if (oval.right > oval.left && oval.bottom > oval.top) {
draw(nativeCanvas, paint, false /*compositeOnly*/, false /*forceSrcMode*/,
new GcSnapshot.Drawable() {
+ @Override
public void draw(Graphics2D graphics, Paint_Delegate paintDelegate) {
int style = paintDelegate.getStyle();
@@ -757,6 +763,7 @@
draw(nativeCanvas, paint, false /*compositeOnly*/, false /*forceSrcMode*/,
new GcSnapshot.Drawable() {
+ @Override
public void draw(Graphics2D graphics, Paint_Delegate paintDelegate) {
int style = paintDelegate.getStyle();
@@ -789,6 +796,7 @@
draw(nativeCanvas, paint, false /*compositeOnly*/, false /*forceSrcMode*/,
new GcSnapshot.Drawable() {
+ @Override
public void draw(Graphics2D graphics, Paint_Delegate paintDelegate) {
Shape shape = pathDelegate.getJavaShape();
int style = paintDelegate.getStyle();
@@ -892,6 +900,7 @@
draw(nativeCanvas, nativePaintOrZero, true /*compositeOnly*/, false /*forceSrcMode*/,
new GcSnapshot.Drawable() {
+ @Override
public void draw(Graphics2D graphics, Paint_Delegate paint) {
if (paint != null && paint.isFilterBitmap()) {
graphics.setRenderingHint(RenderingHints.KEY_INTERPOLATION,
@@ -931,6 +940,7 @@
final AffineTransform mtx = matrixDelegate.getAffineTransform();
canvasDelegate.getSnapshot().draw(new GcSnapshot.Drawable() {
+ @Override
public void draw(Graphics2D graphics, Paint_Delegate paint) {
if (paint != null && paint.isFilterBitmap()) {
graphics.setRenderingHint(RenderingHints.KEY_INTERPOLATION,
@@ -970,6 +980,7 @@
final float startX, final float startY, int flags, int paint) {
draw(nativeCanvas, paint, false /*compositeOnly*/, false /*forceSrcMode*/,
new GcSnapshot.Drawable() {
+ @Override
public void draw(Graphics2D graphics, Paint_Delegate paintDelegate) {
// WARNING: the logic in this method is similar to Paint_Delegate.measureText.
// Any change to this method should be reflected in Paint.measureText
@@ -1279,6 +1290,7 @@
draw(nativeCanvas, nativePaintOrZero, true /*compositeOnly*/, sBoolOut[0],
new GcSnapshot.Drawable() {
+ @Override
public void draw(Graphics2D graphics, Paint_Delegate paint) {
if (paint != null && paint.isFilterBitmap()) {
graphics.setRenderingHint(RenderingHints.KEY_INTERPOLATION,
diff --git a/tools/layoutlib/bridge/src/android/graphics/Gradient_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/Gradient_Delegate.java
index 38c092d..7475c22 100644
--- a/tools/layoutlib/bridge/src/android/graphics/Gradient_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/graphics/Gradient_Delegate.java
@@ -87,6 +87,7 @@
mTileMode = tileMode;
}
+ @Override
public int getTransparency() {
return java.awt.Paint.TRANSLUCENT;
}
diff --git a/tools/layoutlib/bridge/src/android/graphics/LinearGradient_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/LinearGradient_Delegate.java
index a2ba758..f117fca 100644
--- a/tools/layoutlib/bridge/src/android/graphics/LinearGradient_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/graphics/LinearGradient_Delegate.java
@@ -132,6 +132,7 @@
mDSize2 = mDx * mDx + mDy * mDy;
}
+ @Override
public java.awt.PaintContext createContext(
java.awt.image.ColorModel colorModel,
java.awt.Rectangle deviceBounds,
@@ -176,13 +177,16 @@
mColorModel = colorModel;
}
+ @Override
public void dispose() {
}
+ @Override
public java.awt.image.ColorModel getColorModel() {
return mColorModel;
}
+ @Override
public java.awt.image.Raster getRaster(int x, int y, int w, int h) {
java.awt.image.BufferedImage image = new java.awt.image.BufferedImage(w, h,
java.awt.image.BufferedImage.TYPE_INT_ARGB);
diff --git a/tools/layoutlib/bridge/src/android/graphics/NinePatch_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/NinePatch_Delegate.java
index 5e882ce..be27b54 100644
--- a/tools/layoutlib/bridge/src/android/graphics/NinePatch_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/graphics/NinePatch_Delegate.java
@@ -215,6 +215,7 @@
Paint_Delegate paint_delegate = Paint_Delegate.getDelegate(paint_instance_or_null);
canvas_delegate.getSnapshot().draw(new GcSnapshot.Drawable() {
+ @Override
public void draw(Graphics2D graphics, Paint_Delegate paint) {
chunkObject.draw(bitmap_delegate.getImage(), graphics,
left, top, right - left, bottom - top, destDensity, srcDensity);
diff --git a/tools/layoutlib/bridge/src/android/graphics/RadialGradient_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/RadialGradient_Delegate.java
index 9bf78b4..3fe45fa 100644
--- a/tools/layoutlib/bridge/src/android/graphics/RadialGradient_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/graphics/RadialGradient_Delegate.java
@@ -118,6 +118,7 @@
mRadius = radius;
}
+ @Override
public java.awt.PaintContext createContext(
java.awt.image.ColorModel colorModel,
java.awt.Rectangle deviceBounds,
@@ -162,13 +163,16 @@
mColorModel = colorModel;
}
+ @Override
public void dispose() {
}
+ @Override
public java.awt.image.ColorModel getColorModel() {
return mColorModel;
}
+ @Override
public java.awt.image.Raster getRaster(int x, int y, int w, int h) {
java.awt.image.BufferedImage image = new java.awt.image.BufferedImage(w, h,
java.awt.image.BufferedImage.TYPE_INT_ARGB);
diff --git a/tools/layoutlib/bridge/src/android/graphics/SweepGradient_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/SweepGradient_Delegate.java
index 966e06e..13ae12e 100644
--- a/tools/layoutlib/bridge/src/android/graphics/SweepGradient_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/graphics/SweepGradient_Delegate.java
@@ -110,6 +110,7 @@
mCy = cy;
}
+ @Override
public java.awt.PaintContext createContext(
java.awt.image.ColorModel colorModel,
java.awt.Rectangle deviceBounds,
@@ -154,13 +155,16 @@
mColorModel = colorModel;
}
+ @Override
public void dispose() {
}
+ @Override
public java.awt.image.ColorModel getColorModel() {
return mColorModel;
}
+ @Override
public java.awt.image.Raster getRaster(int x, int y, int w, int h) {
java.awt.image.BufferedImage image = new java.awt.image.BufferedImage(w, h,
java.awt.image.BufferedImage.TYPE_INT_ARGB);
diff --git a/tools/layoutlib/bridge/src/android/view/SurfaceView.java b/tools/layoutlib/bridge/src/android/view/SurfaceView.java
index ce32da9..6aa4b3b 100644
--- a/tools/layoutlib/bridge/src/android/view/SurfaceView.java
+++ b/tools/layoutlib/bridge/src/android/view/SurfaceView.java
@@ -27,7 +27,7 @@
* Mock version of the SurfaceView.
* Only non override public methods from the real SurfaceView have been added in there.
* Methods that take an unknown class as parameter or as return object, have been removed for now.
- *
+ *
* TODO: generate automatically.
*
*/
@@ -36,7 +36,7 @@
public SurfaceView(Context context) {
this(context, null);
}
-
+
public SurfaceView(Context context, AttributeSet attrs) {
this(context, attrs , 0);
}
@@ -44,53 +44,66 @@
public SurfaceView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
-
+
public SurfaceHolder getHolder() {
return mSurfaceHolder;
}
private SurfaceHolder mSurfaceHolder = new SurfaceHolder() {
-
+
+ @Override
public boolean isCreating() {
return false;
}
+ @Override
public void addCallback(Callback callback) {
}
+ @Override
public void removeCallback(Callback callback) {
}
-
+
+ @Override
public void setFixedSize(int width, int height) {
}
+ @Override
public void setSizeFromLayout() {
}
+ @Override
public void setFormat(int format) {
}
+ @Override
public void setType(int type) {
}
+ @Override
public void setKeepScreenOn(boolean screenOn) {
}
-
+
+ @Override
public Canvas lockCanvas() {
return null;
}
+ @Override
public Canvas lockCanvas(Rect dirty) {
return null;
}
+ @Override
public void unlockCanvasAndPost(Canvas canvas) {
}
+ @Override
public Surface getSurface() {
return null;
}
+ @Override
public Rect getSurfaceFrame() {
return null;
}
diff --git a/tools/layoutlib/bridge/src/com/android/internal/textservice/ITextServicesManager_Stub_Delegate.java b/tools/layoutlib/bridge/src/com/android/internal/textservice/ITextServicesManager_Stub_Delegate.java
index 9efdcaf..3017292 100644
--- a/tools/layoutlib/bridge/src/com/android/internal/textservice/ITextServicesManager_Stub_Delegate.java
+++ b/tools/layoutlib/bridge/src/com/android/internal/textservice/ITextServicesManager_Stub_Delegate.java
@@ -43,28 +43,33 @@
private static class FakeTextServicesManager implements ITextServicesManager {
+ @Override
public void finishSpellCheckerService(ISpellCheckerSessionListener arg0)
throws RemoteException {
// TODO Auto-generated method stub
}
+ @Override
public SpellCheckerInfo getCurrentSpellChecker(String arg0) throws RemoteException {
// TODO Auto-generated method stub
return null;
}
+ @Override
public SpellCheckerSubtype getCurrentSpellCheckerSubtype(String arg0, boolean arg1)
throws RemoteException {
// TODO Auto-generated method stub
return null;
}
+ @Override
public SpellCheckerInfo[] getEnabledSpellCheckers() throws RemoteException {
// TODO Auto-generated method stub
return null;
}
+ @Override
public void getSpellCheckerService(String arg0, String arg1,
ITextServicesSessionListener arg2, ISpellCheckerSessionListener arg3, Bundle arg4)
throws RemoteException {
@@ -72,26 +77,31 @@
}
+ @Override
public boolean isSpellCheckerEnabled() throws RemoteException {
// TODO Auto-generated method stub
return false;
}
+ @Override
public void setCurrentSpellChecker(String arg0, String arg1) throws RemoteException {
// TODO Auto-generated method stub
}
+ @Override
public void setCurrentSpellCheckerSubtype(String arg0, int arg1) throws RemoteException {
// TODO Auto-generated method stub
}
+ @Override
public void setSpellCheckerEnabled(boolean arg0) throws RemoteException {
// TODO Auto-generated method stub
}
+ @Override
public IBinder asBinder() {
// TODO Auto-generated method stub
return null;
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContentProvider.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContentProvider.java
index c91a3bf..e28866e 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContentProvider.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContentProvider.java
@@ -19,6 +19,7 @@
import android.content.ContentProviderOperation;
import android.content.ContentProviderResult;
import android.content.ContentValues;
+import android.content.ICancellationSignal;
import android.content.IContentProvider;
import android.content.OperationApplicationException;
import android.content.res.AssetFileDescriptor;
@@ -90,8 +91,8 @@
}
@Override
- public Cursor query(Uri arg0, String[] arg1, String arg2, String[] arg3, String arg4)
- throws RemoteException {
+ public Cursor query(Uri arg0, String[] arg1, String arg2, String[] arg3, String arg4,
+ ICancellationSignal arg5) throws RemoteException {
// TODO Auto-generated method stub
return null;
}
@@ -122,4 +123,9 @@
return null;
}
+ @Override
+ public ICancellationSignal createCancellationSignal() throws RemoteException {
+ // TODO Auto-generated method stub
+ return null;
+ }
}
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeIInputMethodManager.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeIInputMethodManager.java
index 2a52888..db0694c 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeIInputMethodManager.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeIInputMethodManager.java
@@ -37,151 +37,179 @@
*/
public class BridgeIInputMethodManager implements IInputMethodManager {
+ @Override
public void addClient(IInputMethodClient arg0, IInputContext arg1, int arg2, int arg3)
throws RemoteException {
// TODO Auto-generated method stub
}
+ @Override
public void finishInput(IInputMethodClient arg0) throws RemoteException {
// TODO Auto-generated method stub
}
+ @Override
public InputMethodSubtype getCurrentInputMethodSubtype() throws RemoteException {
// TODO Auto-generated method stub
return null;
}
+ @Override
public List<InputMethodInfo> getEnabledInputMethodList() throws RemoteException {
// TODO Auto-generated method stub
return null;
}
+ @Override
public List<InputMethodSubtype> getEnabledInputMethodSubtypeList(InputMethodInfo arg0,
boolean arg1) throws RemoteException {
// TODO Auto-generated method stub
return null;
}
+ @Override
public List<InputMethodInfo> getInputMethodList() throws RemoteException {
// TODO Auto-generated method stub
return null;
}
+ @Override
public InputMethodSubtype getLastInputMethodSubtype() throws RemoteException {
// TODO Auto-generated method stub
return null;
}
+ @Override
public List getShortcutInputMethodsAndSubtypes() throws RemoteException {
// TODO Auto-generated method stub
return null;
}
+ @Override
public void hideMySoftInput(IBinder arg0, int arg1) throws RemoteException {
// TODO Auto-generated method stub
}
+ @Override
public boolean hideSoftInput(IInputMethodClient arg0, int arg1, ResultReceiver arg2)
throws RemoteException {
// TODO Auto-generated method stub
return false;
}
+ @Override
public boolean notifySuggestionPicked(SuggestionSpan arg0, String arg1, int arg2)
throws RemoteException {
// TODO Auto-generated method stub
return false;
}
+ @Override
public void registerSuggestionSpansForNotification(SuggestionSpan[] arg0)
throws RemoteException {
// TODO Auto-generated method stub
}
+ @Override
public void removeClient(IInputMethodClient arg0) throws RemoteException {
// TODO Auto-generated method stub
}
+ @Override
public void setAdditionalInputMethodSubtypes(String arg0, InputMethodSubtype[] arg1)
throws RemoteException {
// TODO Auto-generated method stub
}
+ @Override
public boolean setCurrentInputMethodSubtype(InputMethodSubtype arg0) throws RemoteException {
// TODO Auto-generated method stub
return false;
}
+ @Override
public void setImeWindowStatus(IBinder arg0, int arg1, int arg2) throws RemoteException {
// TODO Auto-generated method stub
}
+ @Override
public void setInputMethod(IBinder arg0, String arg1) throws RemoteException {
// TODO Auto-generated method stub
}
+ @Override
public void setInputMethodAndSubtype(IBinder arg0, String arg1, InputMethodSubtype arg2)
throws RemoteException {
// TODO Auto-generated method stub
}
+ @Override
public boolean setInputMethodEnabled(String arg0, boolean arg1) throws RemoteException {
// TODO Auto-generated method stub
return false;
}
+ @Override
public void showInputMethodAndSubtypeEnablerFromClient(IInputMethodClient arg0, String arg1)
throws RemoteException {
// TODO Auto-generated method stub
}
+ @Override
public void showInputMethodPickerFromClient(IInputMethodClient arg0) throws RemoteException {
// TODO Auto-generated method stub
}
+ @Override
public void showMySoftInput(IBinder arg0, int arg1) throws RemoteException {
// TODO Auto-generated method stub
}
+ @Override
public boolean showSoftInput(IInputMethodClient arg0, int arg1, ResultReceiver arg2)
throws RemoteException {
// TODO Auto-generated method stub
return false;
}
+ @Override
public InputBindResult startInput(IInputMethodClient arg0, IInputContext arg1, EditorInfo arg2,
boolean arg3, boolean arg4) throws RemoteException {
// TODO Auto-generated method stub
return null;
}
+ @Override
public boolean switchToLastInputMethod(IBinder arg0) throws RemoteException {
// TODO Auto-generated method stub
return false;
}
+ @Override
public void updateStatusIcon(IBinder arg0, String arg1, int arg2) throws RemoteException {
// TODO Auto-generated method stub
}
+ @Override
public void windowGainedFocus(IInputMethodClient arg0, IBinder arg1, boolean arg2,
boolean arg3, int arg4, boolean arg5, int arg6) throws RemoteException {
// TODO Auto-generated method stub
}
+ @Override
public IBinder asBinder() {
// TODO Auto-generated method stub
return null;
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeLayoutParamsMapAttributes.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeLayoutParamsMapAttributes.java
index d208408..f5912e7 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeLayoutParamsMapAttributes.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeLayoutParamsMapAttributes.java
@@ -37,6 +37,7 @@
mAttributes = attributes;
}
+ @Override
public String getAttributeValue(String namespace, String name) {
if (BridgeConstants.NS_RESOURCES.equals(namespace)) {
return mAttributes.get(name);
@@ -49,93 +50,114 @@
// BridgeContext#obtainStyledAttributes(AttributeSet, int[], int, int)
// Should they ever be called, we'll just implement them on a need basis.
+ @Override
public int getAttributeCount() {
throw new UnsupportedOperationException();
}
+ @Override
public String getAttributeName(int index) {
throw new UnsupportedOperationException();
}
+ @Override
public String getAttributeValue(int index) {
throw new UnsupportedOperationException();
}
+ @Override
public String getPositionDescription() {
throw new UnsupportedOperationException();
}
+ @Override
public int getAttributeNameResource(int index) {
throw new UnsupportedOperationException();
}
+ @Override
public int getAttributeListValue(String namespace, String attribute,
String[] options, int defaultValue) {
throw new UnsupportedOperationException();
}
+ @Override
public boolean getAttributeBooleanValue(String namespace, String attribute,
boolean defaultValue) {
throw new UnsupportedOperationException();
}
+ @Override
public int getAttributeResourceValue(String namespace, String attribute,
int defaultValue) {
throw new UnsupportedOperationException();
}
+ @Override
public int getAttributeIntValue(String namespace, String attribute,
int defaultValue) {
throw new UnsupportedOperationException();
}
+ @Override
public int getAttributeUnsignedIntValue(String namespace, String attribute,
int defaultValue) {
throw new UnsupportedOperationException();
}
+ @Override
public float getAttributeFloatValue(String namespace, String attribute,
float defaultValue) {
throw new UnsupportedOperationException();
}
+ @Override
public int getAttributeListValue(int index,
String[] options, int defaultValue) {
throw new UnsupportedOperationException();
}
+ @Override
public boolean getAttributeBooleanValue(int index, boolean defaultValue) {
throw new UnsupportedOperationException();
}
+ @Override
public int getAttributeResourceValue(int index, int defaultValue) {
throw new UnsupportedOperationException();
}
+ @Override
public int getAttributeIntValue(int index, int defaultValue) {
throw new UnsupportedOperationException();
}
+ @Override
public int getAttributeUnsignedIntValue(int index, int defaultValue) {
throw new UnsupportedOperationException();
}
+ @Override
public float getAttributeFloatValue(int index, float defaultValue) {
throw new UnsupportedOperationException();
}
+ @Override
public String getIdAttribute() {
throw new UnsupportedOperationException();
}
+ @Override
public String getClassAttribute() {
throw new UnsupportedOperationException();
}
+ @Override
public int getIdAttributeResourceValue(int defaultValue) {
throw new UnsupportedOperationException();
}
+ @Override
public int getStyleAttribute() {
throw new UnsupportedOperationException();
}
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeWindow.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeWindow.java
index e13380e..79606a4 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeWindow.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeWindow.java
@@ -24,72 +24,67 @@
import android.os.RemoteException;
import android.view.DragEvent;
import android.view.IWindow;
-import android.view.KeyEvent;
-import android.view.MotionEvent;
/**
* Implementation of {@link IWindow} to pass to the AttachInfo.
*/
public final class BridgeWindow implements IWindow {
+ @Override
public void dispatchAppVisibility(boolean arg0) throws RemoteException {
// pass for now.
}
+ @Override
public void dispatchGetNewSurface() throws RemoteException {
// pass for now.
}
-
- public void dispatchKey(KeyEvent arg0) throws RemoteException {
- // pass for now.
- }
-
- public void dispatchPointer(MotionEvent arg0, long arg1, boolean arg2) throws RemoteException {
- // pass for now.
- }
-
- public void dispatchTrackball(MotionEvent arg0, long arg1, boolean arg2)
- throws RemoteException {
- // pass for now.
- }
-
+ @Override
public void executeCommand(String arg0, String arg1, ParcelFileDescriptor arg2)
throws RemoteException {
// pass for now.
}
+ @Override
public void resized(int arg0, int arg1, Rect arg2, Rect arg3, boolean arg4, Configuration arg5)
throws RemoteException {
// pass for now.
}
+ @Override
public void windowFocusChanged(boolean arg0, boolean arg1) throws RemoteException {
// pass for now.
}
+ @Override
public void dispatchWallpaperOffsets(float x, float y, float xStep, float yStep,
boolean sync) {
// pass for now.
}
+ @Override
public void dispatchWallpaperCommand(String action, int x, int y,
int z, Bundle extras, boolean sync) {
// pass for now.
}
+ @Override
public void closeSystemDialogs(String reason) {
// pass for now.
}
+ @Override
public void dispatchDragEvent(DragEvent event) {
// pass for now.
}
+ @Override
public void dispatchSystemUiVisibilityChanged(int seq, int globalUi,
int localValue, int localChanges) {
// pass for now.
}
+ @Override
public IBinder asBinder() {
// pass for now.
return null;
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeWindowManager.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeWindowManager.java
index 1e66ca2..bef2c95 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeWindowManager.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeWindowManager.java
@@ -67,288 +67,345 @@
// ---- implementation of IWindowManager that we care about ----
+ @Override
public int getRotation() throws RemoteException {
return mRotation;
}
+ @Override
public int getMaximumSizeDimension() throws RemoteException {
return 0;
}
+ @Override
public void getDisplaySize(Point arg0) throws RemoteException {
}
+ @Override
public void getRealDisplaySize(Point arg0) throws RemoteException {
}
// ---- unused implementation of IWindowManager ----
+ @Override
public boolean canStatusBarHide() throws RemoteException {
// TODO Auto-generated method stub
return false;
}
+ @Override
public void addAppToken(int arg0, IApplicationToken arg1, int arg2, int arg3, boolean arg4)
throws RemoteException {
// TODO Auto-generated method stub
}
+ @Override
public void addWindowToken(IBinder arg0, int arg1) throws RemoteException {
// TODO Auto-generated method stub
}
+ @Override
public void clearForcedDisplaySize() throws RemoteException {
// TODO Auto-generated method stub
}
+ @Override
public void closeSystemDialogs(String arg0) throws RemoteException {
// TODO Auto-generated method stub
}
+ @Override
public void disableKeyguard(IBinder arg0, String arg1) throws RemoteException {
// TODO Auto-generated method stub
}
+ @Override
public void executeAppTransition() throws RemoteException {
// TODO Auto-generated method stub
}
+ @Override
public void exitKeyguardSecurely(IOnKeyguardExitResult arg0) throws RemoteException {
// TODO Auto-generated method stub
}
+ @Override
public void freezeRotation(int arg0) throws RemoteException {
// TODO Auto-generated method stub
}
+ @Override
public float getAnimationScale(int arg0) throws RemoteException {
// TODO Auto-generated method stub
return 0;
}
+ @Override
public float[] getAnimationScales() throws RemoteException {
// TODO Auto-generated method stub
return null;
}
+ @Override
public int getAppOrientation(IApplicationToken arg0) throws RemoteException {
// TODO Auto-generated method stub
return 0;
}
+ @Override
public int getDPadKeycodeState(int arg0) throws RemoteException {
// TODO Auto-generated method stub
return 0;
}
+ @Override
public int getDPadScancodeState(int arg0) throws RemoteException {
// TODO Auto-generated method stub
return 0;
}
+ @Override
public InputDevice getInputDevice(int arg0) throws RemoteException {
// TODO Auto-generated method stub
return null;
}
+ @Override
public int[] getInputDeviceIds() throws RemoteException {
// TODO Auto-generated method stub
return null;
}
+ @Override
public int getKeycodeState(int arg0) throws RemoteException {
// TODO Auto-generated method stub
return 0;
}
+ @Override
public int getKeycodeStateForDevice(int arg0, int arg1) throws RemoteException {
// TODO Auto-generated method stub
return 0;
}
+ @Override
public int getPendingAppTransition() throws RemoteException {
// TODO Auto-generated method stub
return 0;
}
+ @Override
public int getScancodeState(int arg0) throws RemoteException {
// TODO Auto-generated method stub
return 0;
}
+ @Override
public int getScancodeStateForDevice(int arg0, int arg1) throws RemoteException {
// TODO Auto-generated method stub
return 0;
}
+ @Override
public int getSwitchState(int arg0) throws RemoteException {
// TODO Auto-generated method stub
return 0;
}
+ @Override
public int getSwitchStateForDevice(int arg0, int arg1) throws RemoteException {
// TODO Auto-generated method stub
return 0;
}
+ @Override
public int getTrackballKeycodeState(int arg0) throws RemoteException {
// TODO Auto-generated method stub
return 0;
}
+ @Override
public int getTrackballScancodeState(int arg0) throws RemoteException {
// TODO Auto-generated method stub
return 0;
}
+ @Override
public boolean hasKeys(int[] arg0, boolean[] arg1) throws RemoteException {
// TODO Auto-generated method stub
return false;
}
+ @Override
public boolean inKeyguardRestrictedInputMode() throws RemoteException {
// TODO Auto-generated method stub
return false;
}
+ @Override
public boolean injectInputEventNoWait(InputEvent arg0) throws RemoteException {
// TODO Auto-generated method stub
return false;
}
+ @Override
public boolean injectKeyEvent(KeyEvent arg0, boolean arg1) throws RemoteException {
// TODO Auto-generated method stub
return false;
}
+ @Override
public boolean injectPointerEvent(MotionEvent arg0, boolean arg1) throws RemoteException {
// TODO Auto-generated method stub
return false;
}
+ @Override
public boolean injectTrackballEvent(MotionEvent arg0, boolean arg1) throws RemoteException {
// TODO Auto-generated method stub
return false;
}
+ @Override
public boolean inputMethodClientHasFocus(IInputMethodClient arg0) throws RemoteException {
// TODO Auto-generated method stub
return false;
}
+ @Override
public boolean isKeyguardLocked() throws RemoteException {
// TODO Auto-generated method stub
return false;
}
+ @Override
public boolean isKeyguardSecure() throws RemoteException {
// TODO Auto-generated method stub
return false;
}
+ @Override
public boolean isViewServerRunning() throws RemoteException {
// TODO Auto-generated method stub
return false;
}
+ @Override
public InputChannel monitorInput(String arg0) throws RemoteException {
// TODO Auto-generated method stub
return null;
}
+ @Override
public void moveAppToken(int arg0, IBinder arg1) throws RemoteException {
// TODO Auto-generated method stub
}
+ @Override
public void moveAppTokensToBottom(List<IBinder> arg0) throws RemoteException {
// TODO Auto-generated method stub
}
+ @Override
public void moveAppTokensToTop(List<IBinder> arg0) throws RemoteException {
// TODO Auto-generated method stub
}
+ @Override
public IWindowSession openSession(IInputMethodClient arg0, IInputContext arg1)
throws RemoteException {
// TODO Auto-generated method stub
return null;
}
+ @Override
public void overridePendingAppTransition(String arg0, int arg1, int arg2)
throws RemoteException {
// TODO Auto-generated method stub
}
+ @Override
public void pauseKeyDispatching(IBinder arg0) throws RemoteException {
// TODO Auto-generated method stub
}
+ @Override
public void prepareAppTransition(int arg0, boolean arg1) throws RemoteException {
// TODO Auto-generated method stub
}
+ @Override
public void reenableKeyguard(IBinder arg0) throws RemoteException {
// TODO Auto-generated method stub
}
+ @Override
public void removeAppToken(IBinder arg0) throws RemoteException {
// TODO Auto-generated method stub
}
+ @Override
public void removeWindowToken(IBinder arg0) throws RemoteException {
// TODO Auto-generated method stub
}
+ @Override
public void resumeKeyDispatching(IBinder arg0) throws RemoteException {
// TODO Auto-generated method stub
}
+ @Override
public Bitmap screenshotApplications(IBinder arg0, int arg1, int arg2) throws RemoteException {
// TODO Auto-generated method stub
return null;
}
+ @Override
public void setAnimationScale(int arg0, float arg1) throws RemoteException {
// TODO Auto-generated method stub
}
+ @Override
public void setAnimationScales(float[] arg0) throws RemoteException {
// TODO Auto-generated method stub
}
+ @Override
public void setAppGroupId(IBinder arg0, int arg1) throws RemoteException {
// TODO Auto-generated method stub
}
+ @Override
public void setAppOrientation(IApplicationToken arg0, int arg1) throws RemoteException {
// TODO Auto-generated method stub
}
+ @Override
public void setAppStartingWindow(IBinder arg0, String arg1, int arg2, CompatibilityInfo arg3,
CharSequence arg4, int arg5, int arg6, int arg7, IBinder arg8, boolean arg9)
throws RemoteException {
@@ -356,119 +413,148 @@
}
+ @Override
public void setAppVisibility(IBinder arg0, boolean arg1) throws RemoteException {
// TODO Auto-generated method stub
}
+ @Override
public void setAppWillBeHidden(IBinder arg0) throws RemoteException {
// TODO Auto-generated method stub
}
+ @Override
public void setEventDispatching(boolean arg0) throws RemoteException {
// TODO Auto-generated method stub
}
+ @Override
public void setFocusedApp(IBinder arg0, boolean arg1) throws RemoteException {
// TODO Auto-generated method stub
}
+ @Override
public void setForcedDisplaySize(int arg0, int arg1) throws RemoteException {
// TODO Auto-generated method stub
}
+ @Override
public void setInTouchMode(boolean arg0) throws RemoteException {
// TODO Auto-generated method stub
}
+ @Override
public void setNewConfiguration(Configuration arg0) throws RemoteException {
// TODO Auto-generated method stub
}
+ @Override
public void setPointerSpeed(int arg0) throws RemoteException {
// TODO Auto-generated method stub
}
+ @Override
public void updateRotation(boolean arg0) throws RemoteException {
// TODO Auto-generated method stub
}
+ @Override
public void setStrictModeVisualIndicatorPreference(String arg0) throws RemoteException {
// TODO Auto-generated method stub
}
+ @Override
public void showStrictModeViolation(boolean arg0) throws RemoteException {
// TODO Auto-generated method stub
}
+ @Override
public void startAppFreezingScreen(IBinder arg0, int arg1) throws RemoteException {
// TODO Auto-generated method stub
}
+ @Override
public boolean startViewServer(int arg0) throws RemoteException {
// TODO Auto-generated method stub
return false;
}
+ @Override
public void statusBarVisibilityChanged(int arg0) throws RemoteException {
// TODO Auto-generated method stub
}
+ @Override
public void stopAppFreezingScreen(IBinder arg0, boolean arg1) throws RemoteException {
// TODO Auto-generated method stub
}
+ @Override
public boolean stopViewServer() throws RemoteException {
// TODO Auto-generated method stub
return false;
}
+ @Override
public void thawRotation() throws RemoteException {
// TODO Auto-generated method stub
}
+ @Override
public Configuration updateOrientationFromAppTokens(Configuration arg0, IBinder arg1)
throws RemoteException {
// TODO Auto-generated method stub
return null;
}
+ @Override
public int watchRotation(IRotationWatcher arg0) throws RemoteException {
// TODO Auto-generated method stub
return 0;
}
+ @Override
public void waitForWindowDrawn(IBinder token, IRemoteCallback callback) {
// TODO Auto-generated method stub
}
-
+
+ @Override
public IBinder asBinder() {
// TODO Auto-generated method stub
return null;
}
+ @Override
public int getPreferredOptionsPanelGravity() throws RemoteException {
return Gravity.CENTER_HORIZONTAL | Gravity.BOTTOM;
}
+ @Override
public void dismissKeyguard() {
}
+ @Override
public boolean hasNavigationBar() {
return false; // should this return something else?
}
+
+ @Override
+ public void lockNow() {
+ // TODO Auto-generated method stub
+ }
}
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeWindowSession.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeWindowSession.java
index a640a91..d3721ed 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeWindowSession.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeWindowSession.java
@@ -26,7 +26,6 @@
import android.view.IWindow;
import android.view.IWindowSession;
import android.view.InputChannel;
-import android.view.MotionEvent;
import android.view.Surface;
import android.view.SurfaceView;
import android.view.WindowManager.LayoutParams;
@@ -37,6 +36,7 @@
*/
public final class BridgeWindowSession implements IWindowSession {
+ @Override
public int add(IWindow arg0, int seq, LayoutParams arg1, int arg2, Rect arg3,
InputChannel outInputchannel)
throws RemoteException {
@@ -44,40 +44,30 @@
return 0;
}
+ @Override
public int addWithoutInputChannel(IWindow arg0, int seq, LayoutParams arg1, int arg2, Rect arg3)
throws RemoteException {
// pass for now.
return 0;
}
+ @Override
public void finishDrawing(IWindow arg0) throws RemoteException {
// pass for now.
}
- public void finishKey(IWindow arg0) throws RemoteException {
- // pass for now.
- }
-
+ @Override
public boolean getInTouchMode() throws RemoteException {
// pass for now.
return false;
}
+ @Override
public boolean performHapticFeedback(IWindow window, int effectId, boolean always) {
// pass for now.
return false;
}
-
- public MotionEvent getPendingPointerMove(IWindow arg0) throws RemoteException {
- // pass for now.
- return null;
- }
-
- public MotionEvent getPendingTrackballMove(IWindow arg0) throws RemoteException {
- // pass for now.
- return null;
- }
-
+ @Override
public int relayout(IWindow arg0, int seq, LayoutParams arg1, int arg2, int arg3, int arg4,
int arg4_5, Rect arg5, Rect arg6, Rect arg7, Configuration arg7b, Surface arg8)
throws RemoteException {
@@ -85,35 +75,43 @@
return 0;
}
+ @Override
public void performDeferredDestroy(IWindow window) {
// pass for now.
}
+ @Override
public boolean outOfMemory(IWindow window) throws RemoteException {
return false;
}
+ @Override
public void getDisplayFrame(IWindow window, Rect outDisplayFrame) {
// pass for now.
}
+ @Override
public void remove(IWindow arg0) throws RemoteException {
// pass for now.
}
+ @Override
public void setInTouchMode(boolean arg0) throws RemoteException {
// pass for now.
}
+ @Override
public void setTransparentRegion(IWindow arg0, Region arg1) throws RemoteException {
// pass for now.
}
+ @Override
public void setInsets(IWindow window, int touchable, Rect contentInsets,
Rect visibleInsets, Region touchableRegion) {
// pass for now.
}
+ @Override
public IBinder prepareDrag(IWindow window, int flags,
int thumbnailWidth, int thumbnailHeight, Surface outSurface)
throws RemoteException {
@@ -121,6 +119,7 @@
return null;
}
+ @Override
public boolean performDrag(IWindow window, IBinder dragToken,
float touchX, float touchY, float thumbCenterX, float thumbCenterY,
ClipData data)
@@ -129,49 +128,47 @@
return false;
}
+ @Override
public void reportDropResult(IWindow window, boolean consumed) throws RemoteException {
// pass for now
}
+ @Override
public void dragRecipientEntered(IWindow window) throws RemoteException {
// pass for now
}
+ @Override
public void dragRecipientExited(IWindow window) throws RemoteException {
// pass for now
}
+ @Override
public void setWallpaperPosition(IBinder window, float x, float y,
float xStep, float yStep) {
// pass for now.
}
+ @Override
public void wallpaperOffsetsComplete(IBinder window) {
// pass for now.
}
+ @Override
public Bundle sendWallpaperCommand(IBinder window, String action, int x, int y,
int z, Bundle extras, boolean sync) {
// pass for now.
return null;
}
+ @Override
public void wallpaperCommandComplete(IBinder window, Bundle result) {
// pass for now.
}
- public void closeSystemDialogs(String reason) {
- // pass for now.
- }
-
+ @Override
public IBinder asBinder() {
// pass for now.
return null;
}
-
- public IBinder prepareDrag(IWindow arg0, boolean arg1, int arg2, int arg3, Surface arg4)
- throws RemoteException {
- // TODO Auto-generated method stub
- return null;
- }
}
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeXmlBlockParser.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeXmlBlockParser.java
index f8ed4f7..ac8712e 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeXmlBlockParser.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeXmlBlockParser.java
@@ -95,6 +95,7 @@
// ------- XmlResourceParser implementation
+ @Override
public void setFeature(String name, boolean state)
throws XmlPullParserException {
if (FEATURE_PROCESS_NAMESPACES.equals(name) && state) {
@@ -106,6 +107,7 @@
throw new XmlPullParserException("Unsupported feature: " + name);
}
+ @Override
public boolean getFeature(String name) {
if (FEATURE_PROCESS_NAMESPACES.equals(name)) {
return true;
@@ -116,82 +118,101 @@
return false;
}
+ @Override
public void setProperty(String name, Object value) throws XmlPullParserException {
throw new XmlPullParserException("setProperty() not supported");
}
+ @Override
public Object getProperty(String name) {
return null;
}
+ @Override
public void setInput(Reader in) throws XmlPullParserException {
mParser.setInput(in);
}
+ @Override
public void setInput(InputStream inputStream, String inputEncoding)
throws XmlPullParserException {
mParser.setInput(inputStream, inputEncoding);
}
+ @Override
public void defineEntityReplacementText(String entityName,
String replacementText) throws XmlPullParserException {
throw new XmlPullParserException(
"defineEntityReplacementText() not supported");
}
+ @Override
public String getNamespacePrefix(int pos) throws XmlPullParserException {
throw new XmlPullParserException("getNamespacePrefix() not supported");
}
+ @Override
public String getInputEncoding() {
return null;
}
+ @Override
public String getNamespace(String prefix) {
throw new RuntimeException("getNamespace() not supported");
}
+ @Override
public int getNamespaceCount(int depth) throws XmlPullParserException {
throw new XmlPullParserException("getNamespaceCount() not supported");
}
+ @Override
public String getPositionDescription() {
return "Binary XML file line #" + getLineNumber();
}
+ @Override
public String getNamespaceUri(int pos) throws XmlPullParserException {
throw new XmlPullParserException("getNamespaceUri() not supported");
}
+ @Override
public int getColumnNumber() {
return -1;
}
+ @Override
public int getDepth() {
return mParser.getDepth();
}
+ @Override
public String getText() {
return mParser.getText();
}
+ @Override
public int getLineNumber() {
return mParser.getLineNumber();
}
+ @Override
public int getEventType() {
return mEventType;
}
+ @Override
public boolean isWhitespace() throws XmlPullParserException {
// Original comment: whitespace was stripped by aapt.
return mParser.isWhitespace();
}
+ @Override
public String getPrefix() {
throw new RuntimeException("getPrefix not supported");
}
+ @Override
public char[] getTextCharacters(int[] holderForStartAndLength) {
String txt = getText();
char[] chars = null;
@@ -204,55 +225,68 @@
return chars;
}
+ @Override
public String getNamespace() {
return mParser.getNamespace();
}
+ @Override
public String getName() {
return mParser.getName();
}
+ @Override
public String getAttributeNamespace(int index) {
return mParser.getAttributeNamespace(index);
}
+ @Override
public String getAttributeName(int index) {
return mParser.getAttributeName(index);
}
+ @Override
public String getAttributePrefix(int index) {
throw new RuntimeException("getAttributePrefix not supported");
}
+ @Override
public boolean isEmptyElementTag() {
// XXX Need to detect this.
return false;
}
+ @Override
public int getAttributeCount() {
return mParser.getAttributeCount();
}
+ @Override
public String getAttributeValue(int index) {
return mParser.getAttributeValue(index);
}
+ @Override
public String getAttributeType(int index) {
return "CDATA";
}
+ @Override
public boolean isAttributeDefault(int index) {
return false;
}
+ @Override
public int nextToken() throws XmlPullParserException, IOException {
return next();
}
+ @Override
public String getAttributeValue(String namespace, String name) {
return mParser.getAttributeValue(namespace, name);
}
+ @Override
public int next() throws XmlPullParserException, IOException {
if (!mStarted) {
mStarted = true;
@@ -313,6 +347,7 @@
return "????";
}
+ @Override
public void require(int type, String namespace, String name)
throws XmlPullParserException {
if (type != getEventType()
@@ -322,6 +357,7 @@
+ getPositionDescription());
}
+ @Override
public String nextText() throws XmlPullParserException, IOException {
if (getEventType() != START_TAG) {
throw new XmlPullParserException(getPositionDescription()
@@ -348,6 +384,7 @@
}
}
+ @Override
public int nextTag() throws XmlPullParserException, IOException {
int eventType = next();
if (eventType == TEXT && isWhitespace()) { // skip whitespace
@@ -363,76 +400,94 @@
// AttributeSet implementation
+ @Override
public void close() {
// pass
}
+ @Override
public boolean getAttributeBooleanValue(int index, boolean defaultValue) {
return mAttrib.getAttributeBooleanValue(index, defaultValue);
}
+ @Override
public boolean getAttributeBooleanValue(String namespace, String attribute,
boolean defaultValue) {
return mAttrib.getAttributeBooleanValue(namespace, attribute, defaultValue);
}
+ @Override
public float getAttributeFloatValue(int index, float defaultValue) {
return mAttrib.getAttributeFloatValue(index, defaultValue);
}
+ @Override
public float getAttributeFloatValue(String namespace, String attribute, float defaultValue) {
return mAttrib.getAttributeFloatValue(namespace, attribute, defaultValue);
}
+ @Override
public int getAttributeIntValue(int index, int defaultValue) {
return mAttrib.getAttributeIntValue(index, defaultValue);
}
+ @Override
public int getAttributeIntValue(String namespace, String attribute, int defaultValue) {
return mAttrib.getAttributeIntValue(namespace, attribute, defaultValue);
}
+ @Override
public int getAttributeListValue(int index, String[] options, int defaultValue) {
return mAttrib.getAttributeListValue(index, options, defaultValue);
}
+ @Override
public int getAttributeListValue(String namespace, String attribute,
String[] options, int defaultValue) {
return mAttrib.getAttributeListValue(namespace, attribute, options, defaultValue);
}
+ @Override
public int getAttributeNameResource(int index) {
return mAttrib.getAttributeNameResource(index);
}
+ @Override
public int getAttributeResourceValue(int index, int defaultValue) {
return mAttrib.getAttributeResourceValue(index, defaultValue);
}
+ @Override
public int getAttributeResourceValue(String namespace, String attribute, int defaultValue) {
return mAttrib.getAttributeResourceValue(namespace, attribute, defaultValue);
}
+ @Override
public int getAttributeUnsignedIntValue(int index, int defaultValue) {
return mAttrib.getAttributeUnsignedIntValue(index, defaultValue);
}
+ @Override
public int getAttributeUnsignedIntValue(String namespace, String attribute, int defaultValue) {
return mAttrib.getAttributeUnsignedIntValue(namespace, attribute, defaultValue);
}
+ @Override
public String getClassAttribute() {
return mAttrib.getClassAttribute();
}
+ @Override
public String getIdAttribute() {
return mAttrib.getIdAttribute();
}
+ @Override
public int getIdAttributeResourceValue(int defaultValue) {
return mAttrib.getIdAttributeResourceValue(defaultValue);
}
+ @Override
public int getStyleAttribute() {
return mAttrib.getStyleAttribute();
}
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderSessionImpl.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderSessionImpl.java
index d5400d7..6840f46 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderSessionImpl.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderSessionImpl.java
@@ -33,10 +33,10 @@
import com.android.ide.common.rendering.api.ResourceReference;
import com.android.ide.common.rendering.api.ResourceValue;
import com.android.ide.common.rendering.api.Result;
-import com.android.ide.common.rendering.api.SessionParams;
-import com.android.ide.common.rendering.api.ViewInfo;
import com.android.ide.common.rendering.api.Result.Status;
+import com.android.ide.common.rendering.api.SessionParams;
import com.android.ide.common.rendering.api.SessionParams.RenderingMode;
+import com.android.ide.common.rendering.api.ViewInfo;
import com.android.internal.util.XmlUtils;
import com.android.layoutlib.bridge.Bridge;
import com.android.layoutlib.bridge.android.BridgeContext;
@@ -69,8 +69,8 @@
import android.view.AttachInfo_Accessor;
import android.view.BridgeInflater;
import android.view.View;
-import android.view.ViewGroup;
import android.view.View.MeasureSpec;
+import android.view.ViewGroup;
import android.view.ViewGroup.LayoutParams;
import android.view.ViewGroup.MarginLayoutParams;
import android.widget.AbsListView;
@@ -82,8 +82,8 @@
import android.widget.ListView;
import android.widget.QuickContactBadge;
import android.widget.TabHost;
-import android.widget.TabWidget;
import android.widget.TabHost.TabSpec;
+import android.widget.TabWidget;
import java.awt.AlphaComposite;
import java.awt.Color;
@@ -835,6 +835,7 @@
previousTransition.addTransitionListener(new TransitionListener() {
private int mChangeDisappearingCount = 0;
+ @Override
public void startTransition(LayoutTransition transition, ViewGroup container,
View view, int transitionType) {
if (transitionType == LayoutTransition.CHANGE_DISAPPEARING) {
@@ -842,6 +843,7 @@
}
}
+ @Override
public void endTransition(LayoutTransition transition, ViewGroup container,
View view, int transitionType) {
if (transitionType == LayoutTransition.CHANGE_DISAPPEARING) {
@@ -1227,6 +1229,7 @@
TabSpec spec = tabHost.newTabSpec("tag").setIndicator("Tab Label",
tabHost.getResources().getDrawable(android.R.drawable.ic_menu_info_details))
.setContent(new TabHost.TabContentFactory() {
+ @Override
public View createTabContent(String tag) {
return new LinearLayout(getContext());
}
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/binding/FakeAdapter.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/binding/FakeAdapter.java
index c9bb424..22570b9 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/binding/FakeAdapter.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/binding/FakeAdapter.java
@@ -74,38 +74,46 @@
}
}
+ @Override
public boolean isEnabled(int position) {
return true;
}
+ @Override
public int getCount() {
return mItems.size();
}
+ @Override
public Object getItem(int position) {
return mItems.get(position);
}
+ @Override
public long getItemId(int position) {
return position;
}
+ @Override
public int getItemViewType(int position) {
return mItems.get(position).getType();
}
+ @Override
public View getView(int position, View convertView, ViewGroup parent) {
// we don't care about recycling here because we never scroll.
AdapterItem item = mItems.get(position);
return getView(item, null /*parentGroup*/, convertView, parent);
}
+ @Override
public int getViewTypeCount() {
return mTypes.size();
}
// ---- SpinnerAdapter
+ @Override
public View getDropDownView(int position, View convertView, ViewGroup parent) {
// pass
return null;
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/binding/FakeExpandableAdapter.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/binding/FakeExpandableAdapter.java
index 2c492e3..199e040 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/binding/FakeExpandableAdapter.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/binding/FakeExpandableAdapter.java
@@ -99,23 +99,28 @@
// ---- ExpandableListAdapter
+ @Override
public int getGroupCount() {
return mItems.size();
}
+ @Override
public int getChildrenCount(int groupPosition) {
AdapterItem item = mItems.get(groupPosition);
return item.getChildren().size();
}
+ @Override
public Object getGroup(int groupPosition) {
return mItems.get(groupPosition);
}
+ @Override
public Object getChild(int groupPosition, int childPosition) {
return getChildItem(groupPosition, childPosition);
}
+ @Override
public View getGroupView(int groupPosition, boolean isExpanded, View convertView,
ViewGroup parent) {
// we don't care about recycling here because we never scroll.
@@ -123,6 +128,7 @@
return getView(item, null /*parentItem*/, convertView, parent);
}
+ @Override
public View getChildView(int groupPosition, int childPosition, boolean isLastChild,
View convertView, ViewGroup parent) {
// we don't care about recycling here because we never scroll.
@@ -131,48 +137,59 @@
return getView(item, parentItem, convertView, parent);
}
+ @Override
public long getGroupId(int groupPosition) {
return groupPosition;
}
+ @Override
public long getChildId(int groupPosition, int childPosition) {
return childPosition;
}
+ @Override
public long getCombinedGroupId(long groupId) {
return groupId << 16 | 0x0000FFFF;
}
+ @Override
public long getCombinedChildId(long groupId, long childId) {
return groupId << 16 | childId;
}
+ @Override
public boolean isChildSelectable(int groupPosition, int childPosition) {
return true;
}
+ @Override
public void onGroupCollapsed(int groupPosition) {
// pass
}
+ @Override
public void onGroupExpanded(int groupPosition) {
// pass
}
// ---- HeterogeneousExpandableList
+ @Override
public int getChildType(int groupPosition, int childPosition) {
return getChildItem(groupPosition, childPosition).getType();
}
+ @Override
public int getChildTypeCount() {
return mChildrenTypes.size();
}
+ @Override
public int getGroupType(int groupPosition) {
return mItems.get(groupPosition).getType();
}
+ @Override
public int getGroupTypeCount() {
return mGroupTypes.size();
}
diff --git a/tools/layoutlib/create/.settings/README.txt b/tools/layoutlib/create/.settings/README.txt
new file mode 100644
index 0000000..9120b20
--- /dev/null
+++ b/tools/layoutlib/create/.settings/README.txt
@@ -0,0 +1,2 @@
+Copy this in eclipse project as a .settings folder at the root.
+This ensure proper compilation compliance and warning/error levels.
\ No newline at end of file
diff --git a/tools/layoutlib/create/.settings/org.eclipse.jdt.core.prefs b/tools/layoutlib/create/.settings/org.eclipse.jdt.core.prefs
new file mode 100644
index 0000000..5381a0e
--- /dev/null
+++ b/tools/layoutlib/create/.settings/org.eclipse.jdt.core.prefs
@@ -0,0 +1,93 @@
+eclipse.preferences.version=1
+org.eclipse.jdt.core.compiler.annotation.nonnull=com.android.annotations.NonNull
+org.eclipse.jdt.core.compiler.annotation.nonnullbydefault=com.android.annotations.NonNullByDefault
+org.eclipse.jdt.core.compiler.annotation.nonnullisdefault=disabled
+org.eclipse.jdt.core.compiler.annotation.nullable=com.android.annotations.Nullable
+org.eclipse.jdt.core.compiler.annotation.nullanalysis=enabled
+org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
+org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6
+org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve
+org.eclipse.jdt.core.compiler.compliance=1.6
+org.eclipse.jdt.core.compiler.debug.lineNumber=generate
+org.eclipse.jdt.core.compiler.debug.localVariable=generate
+org.eclipse.jdt.core.compiler.debug.sourceFile=generate
+org.eclipse.jdt.core.compiler.problem.annotationSuperInterface=warning
+org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
+org.eclipse.jdt.core.compiler.problem.autoboxing=ignore
+org.eclipse.jdt.core.compiler.problem.comparingIdentical=warning
+org.eclipse.jdt.core.compiler.problem.deadCode=warning
+org.eclipse.jdt.core.compiler.problem.deprecation=warning
+org.eclipse.jdt.core.compiler.problem.deprecationInDeprecatedCode=disabled
+org.eclipse.jdt.core.compiler.problem.deprecationWhenOverridingDeprecatedMethod=disabled
+org.eclipse.jdt.core.compiler.problem.discouragedReference=warning
+org.eclipse.jdt.core.compiler.problem.emptyStatement=ignore
+org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
+org.eclipse.jdt.core.compiler.problem.explicitlyClosedAutoCloseable=ignore
+org.eclipse.jdt.core.compiler.problem.fallthroughCase=warning
+org.eclipse.jdt.core.compiler.problem.fatalOptionalError=enabled
+org.eclipse.jdt.core.compiler.problem.fieldHiding=warning
+org.eclipse.jdt.core.compiler.problem.finalParameterBound=warning
+org.eclipse.jdt.core.compiler.problem.finallyBlockNotCompletingNormally=warning
+org.eclipse.jdt.core.compiler.problem.forbiddenReference=error
+org.eclipse.jdt.core.compiler.problem.hiddenCatchBlock=warning
+org.eclipse.jdt.core.compiler.problem.includeNullInfoFromAsserts=enabled
+org.eclipse.jdt.core.compiler.problem.incompatibleNonInheritedInterfaceMethod=warning
+org.eclipse.jdt.core.compiler.problem.incompleteEnumSwitch=ignore
+org.eclipse.jdt.core.compiler.problem.indirectStaticAccess=ignore
+org.eclipse.jdt.core.compiler.problem.localVariableHiding=warning
+org.eclipse.jdt.core.compiler.problem.methodWithConstructorName=warning
+org.eclipse.jdt.core.compiler.problem.missingDeprecatedAnnotation=warning
+org.eclipse.jdt.core.compiler.problem.missingHashCodeMethod=warning
+org.eclipse.jdt.core.compiler.problem.missingOverrideAnnotation=error
+org.eclipse.jdt.core.compiler.problem.missingOverrideAnnotationForInterfaceMethodImplementation=enabled
+org.eclipse.jdt.core.compiler.problem.missingSerialVersion=warning
+org.eclipse.jdt.core.compiler.problem.missingSynchronizedOnInheritedMethod=ignore
+org.eclipse.jdt.core.compiler.problem.noEffectAssignment=warning
+org.eclipse.jdt.core.compiler.problem.noImplicitStringConversion=warning
+org.eclipse.jdt.core.compiler.problem.nonExternalizedStringLiteral=ignore
+org.eclipse.jdt.core.compiler.problem.nullReference=error
+org.eclipse.jdt.core.compiler.problem.nullSpecInsufficientInfo=warning
+org.eclipse.jdt.core.compiler.problem.nullSpecViolation=error
+org.eclipse.jdt.core.compiler.problem.overridingPackageDefaultMethod=warning
+org.eclipse.jdt.core.compiler.problem.parameterAssignment=ignore
+org.eclipse.jdt.core.compiler.problem.possibleAccidentalBooleanAssignment=warning
+org.eclipse.jdt.core.compiler.problem.potentialNullReference=warning
+org.eclipse.jdt.core.compiler.problem.potentialNullSpecViolation=error
+org.eclipse.jdt.core.compiler.problem.potentiallyUnclosedCloseable=warning
+org.eclipse.jdt.core.compiler.problem.rawTypeReference=warning
+org.eclipse.jdt.core.compiler.problem.redundantNullAnnotation=warning
+org.eclipse.jdt.core.compiler.problem.redundantNullCheck=ignore
+org.eclipse.jdt.core.compiler.problem.redundantSpecificationOfTypeArguments=ignore
+org.eclipse.jdt.core.compiler.problem.redundantSuperinterface=warning
+org.eclipse.jdt.core.compiler.problem.reportMethodCanBePotentiallyStatic=ignore
+org.eclipse.jdt.core.compiler.problem.reportMethodCanBeStatic=ignore
+org.eclipse.jdt.core.compiler.problem.specialParameterHidingField=disabled
+org.eclipse.jdt.core.compiler.problem.staticAccessReceiver=warning
+org.eclipse.jdt.core.compiler.problem.suppressOptionalErrors=disabled
+org.eclipse.jdt.core.compiler.problem.suppressWarnings=enabled
+org.eclipse.jdt.core.compiler.problem.syntheticAccessEmulation=ignore
+org.eclipse.jdt.core.compiler.problem.typeParameterHiding=warning
+org.eclipse.jdt.core.compiler.problem.unavoidableGenericTypeProblems=disabled
+org.eclipse.jdt.core.compiler.problem.uncheckedTypeOperation=warning
+org.eclipse.jdt.core.compiler.problem.unclosedCloseable=error
+org.eclipse.jdt.core.compiler.problem.undocumentedEmptyBlock=ignore
+org.eclipse.jdt.core.compiler.problem.unhandledWarningToken=warning
+org.eclipse.jdt.core.compiler.problem.unnecessaryElse=ignore
+org.eclipse.jdt.core.compiler.problem.unnecessaryTypeCheck=warning
+org.eclipse.jdt.core.compiler.problem.unqualifiedFieldAccess=ignore
+org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownException=warning
+org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionExemptExceptionAndThrowable=enabled
+org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionIncludeDocCommentReference=enabled
+org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionWhenOverriding=disabled
+org.eclipse.jdt.core.compiler.problem.unusedImport=warning
+org.eclipse.jdt.core.compiler.problem.unusedLabel=warning
+org.eclipse.jdt.core.compiler.problem.unusedLocal=warning
+org.eclipse.jdt.core.compiler.problem.unusedObjectAllocation=warning
+org.eclipse.jdt.core.compiler.problem.unusedParameter=ignore
+org.eclipse.jdt.core.compiler.problem.unusedParameterIncludeDocCommentReference=enabled
+org.eclipse.jdt.core.compiler.problem.unusedParameterWhenImplementingAbstract=disabled
+org.eclipse.jdt.core.compiler.problem.unusedParameterWhenOverridingConcrete=disabled
+org.eclipse.jdt.core.compiler.problem.unusedPrivateMember=warning
+org.eclipse.jdt.core.compiler.problem.unusedWarningToken=warning
+org.eclipse.jdt.core.compiler.problem.varargsArgumentNeedCast=warning
+org.eclipse.jdt.core.compiler.source=1.6
diff --git a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/CreateInfo.java b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/CreateInfo.java
index 70c8a00..4b33474 100644
--- a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/CreateInfo.java
+++ b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/CreateInfo.java
@@ -27,6 +27,7 @@
* Returns the list of class from layoutlib_create to inject in layoutlib.
* The list can be empty but must not be null.
*/
+ @Override
public Class<?>[] getInjectedClasses() {
return INJECTED_CLASSES;
}
@@ -35,6 +36,7 @@
* Returns the list of methods to rewrite as delegates.
* The list can be empty but must not be null.
*/
+ @Override
public String[] getDelegateMethods() {
return DELEGATE_METHODS;
}
@@ -43,6 +45,7 @@
* Returns the list of classes on which to delegate all native methods.
* The list can be empty but must not be null.
*/
+ @Override
public String[] getDelegateClassNatives() {
return DELEGATE_CLASS_NATIVES;
}
@@ -54,6 +57,7 @@
* <p/>
* This usage is deprecated. Please use method 'delegates' instead.
*/
+ @Override
public String[] getOverriddenMethods() {
return OVERRIDDEN_METHODS;
}
@@ -63,6 +67,7 @@
* of class to replace followed by the new FQCN.
* The list can be empty but must not be null.
*/
+ @Override
public String[] getRenamedClasses() {
return RENAMED_CLASSES;
}
@@ -74,6 +79,7 @@
* the methods to delete.
* The list can be empty but must not be null.
*/
+ @Override
public String[] getDeleteReturns() {
return DELETE_RETURNS;
}
diff --git a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/MethodAdapter.java b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/MethodAdapter.java
index 627ea17..7d1e4cf 100644
--- a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/MethodAdapter.java
+++ b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/MethodAdapter.java
@@ -28,13 +28,14 @@
* A stub method is being invoked.
* <p/>
* Known limitation: caller arguments are not available.
- *
+ *
* @param signature The signature of the method being invoked, composed of the
* binary class name followed by the method descriptor (aka argument
* types). Example: "com/foo/MyClass/InnerClass/printInt(I)V".
* @param isNative True if the method was a native method.
* @param caller The calling object. Null for static methods, "this" for instance methods.
*/
+ @Override
public void onInvokeV(String signature, boolean isNative, Object caller) {
}
@@ -43,6 +44,7 @@
* @see #onInvokeV(String, boolean, Object)
* @return an integer, or a boolean, or a short or a byte.
*/
+ @Override
public int onInvokeI(String signature, boolean isNative, Object caller) {
onInvokeV(signature, isNative, caller);
return 0;
@@ -53,6 +55,7 @@
* @see #onInvokeV(String, boolean, Object)
* @return a long.
*/
+ @Override
public long onInvokeL(String signature, boolean isNative, Object caller) {
onInvokeV(signature, isNative, caller);
return 0;
@@ -63,6 +66,7 @@
* @see #onInvokeV(String, boolean, Object)
* @return a float.
*/
+ @Override
public float onInvokeF(String signature, boolean isNative, Object caller) {
onInvokeV(signature, isNative, caller);
return 0;
@@ -73,6 +77,7 @@
* @see #onInvokeV(String, boolean, Object)
* @return a double.
*/
+ @Override
public double onInvokeD(String signature, boolean isNative, Object caller) {
onInvokeV(signature, isNative, caller);
return 0;
@@ -83,6 +88,7 @@
* @see #onInvokeV(String, boolean, Object)
* @return an object.
*/
+ @Override
public Object onInvokeA(String signature, boolean isNative, Object caller) {
onInvokeV(signature, isNative, caller);
return null;
diff --git a/tools/layoutlib/create/tests/com/android/tools/layoutlib/create/AsmGeneratorTest.java b/tools/layoutlib/create/tests/com/android/tools/layoutlib/create/AsmGeneratorTest.java
index f4ff389..7b76a5b 100644
--- a/tools/layoutlib/create/tests/com/android/tools/layoutlib/create/AsmGeneratorTest.java
+++ b/tools/layoutlib/create/tests/com/android/tools/layoutlib/create/AsmGeneratorTest.java
@@ -65,24 +65,29 @@
public void testClassRenaming() throws IOException, LogAbortException {
ICreateInfo ci = new ICreateInfo() {
+ @Override
public Class<?>[] getInjectedClasses() {
// classes to inject in the final JAR
return new Class<?>[0];
}
+ @Override
public String[] getDelegateMethods() {
return new String[0];
}
+ @Override
public String[] getDelegateClassNatives() {
return new String[0];
}
+ @Override
public String[] getOverriddenMethods() {
// methods to force override
return new String[0];
}
+ @Override
public String[] getRenamedClasses() {
// classes to rename (so that we can replace them)
return new String[] {
@@ -91,6 +96,7 @@
};
}
+ @Override
public String[] getDeleteReturns() {
// methods deleted from their return type.
return new String[0];
diff --git a/wifi/java/android/net/wifi/WifiStateMachine.java b/wifi/java/android/net/wifi/WifiStateMachine.java
index 8c9e472..b8b7c0e 100644
--- a/wifi/java/android/net/wifi/WifiStateMachine.java
+++ b/wifi/java/android/net/wifi/WifiStateMachine.java
@@ -1625,6 +1625,10 @@
private void handleNetworkDisconnect() {
if (DBG) log("Stopping DHCP and clearing IP");
+ /* In case we were in middle of DHCP operation
+ restore back powermode */
+ handlePostDhcpSetup();
+
/*
* stop DHCP
*/