Merge "Fix a race that could cause GL commands to be executed from the wrong thread."
diff --git a/Android.mk b/Android.mk
index 9bd30fe..b8a48a4 100644
--- a/Android.mk
+++ b/Android.mk
@@ -109,6 +109,7 @@
core/java/android/net/IConnectivityManager.aidl \
core/java/android/net/INetworkManagementEventObserver.aidl \
core/java/android/net/IThrottleManager.aidl \
+ core/java/android/net/INetworkPolicyManager.aidl \
core/java/android/nfc/ILlcpConnectionlessSocket.aidl \
core/java/android/nfc/ILlcpServiceSocket.aidl \
core/java/android/nfc/ILlcpSocket.aidl \
diff --git a/api/14.txt b/api/14.txt
index ebb4308..b080d25 100644
--- a/api/14.txt
+++ b/api/14.txt
@@ -22002,7 +22002,7 @@
method public boolean isEnabled();
method public boolean isFullScreen();
method public boolean isPassword();
- method protected static android.view.accessibility.AccessibilityRecord obtain();
+ method public static android.view.accessibility.AccessibilityRecord obtain();
method public void recycle();
method public void setAddedCount(int);
method public void setBeforeText(java.lang.CharSequence);
diff --git a/api/current.txt b/api/current.txt
index 1309575..3c8e551 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -8839,6 +8839,7 @@
field public static final deprecated int TYPE_ORIENTATION = 3; // 0x3
field public static final int TYPE_PRESSURE = 6; // 0x6
field public static final int TYPE_PROXIMITY = 8; // 0x8
+ field public static final int TYPE_RELATIVE_HUMIDITY = 12; // 0xc
field public static final int TYPE_ROTATION_VECTOR = 11; // 0xb
field public static final deprecated int TYPE_TEMPERATURE = 7; // 0x7
}
@@ -9015,6 +9016,7 @@
method public void close();
method public int controlTransfer(int, int, int, int, byte[], int, int);
method public int getFileDescriptor();
+ method public byte[] getRawDescriptors();
method public java.lang.String getSerial();
method public boolean releaseInterface(android.hardware.usb.UsbInterface);
method public android.hardware.usb.UsbRequest requestWait();
@@ -10113,6 +10115,7 @@
method public void setAuxiliaryOutputFile(java.lang.String);
method public void setCamera(android.hardware.Camera);
method public void setCaptureRate(double);
+ method public void setLocation(float, float);
method public void setMaxDuration(int) throws java.lang.IllegalArgumentException;
method public void setMaxFileSize(long) throws java.lang.IllegalArgumentException;
method public void setOnErrorListener(android.media.MediaRecorder.OnErrorListener);
@@ -17137,7 +17140,7 @@
package android.speech.tts {
public abstract class SynthesisRequest {
- ctor public SynthesisRequest(java.lang.String);
+ ctor public SynthesisRequest(java.lang.String, android.os.Bundle);
method public abstract int audioAvailable(byte[], int, int);
method public abstract int completeAudioAvailable(int, int, int, byte[], int, int);
method public abstract int done();
@@ -17145,6 +17148,7 @@
method public java.lang.String getCountry();
method public java.lang.String getLanguage();
method public abstract int getMaxBufferSize();
+ method public android.os.Bundle getParams();
method public int getPitch();
method public int getSpeechRate();
method public java.lang.String getText();
@@ -21270,6 +21274,7 @@
method public boolean isInEditMode();
method public boolean isInTouchMode();
method public boolean isLayoutRequested();
+ method public boolean isLayoutRtl();
method public boolean isLongClickable();
method public boolean isOpaque();
method protected boolean isPaddingOffsetRequired();
@@ -22239,7 +22244,7 @@
method public boolean isEnabled();
method public boolean isFullScreen();
method public boolean isPassword();
- method protected static android.view.accessibility.AccessibilityRecord obtain();
+ method public static android.view.accessibility.AccessibilityRecord obtain();
method public void recycle();
method public void setAddedCount(int);
method public void setBeforeText(java.lang.CharSequence);
@@ -24008,6 +24013,7 @@
ctor public ExpandableListView(android.content.Context, android.util.AttributeSet, int);
method public boolean collapseGroup(int);
method public boolean expandGroup(int);
+ method public boolean expandGroup(int, boolean);
method public android.widget.ExpandableListAdapter getExpandableListAdapter();
method public long getExpandableListPosition(int);
method public int getFlatListPosition(long);
diff --git a/cmds/am/src/com/android/commands/am/Am.java b/cmds/am/src/com/android/commands/am/Am.java
index 8a9144c..38cacdd 100644
--- a/cmds/am/src/com/android/commands/am/Am.java
+++ b/cmds/am/src/com/android/commands/am/Am.java
@@ -25,6 +25,7 @@
import android.app.IInstrumentationWatcher;
import android.app.Instrumentation;
import android.content.ComponentName;
+import android.content.Context;
import android.content.IIntentReceiver;
import android.content.Intent;
import android.net.Uri;
@@ -109,6 +110,8 @@
runMonitor();
} else if (op.equals("screen-compat")) {
runScreenCompat();
+ } else if (op.equals("display-size")) {
+ runDisplaySize();
} else {
throw new IllegalArgumentException("Unknown command: " + op);
}
@@ -804,6 +807,53 @@
} while (packageName != null);
}
+ private void runDisplaySize() throws Exception {
+ String size = nextArgRequired();
+ int m, n;
+ if ("reset".equals(size)) {
+ m = n = -1;
+ } else {
+ int div = size.indexOf('x');
+ if (div <= 0 || div >= (size.length()-1)) {
+ System.err.println("Error: bad size " + size);
+ showUsage();
+ return;
+ }
+ String mstr = size.substring(0, div);
+ String nstr = size.substring(div+1);
+ try {
+ m = Integer.parseInt(mstr);
+ n = Integer.parseInt(nstr);
+ } catch (NumberFormatException e) {
+ System.err.println("Error: bad number " + e);
+ showUsage();
+ return;
+ }
+ }
+
+ if (m < n) {
+ int tmp = m;
+ m = n;
+ n = tmp;
+ }
+
+ IWindowManager wm = IWindowManager.Stub.asInterface(ServiceManager.checkService(
+ Context.WINDOW_SERVICE));
+ if (wm == null) {
+ System.err.println(NO_SYSTEM_ERROR_CODE);
+ throw new AndroidException("Can't connect to window manager; is the system running?");
+ }
+
+ try {
+ if (m >= 0 && n >= 0) {
+ wm.setForcedDisplaySize(m, n);
+ } else {
+ wm.clearForcedDisplaySize();
+ }
+ } catch (RemoteException e) {
+ }
+ }
+
private class IntentReceiver extends IIntentReceiver.Stub {
private boolean mFinished = false;
@@ -986,6 +1036,8 @@
"\n" +
" control screen compatibility: am screen-compat [on|off] [package]\n" +
"\n" +
+ " override display size: am display-size [reset|MxN]\n" +
+ "\n" +
" <INTENT> specifications include these flags:\n" +
" [-a <ACTION>] [-d <DATA_URI>] [-t <MIME_TYPE>]\n" +
" [-c <CATEGORY> [-c <CATEGORY>] ...]\n" +
diff --git a/cmds/dumpstate/dumpstate.c b/cmds/dumpstate/dumpstate.c
index b0d764f..21bb62e 100644
--- a/cmds/dumpstate/dumpstate.c
+++ b/cmds/dumpstate/dumpstate.c
@@ -133,12 +133,14 @@
"su", "root", "wlutil", "counters", NULL);
#endif
- char ril_dumpstate_timeout[PROPERTY_VALUE_MAX] = {0};
+#ifdef BROKEN_VRIL_IS_FIXED_B_4442803
+ char ril_dumpstate_timeout[PROPERTY_VALUE_MAX] = {0};
property_get("ril.dumpstate.timeout", ril_dumpstate_timeout, "30");
if (strlen(ril_dumpstate_timeout) > 0) {
run_command("DUMP VENDOR RIL LOGS", atoi(ril_dumpstate_timeout),
"su", "root", "vril-dump", NULL);
}
+#endif
print_properties();
diff --git a/cmds/pm/src/com/android/commands/pm/Pm.java b/cmds/pm/src/com/android/commands/pm/Pm.java
index 701c7ac..b0e4a86 100644
--- a/cmds/pm/src/com/android/commands/pm/Pm.java
+++ b/cmds/pm/src/com/android/commands/pm/Pm.java
@@ -30,11 +30,13 @@
import android.content.pm.PackageInfo;
import android.content.pm.PackageItemInfo;
import android.content.pm.PackageManager;
+import android.content.pm.ParceledListSlice;
import android.content.pm.PermissionGroupInfo;
import android.content.pm.PermissionInfo;
import android.content.res.AssetManager;
import android.content.res.Resources;
import android.net.Uri;
+import android.os.Parcel;
import android.os.Process;
import android.os.RemoteException;
import android.os.ServiceManager;
@@ -239,7 +241,7 @@
String filter = nextArg();
try {
- List<PackageInfo> packages = mPm.getInstalledPackages(getFlags);
+ final List<PackageInfo> packages = getInstalledPackages(mPm, getFlags);
int count = packages.size();
for (int p = 0 ; p < count ; p++) {
@@ -267,6 +269,22 @@
}
}
+ @SuppressWarnings("unchecked")
+ private List<PackageInfo> getInstalledPackages(IPackageManager pm, int flags)
+ throws RemoteException {
+ final List<PackageInfo> packageInfos = new ArrayList<PackageInfo>();
+ PackageInfo lastItem = null;
+ ParceledListSlice<PackageInfo> slice;
+
+ do {
+ final String lastKey = lastItem != null ? lastItem.packageName : null;
+ slice = pm.getInstalledPackages(flags, lastKey);
+ lastItem = slice.populateList(packageInfos, PackageInfo.CREATOR);
+ } while (!slice.isLastSlice());
+
+ return packageInfos;
+ }
+
/**
* Lists all of the features supported by the current device.
*
diff --git a/core/java/android/app/ApplicationPackageManager.java b/core/java/android/app/ApplicationPackageManager.java
index 85918cf..4cff12f 100644
--- a/core/java/android/app/ApplicationPackageManager.java
+++ b/core/java/android/app/ApplicationPackageManager.java
@@ -34,6 +34,7 @@
import android.content.pm.InstrumentationInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
+import android.content.pm.ParceledListSlice;
import android.content.pm.PermissionGroupInfo;
import android.content.pm.PermissionInfo;
import android.content.pm.ProviderInfo;
@@ -44,6 +45,7 @@
import android.content.res.XmlResourceParser;
import android.graphics.drawable.Drawable;
import android.net.Uri;
+import android.os.Parcel;
import android.os.Process;
import android.os.RemoteException;
import android.util.Log;
@@ -378,19 +380,41 @@
throw new NameNotFoundException("No shared userid for user:"+sharedUserName);
}
+ @SuppressWarnings("unchecked")
@Override
public List<PackageInfo> getInstalledPackages(int flags) {
try {
- return mPM.getInstalledPackages(flags);
+ final List<PackageInfo> packageInfos = new ArrayList<PackageInfo>();
+ PackageInfo lastItem = null;
+ ParceledListSlice<PackageInfo> slice;
+
+ do {
+ final String lastKey = lastItem != null ? lastItem.packageName : null;
+ slice = mPM.getInstalledPackages(flags, lastKey);
+ lastItem = slice.populateList(packageInfos, PackageInfo.CREATOR);
+ } while (!slice.isLastSlice());
+
+ return packageInfos;
} catch (RemoteException e) {
throw new RuntimeException("Package manager has died", e);
}
}
+ @SuppressWarnings("unchecked")
@Override
public List<ApplicationInfo> getInstalledApplications(int flags) {
try {
- return mPM.getInstalledApplications(flags);
+ final List<ApplicationInfo> applicationInfos = new ArrayList<ApplicationInfo>();
+ ApplicationInfo lastItem = null;
+ ParceledListSlice<ApplicationInfo> slice;
+
+ do {
+ final String lastKey = lastItem != null ? lastItem.packageName : null;
+ slice = mPM.getInstalledApplications(flags, lastKey);
+ lastItem = slice.populateList(applicationInfos, ApplicationInfo.CREATOR);
+ } while (!slice.isLastSlice());
+
+ return applicationInfos;
} catch (RemoteException e) {
throw new RuntimeException("Package manager has died", e);
}
diff --git a/core/java/android/content/pm/IPackageManager.aidl b/core/java/android/content/pm/IPackageManager.aidl
index 11cd446..37b6822 100644
--- a/core/java/android/content/pm/IPackageManager.aidl
+++ b/core/java/android/content/pm/IPackageManager.aidl
@@ -30,6 +30,7 @@
import android.content.pm.IPackageStatsObserver;
import android.content.pm.InstrumentationInfo;
import android.content.pm.PackageInfo;
+import android.content.pm.ParceledListSlice;
import android.content.pm.ProviderInfo;
import android.content.pm.PermissionGroupInfo;
import android.content.pm.PermissionInfo;
@@ -110,9 +111,21 @@
List<ResolveInfo> queryIntentServices(in Intent intent,
String resolvedType, int flags);
- List<PackageInfo> getInstalledPackages(int flags);
+ /**
+ * This implements getInstalledPackages via a "last returned row"
+ * mechanism that is not exposed in the API. This is to get around the IPC
+ * limit that kicks in when flags are included that bloat up the data
+ * returned.
+ */
+ ParceledListSlice getInstalledPackages(int flags, in String lastRead);
- List<ApplicationInfo> getInstalledApplications(int flags);
+ /**
+ * This implements getInstalledApplications via a "last returned row"
+ * mechanism that is not exposed in the API. This is to get around the IPC
+ * limit that kicks in when flags are included that bloat up the data
+ * returned.
+ */
+ ParceledListSlice getInstalledApplications(int flags, in String lastRead);
/**
* Retrieve all applications that are marked as persistent.
diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java
index b8cb165..18120ac 100644
--- a/core/java/android/content/pm/PackageParser.java
+++ b/core/java/android/content/pm/PackageParser.java
@@ -1942,7 +1942,7 @@
com.android.internal.R.styleable.AndroidManifestActivity_configChanges,
0);
if (owner.applicationInfo.targetSdkVersion
- < android.os.Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
+ < android.os.Build.VERSION_CODES.HONEYCOMB_MR2) {
a.info.configChanges |= ActivityInfo.CONFIG_SCREEN_SIZE;
}
a.info.softInputMode = sa.getInt(
diff --git a/core/java/android/content/pm/ParceledListSlice.aidl b/core/java/android/content/pm/ParceledListSlice.aidl
new file mode 100755
index 0000000..c02cc6a
--- /dev/null
+++ b/core/java/android/content/pm/ParceledListSlice.aidl
@@ -0,0 +1,19 @@
+/*
+ * 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.
+ */
+
+package android.content.pm;
+
+parcelable ParceledListSlice;
diff --git a/core/java/android/content/pm/ParceledListSlice.java b/core/java/android/content/pm/ParceledListSlice.java
new file mode 100644
index 0000000..f3a98db4
--- /dev/null
+++ b/core/java/android/content/pm/ParceledListSlice.java
@@ -0,0 +1,170 @@
+/*
+ * 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 android.content.pm;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.util.List;
+
+/**
+ * Builds up a parcel that is discarded when written to another parcel or
+ * written to a list. This is useful for API that sends huge lists across a
+ * Binder that may be larger than the IPC limit.
+ *
+ * @hide
+ */
+public class ParceledListSlice<T extends Parcelable> implements Parcelable {
+ /*
+ * TODO get this number from somewhere else. For now set it to a quarter of
+ * the 1MB limit.
+ */
+ private static final int MAX_IPC_SIZE = 256 * 1024;
+
+ private Parcel mParcel;
+
+ private int mNumItems;
+
+ private boolean mIsLastSlice;
+
+ public ParceledListSlice() {
+ mParcel = Parcel.obtain();
+ }
+
+ private ParceledListSlice(Parcel p, int numItems, boolean lastSlice) {
+ mParcel = p;
+ mNumItems = numItems;
+ mIsLastSlice = lastSlice;
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ /**
+ * Write this to another Parcel. Note that this discards the internal Parcel
+ * and should not be used anymore. This is so we can pass this to a Binder
+ * where we won't have a chance to call recycle on this.
+ */
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeInt(mNumItems);
+ dest.writeInt(mIsLastSlice ? 1 : 0);
+
+ if (mNumItems > 0) {
+ final int parcelSize = mParcel.dataSize();
+ dest.writeInt(parcelSize);
+ dest.appendFrom(mParcel, 0, parcelSize);
+ }
+
+ mNumItems = 0;
+ mParcel.recycle();
+ mParcel = null;
+ }
+
+ /**
+ * Appends a parcel to this list slice.
+ *
+ * @param item Parcelable item to append to this list slice
+ * @return true when the list slice is full and should not be appended to
+ * anymore
+ */
+ public boolean append(T item) {
+ if (mParcel == null) {
+ throw new IllegalStateException("ParceledListSlice has already been recycled");
+ }
+
+ item.writeToParcel(mParcel, PARCELABLE_WRITE_RETURN_VALUE);
+ mNumItems++;
+
+ return mParcel.dataSize() > MAX_IPC_SIZE;
+ }
+
+ /**
+ * Populates a list and discards the internal state of the
+ * ParceledListSlice in the process. The instance should
+ * not be used anymore.
+ *
+ * @param list list to insert items from this slice.
+ * @param creator creator that knows how to unparcel the
+ * target object type.
+ * @return the last item inserted into the list or null if none.
+ */
+ public T populateList(List<T> list, Creator<T> creator) {
+ mParcel.setDataPosition(0);
+
+ T item = null;
+ for (int i = 0; i < mNumItems; i++) {
+ item = creator.createFromParcel(mParcel);
+ list.add(item);
+ }
+
+ mParcel.recycle();
+ mParcel = null;
+
+ return item;
+ }
+
+ /**
+ * Sets whether this is the last list slice in the series.
+ *
+ * @param lastSlice
+ */
+ public void setLastSlice(boolean lastSlice) {
+ mIsLastSlice = lastSlice;
+ }
+
+ /**
+ * Returns whether this is the last slice in a series of slices.
+ *
+ * @return true if this is the last slice in the series.
+ */
+ public boolean isLastSlice() {
+ return mIsLastSlice;
+ }
+
+ @SuppressWarnings("unchecked")
+ public static final Parcelable.Creator<ParceledListSlice> CREATOR =
+ new Parcelable.Creator<ParceledListSlice>() {
+ public ParceledListSlice createFromParcel(Parcel in) {
+ final int numItems = in.readInt();
+ final boolean lastSlice = in.readInt() == 1;
+
+ if (numItems > 0) {
+ final int parcelSize = in.readInt();
+
+ // Advance within this Parcel
+ int offset = in.dataPosition();
+ in.setDataPosition(offset + parcelSize);
+
+ Parcel p = Parcel.obtain();
+ p.setDataPosition(0);
+ p.appendFrom(in, offset, parcelSize);
+ p.setDataPosition(0);
+
+ return new ParceledListSlice(p, numItems, lastSlice);
+ } else {
+ return new ParceledListSlice();
+ }
+ }
+
+ public ParceledListSlice[] newArray(int size) {
+ return new ParceledListSlice[size];
+ }
+ };
+}
diff --git a/core/java/android/hardware/Camera.java b/core/java/android/hardware/Camera.java
index 6d955e7..d5c4ace 100644
--- a/core/java/android/hardware/Camera.java
+++ b/core/java/android/hardware/Camera.java
@@ -1181,6 +1181,8 @@
private static final String KEY_EXPOSURE_COMPENSATION_STEP = "exposure-compensation-step";
private static final String KEY_AUTO_EXPOSURE_LOCK = "auto-exposure-lock";
private static final String KEY_AUTO_EXPOSURE_LOCK_SUPPORTED = "auto-exposure-lock-supported";
+ private static final String KEY_AUTO_WHITEBALANCE_LOCK = "auto-whitebalance-lock";
+ private static final String KEY_AUTO_WHITEBALANCE_LOCK_SUPPORTED = "auto-whitebalance-lock-supported";
private static final String KEY_METERING_AREAS = "metering-areas";
private static final String KEY_MAX_NUM_METERING_AREAS = "max-num-metering-areas";
private static final String KEY_ZOOM = "zoom";
@@ -2468,37 +2470,47 @@
}
/**
- * Sets the auto-exposure lock state. Applications should check
- * {@link #isAutoExposureLockSupported} before using this method.
+ * <p>Sets the auto-exposure lock state. Applications should check
+ * {@link #isAutoExposureLockSupported} before using this method.</p>
*
- * If set to true, the camera auto-exposure routine will pause until the
- * lock is set to false. Exposure compensation settings changes will
- * still take effect while auto-exposure is locked. Stopping preview
- * with {@link #stopPreview()}, or triggering still image capture with
- * {@link #takePicture(Camera.ShutterCallback, Camera.PictureCallback,
- * Camera.PictureCallback)}, will automatically set the lock to
- * false. However, the lock can be re-enabled before preview is
- * re-started to keep the same AE parameters. Exposure compensation, in
- * conjunction with re-enabling the AE lock after each still capture,
- * can be used to capture an exposure-bracketed burst of images, for
- * example. Auto-exposure state, including the lock state, will not be
+ * <p>If set to true, the camera auto-exposure routine will immediately
+ * pause until the lock is set to false. Exposure compensation settings
+ * changes will still take effect while auto-exposure is locked.</p>
+ *
+ * <p>If auto-exposure is already locked, setting this to true again has
+ * no effect (the driver will not recalculate exposure values).</p>
+ *
+ * <p>Stopping preview with {@link #stopPreview()}, or triggering still
+ * image capture with {@link #takePicture(Camera.ShutterCallback,
+ * Camera.PictureCallback, Camera.PictureCallback)}, will automatically
+ * set the lock to false. However, the lock can be re-enabled before
+ * preview is re-started to keep the same AE parameters.</p>
+ *
+ * <p>Exposure compensation, in conjunction with re-enabling the AE and
+ * AWB locks after each still capture, can be used to capture an
+ * exposure-bracketed burst of images, for example.</p>
+ *
+ * <p>Auto-exposure state, including the lock state, will not be
* maintained after camera {@link #release()} is called. Locking
* auto-exposure after {@link #open()} but before the first call to
* {@link #startPreview()} will not allow the auto-exposure routine to
- * run at all, and may result in severely over- or under-exposed images.
+ * run at all, and may result in severely over- or under-exposed
+ * images.</p>
*
- * The driver may also independently lock auto-exposure after auto-focus
- * completes. If this is undesirable, be sure to always set the
- * auto-exposure lock to false after the
+ * <p>The driver may also independently lock auto-exposure after
+ * auto-focus completes. If this is undesirable, be sure to always set
+ * the auto-exposure lock to false after the
* {@link AutoFocusCallback#onAutoFocus(boolean, Camera)} callback is
* received. The {@link #getAutoExposureLock()} method can be used after
* the callback to determine if the camera has locked auto-exposure
- * independently.
+ * independently.</p>
*
* @param toggle new state of the auto-exposure lock. True means that
* auto-exposure is locked, false means that the auto-exposure
* routine is free to run normally.
*
+ * @see #getAutoExposureLock()
+ *
* @hide
*/
public void setAutoExposureLock(boolean toggle) {
@@ -2542,6 +2554,91 @@
}
/**
+ * <p>Sets the auto-white balance lock state. Applications should check
+ * {@link #isAutoWhiteBalanceLockSupported} before using this
+ * method.</p>
+ *
+ * <p>If set to true, the camera auto-white balance routine will
+ * immediately pause until the lock is set to false.</p>
+ *
+ * <p>If auto-white balance is already locked, setting this to true
+ * again has no effect (the driver will not recalculate white balance
+ * values).</p>
+ *
+ * <p>Stopping preview with {@link #stopPreview()}, or triggering still
+ * image capture with {@link #takePicture(Camera.ShutterCallback,
+ * Camera.PictureCallback, Camera.PictureCallback)}, will automatically
+ * set the lock to false. However, the lock can be re-enabled before
+ * preview is re-started to keep the same white balance parameters.</p>
+ *
+ * <p>Exposure compensation, in conjunction with re-enabling the AE and
+ * AWB locks after each still capture, can be used to capture an
+ * exposure-bracketed burst of images, for example. Auto-white balance
+ * state, including the lock state, will not be maintained after camera
+ * {@link #release()} is called. Locking auto-white balance after
+ * {@link #open()} but before the first call to {@link #startPreview()}
+ * will not allow the auto-white balance routine to run at all, and may
+ * result in severely incorrect color in captured images.</p>
+ *
+ * <p>The driver may also independently lock auto-white balance after
+ * auto-focus completes. If this is undesirable, be sure to always set
+ * the auto-white balance lock to false after the
+ * {@link AutoFocusCallback#onAutoFocus(boolean, Camera)} callback is
+ * received. The {@link #getAutoWhiteBalanceLock()} method can be used
+ * after the callback to determine if the camera has locked auto-white
+ * balance independently.</p>
+ *
+ * @param toggle new state of the auto-white balance lock. True means
+ * that auto-white balance is locked, false means that the
+ * auto-white balance routine is free to run normally.
+ *
+ * @see #getAutoWhiteBalanceLock()
+ *
+ * @hide
+ */
+ public void setAutoWhiteBalanceLock(boolean toggle) {
+ set(KEY_AUTO_WHITEBALANCE_LOCK, toggle ? TRUE : FALSE);
+ }
+
+ /**
+ * Gets the state of the auto-white balance lock. Applications should
+ * check {@link #isAutoWhiteBalanceLockSupported} before using this
+ * method. See {@link #setAutoWhiteBalanceLock} for details about the
+ * lock.
+ *
+ * @return State of the auto-white balance lock. Returns true if
+ * auto-white balance is currently locked, and false
+ * otherwise. The auto-white balance lock may be independently
+ * enabled by the camera subsystem when auto-focus has
+ * completed. This method can be used after the
+ * {@link AutoFocusCallback#onAutoFocus(boolean, Camera)}
+ * callback to determine if the camera has locked AWB.
+ *
+ * @see #setAutoWhiteBalanceLock(boolean)
+ *
+ * @hide
+ */
+ public boolean getAutoWhiteBalanceLock() {
+ String str = get(KEY_AUTO_WHITEBALANCE_LOCK);
+ return TRUE.equals(str);
+ }
+
+ /**
+ * Returns true if auto-white balance locking is supported. Applications
+ * should call this before trying to lock auto-white balance. See
+ * {@link #setAutoWhiteBalanceLock} for details about the lock.
+ *
+ * @return true if auto-white balance lock is supported.
+ * @see #setAutoWhiteBalanceLock(boolean)
+ *
+ * @hide
+ */
+ public boolean isAutoWhiteBalanceLockSupported() {
+ String str = get(KEY_AUTO_WHITEBALANCE_LOCK_SUPPORTED);
+ return TRUE.equals(str);
+ }
+
+ /**
* Gets current zoom value. This also works when smooth zoom is in
* progress. Applications should check {@link #isZoomSupported} before
* using this method.
diff --git a/core/java/android/hardware/Sensor.java b/core/java/android/hardware/Sensor.java
index a4ba3bd..68fc101 100644
--- a/core/java/android/hardware/Sensor.java
+++ b/core/java/android/hardware/Sensor.java
@@ -104,6 +104,13 @@
*/
public static final int TYPE_ROTATION_VECTOR = 11;
+ /**
+ * A constant describing a relative humidity sensor type.
+ * See {@link android.hardware.SensorEvent SensorEvent}
+ * for more details.
+ */
+ public static final int TYPE_RELATIVE_HUMIDITY = 12;
+
/** A constant describing an ambient temperature sensor type */
public static final int TYPE_AMBIENT_TEMPERATURE = 13;
diff --git a/core/java/android/hardware/SensorEvent.java b/core/java/android/hardware/SensorEvent.java
index b111b84..0411b5c 100644
--- a/core/java/android/hardware/SensorEvent.java
+++ b/core/java/android/hardware/SensorEvent.java
@@ -327,6 +327,64 @@
* in the clockwise direction (mathematically speaking, it should be
* positive in the counter-clockwise direction).
* </p>
+ *
+ * <h4>{@link android.hardware.Sensor#TYPE_RELATIVE_HUMIDITY
+ * Sensor.TYPE_RELATIVE_HUMIDITY}:</h4>
+ * <ul>
+ * <p>
+ * values[0]: Relative ambient air humidity in percent
+ * </p>
+ * </ul>
+ * <p>
+ * When relative ambient air humidity and ambient temperature are
+ * measured, the dew point and absolute humidity can be calculated.
+ * </p>
+ * <u>Dew Point</u>
+ * <p>
+ * The dew point is the temperature to which a given parcel of air must be
+ * cooled, at constant barometric pressure, for water vapor to condense
+ * into water.
+ * </p>
+ * <center><pre>
+ * ln(RH/100%) + m·t/(T<sub>n</sub>+t)
+ * t<sub>d</sub>(t,RH) = T<sub>n</sub> · ------------------------------
+ * m - [ln(RH/100%) + m·t/(T<sub>n</sub>+t)]
+ * </pre></center>
+ * <dl>
+ * <dt>t<sub>d</sub></dt> <dd>dew point temperature in °C</dd>
+ * <dt>t</dt> <dd>actual temperature in °C</dd>
+ * <dt>RH</dt> <dd>actual relative humidity in %</dd>
+ * <dt>m</dt> <dd>17.62</dd>
+ * <dt>T<sub>n</sub></dt> <dd>243.12 °C</dd>
+ * </dl>
+ * <p>for example:</p>
+ * <pre class="prettyprint">
+ * h = Math.log(rh / 100.0) + (17.62 * t) / (243.12 + t);
+ * td = 243.12 * h / (17.62 - h);
+ * </pre>
+ * <u>Absolute Humidity</u>
+ * <p>
+ * The absolute humidity is the mass of water vapor in a particular volume
+ * of dry air. The unit is g/m<sup>3</sup>.
+ * </p>
+ * <center><pre>
+ * RH/100%·A·exp(m·t/(T<sub>n</sub>+t))
+ * d<sub>v</sub>(t,RH) = 216.7 · -------------------------
+ * 273.15 + t
+ * </pre></center>
+ * <dl>
+ * <dt>d<sub>v</sub></dt> <dd>absolute humidity in g/m<sup>3</sup></dd>
+ * <dt>t</dt> <dd>actual temperature in °C</dd>
+ * <dt>RH</dt> <dd>actual relative humidity in %</dd>
+ * <dt>m</dt> <dd>17.62</dd>
+ * <dt>T<sub>n</sub></dt> <dd>243.12 °C</dd>
+ * <dt>A</dt> <dd>6.112 hPa</dd>
+ * </dl>
+ * <p>for example:</p>
+ * <pre class="prettyprint">
+ * dv = 216.7 *
+ * (rh / 100.0 * 6.112 * Math.exp(17.62 * t / (243.12 + t)) / (273.15 + t));
+ * </pre>
*
* <h4>{@link android.hardware.Sensor#TYPE_AMBIENT_TEMPERATURE Sensor.TYPE_AMBIENT_TEMPERATURE}:
* </h4>
diff --git a/core/java/android/hardware/usb/UsbDeviceConnection.java b/core/java/android/hardware/usb/UsbDeviceConnection.java
index a153c0b..b536490 100644
--- a/core/java/android/hardware/usb/UsbDeviceConnection.java
+++ b/core/java/android/hardware/usb/UsbDeviceConnection.java
@@ -69,6 +69,17 @@
}
/**
+ * Returns the raw USB descriptors for the device.
+ * This can be used to access descriptors not supported directly
+ * via the higher level APIs.
+ *
+ * @return raw USB descriptors
+ */
+ public byte[] getRawDescriptors() {
+ return native_get_desc();
+ }
+
+ /**
* Claims exclusive access to a {@link android.hardware.usb.UsbInterface}.
* This must be done before sending or receiving data on any
* {@link android.hardware.usb.UsbEndpoint}s belonging to the interface.
@@ -160,6 +171,7 @@
private native boolean native_open(String deviceName, FileDescriptor pfd);
private native void native_close();
private native int native_get_fd();
+ private native byte[] native_get_desc();
private native boolean native_claim_interface(int interfaceID, boolean force);
private native boolean native_release_interface(int interfaceID);
private native int native_control_request(int requestType, int request, int value,
diff --git a/core/java/android/net/INetworkPolicyManager.aidl b/core/java/android/net/INetworkPolicyManager.aidl
new file mode 100644
index 0000000..fa6eae5
--- /dev/null
+++ b/core/java/android/net/INetworkPolicyManager.aidl
@@ -0,0 +1,34 @@
+/*
+ * 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 android.net;
+
+/**
+ * Interface that creates and modifies network policy rules.
+ *
+ * {@hide}
+ */
+interface INetworkPolicyManager {
+
+ void onForegroundActivitiesChanged(int uid, int pid, boolean foregroundActivities);
+ void onProcessDied(int uid, int pid);
+
+ void setUidPolicy(int uid, int policy);
+ int getUidPolicy(int uid);
+
+ // TODO: build API to surface stats details for settings UI
+
+}
diff --git a/core/java/android/net/LinkProperties.java b/core/java/android/net/LinkProperties.java
index 61acf2b..19894a0 100644
--- a/core/java/android/net/LinkProperties.java
+++ b/core/java/android/net/LinkProperties.java
@@ -68,7 +68,8 @@
mLinkAddresses = source.getLinkAddresses();
mDnses = source.getDnses();
mRoutes = source.getRoutes();
- mHttpProxy = new ProxyProperties(source.getHttpProxy());
+ mHttpProxy = (source.getHttpProxy() == null) ?
+ null : new ProxyProperties(source.getHttpProxy());
}
}
diff --git a/core/java/android/net/MobileDataStateTracker.java b/core/java/android/net/MobileDataStateTracker.java
index bb6ee0f..770f152 100644
--- a/core/java/android/net/MobileDataStateTracker.java
+++ b/core/java/android/net/MobileDataStateTracker.java
@@ -276,6 +276,21 @@
setDetailedState(DetailedState.CONNECTED, reason, apnName);
break;
}
+ } else {
+ // There was no state change. Check if LinkProperties has been updated.
+ if (TextUtils.equals(reason, Phone.REASON_LINK_PROPERTIES_CHANGED)) {
+ mLinkProperties = intent.getParcelableExtra(Phone.DATA_LINK_PROPERTIES_KEY);
+ if (mLinkProperties == null) {
+ log("No link property in LINK_PROPERTIES change event.");
+ mLinkProperties = new LinkProperties();
+ }
+ // Just update reason field in this NetworkInfo
+ mNetworkInfo.setDetailedState(mNetworkInfo.getDetailedState(), reason,
+ mNetworkInfo.getExtraInfo());
+ Message msg = mTarget.obtainMessage(EVENT_CONFIGURATION_CHANGED,
+ mNetworkInfo);
+ msg.sendToTarget();
+ }
}
} else if (intent.getAction().
equals(TelephonyIntents.ACTION_DATA_CONNECTION_FAILED)) {
diff --git a/core/java/android/net/NetworkPolicyManager.java b/core/java/android/net/NetworkPolicyManager.java
new file mode 100644
index 0000000..2312bd9
--- /dev/null
+++ b/core/java/android/net/NetworkPolicyManager.java
@@ -0,0 +1,68 @@
+/*
+ * 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 android.net;
+
+import android.os.RemoteException;
+
+/**
+ * Manager for creating and modifying network policy rules.
+ *
+ * {@hide}
+ */
+public class NetworkPolicyManager {
+
+ /** No specific network policy, use system default. */
+ public static final int POLICY_NONE = 0x0;
+ /** Reject network usage when application in background. */
+ public static final int POLICY_REJECT_BACKGROUND = 0x1;
+ /** Reject network usage on paid network connections. */
+ public static final int POLICY_REJECT_PAID = 0x2;
+ /** Application should conserve data. */
+ public static final int POLICY_CONSERVE_DATA = 0x4;
+
+ private INetworkPolicyManager mService;
+
+ public NetworkPolicyManager(INetworkPolicyManager service) {
+ if (service == null) {
+ throw new IllegalArgumentException("missing INetworkPolicyManager");
+ }
+ mService = service;
+ }
+
+ /**
+ * Set policy flags for specific UID.
+ *
+ * @param policy {@link #POLICY_NONE} or combination of
+ * {@link #POLICY_REJECT_BACKGROUND}, {@link #POLICY_REJECT_PAID},
+ * or {@link #POLICY_CONSERVE_DATA}.
+ */
+ public void setUidPolicy(int uid, int policy) {
+ try {
+ mService.setUidPolicy(uid, policy);
+ } catch (RemoteException e) {
+ }
+ }
+
+ public int getUidPolicy(int uid) {
+ try {
+ return mService.getUidPolicy(uid);
+ } catch (RemoteException e) {
+ return POLICY_NONE;
+ }
+ }
+
+}
diff --git a/core/java/android/net/NetworkUtils.java b/core/java/android/net/NetworkUtils.java
index fbe5379..8a678d6 100644
--- a/core/java/android/net/NetworkUtils.java
+++ b/core/java/android/net/NetworkUtils.java
@@ -38,32 +38,6 @@
/** Bring the named network interface down. */
public native static int disableInterface(String interfaceName);
- /**
- * Add a route to the routing table.
- *
- * @param interfaceName the interface to route through.
- * @param dst the network or host to route to. May be IPv4 or IPv6, e.g.
- * "0.0.0.0" or "2001:4860::".
- * @param prefixLength the prefix length of the route.
- * @param gw the gateway to use, e.g., "192.168.251.1". If null,
- * indicates a directly-connected route.
- */
- public native static int addRoute(String interfaceName, String dst,
- int prefixLength, String gw);
-
- /** Return the gateway address for the default route for the named interface. */
- public static InetAddress getDefaultRoute(String interfaceName) {
- int addr = getDefaultRouteNative(interfaceName);
- return intToInetAddress(addr);
- }
- private native static int getDefaultRouteNative(String interfaceName);
-
- /** Remove host routes that uses the named interface. */
- public native static int removeHostRoutes(String interfaceName);
-
- /** Remove the default route for the named interface. */
- public native static int removeDefaultRoute(String interfaceName);
-
/** Reset any sockets that are connected via the named interface. */
public native static int resetConnections(String interfaceName);
@@ -160,6 +134,15 @@
}
/**
+ * Convert a IPv4 netmask integer to a prefix length
+ * @param netmask as an integer in network byte order
+ * @return the network prefix length
+ */
+ public static int netmaskIntToPrefixLength(int netmask) {
+ return Integer.bitCount(netmask);
+ }
+
+ /**
* Create an InetAddress from a string where the string must be a standard
* representation of a V4 or V6 address. Avoids doing a DNS lookup on failure
* but it will throw an IllegalArgumentException in that case.
@@ -173,60 +156,6 @@
}
/**
- * Add a default route through the specified gateway.
- * @param interfaceName interface on which the route should be added
- * @param gw the IP address of the gateway to which the route is desired,
- * @return {@code true} on success, {@code false} on failure
- */
- public static boolean addDefaultRoute(String interfaceName, InetAddress gw) {
- String dstStr;
- String gwStr = gw.getHostAddress();
-
- if (gw instanceof Inet4Address) {
- dstStr = "0.0.0.0";
- } else if (gw instanceof Inet6Address) {
- dstStr = "::";
- } else {
- Log.w(TAG, "addDefaultRoute failure: address is neither IPv4 nor IPv6" +
- "(" + gwStr + ")");
- return false;
- }
- return addRoute(interfaceName, dstStr, 0, gwStr) == 0;
- }
-
- /**
- * Add a host route.
- * @param interfaceName interface on which the route should be added
- * @param dst the IP address of the host to which the route is desired,
- * this should not be null.
- * @param gw the IP address of the gateway to which the route is desired,
- * if null, indicates a directly-connected route.
- * @return {@code true} on success, {@code false} on failure
- */
- public static boolean addHostRoute(String interfaceName, InetAddress dst,
- InetAddress gw) {
- if (dst == null) {
- Log.w(TAG, "addHostRoute: dst should not be null");
- return false;
- }
-
- int prefixLength;
- String dstStr = dst.getHostAddress();
- String gwStr = (gw != null) ? gw.getHostAddress() : null;
-
- if (dst instanceof Inet4Address) {
- prefixLength = 32;
- } else if (dst instanceof Inet6Address) {
- prefixLength = 128;
- } else {
- Log.w(TAG, "addHostRoute failure: address is neither IPv4 nor IPv6" +
- "(" + dst + ")");
- return false;
- }
- return addRoute(interfaceName, dstStr, prefixLength, gwStr) == 0;
- }
-
- /**
* Get InetAddress masked with prefixLength. Will never return null.
* @param IP address which will be masked with specified prefixLength
* @param prefixLength the prefixLength used to mask the IP
@@ -271,4 +200,25 @@
return (((left instanceof Inet4Address) && (right instanceof Inet4Address)) ||
((left instanceof Inet6Address) && (right instanceof Inet6Address)));
}
+
+ /**
+ * Convert a 32 char hex string into a Inet6Address.
+ * throws a runtime exception if the string isn't 32 chars, isn't hex or can't be
+ * made into an Inet6Address
+ * @param addrHexString a 32 character hex string representing an IPv6 addr
+ * @return addr an InetAddress representation for the string
+ */
+ public static InetAddress hexToInet6Address(String addrHexString)
+ throws IllegalArgumentException {
+ try {
+ return numericToInetAddress(String.format("%s:%s:%s:%s:%s:%s:%s:%s",
+ addrHexString.substring(0,4), addrHexString.substring(4,8),
+ addrHexString.substring(8,12), addrHexString.substring(12,16),
+ addrHexString.substring(16,20), addrHexString.substring(20,24),
+ addrHexString.substring(24,28), addrHexString.substring(28,32)));
+ } catch (Exception e) {
+ Log.e("NetworkUtils", "error in hexToInet6Address(" + addrHexString + "): " + e);
+ throw new IllegalArgumentException(e);
+ }
+ }
}
diff --git a/core/java/android/net/RouteInfo.java b/core/java/android/net/RouteInfo.java
index 39e708a..8e5ddda 100644
--- a/core/java/android/net/RouteInfo.java
+++ b/core/java/android/net/RouteInfo.java
@@ -46,18 +46,16 @@
public RouteInfo(LinkAddress destination, InetAddress gateway) {
if (destination == null) {
- try {
- if (gateway != null) {
- if (gateway instanceof Inet4Address) {
- destination = new LinkAddress(Inet4Address.ANY, 0);
- } else {
- destination = new LinkAddress(Inet6Address.ANY, 0);
- }
+ if (gateway != null) {
+ if (gateway instanceof Inet4Address) {
+ destination = new LinkAddress(Inet4Address.ANY, 0);
} else {
- // no destination, no gateway. invalid.
- throw new RuntimeException("Invalid arguments passed in.");
+ destination = new LinkAddress(Inet6Address.ANY, 0);
}
- } catch (Exception e) {}
+ } else {
+ // no destination, no gateway. invalid.
+ throw new RuntimeException("Invalid arguments passed in.");
+ }
}
if (gateway == null) {
if (destination.getAddress() instanceof Inet4Address) {
@@ -76,6 +74,20 @@
this(null, gateway);
}
+ public static RouteInfo makeHostRoute(InetAddress host) {
+ return makeHostRoute(host, null);
+ }
+
+ public static RouteInfo makeHostRoute(InetAddress host, InetAddress gateway) {
+ if (host == null) return null;
+
+ if (host instanceof Inet4Address) {
+ return new RouteInfo(new LinkAddress(host, 32), gateway);
+ } else {
+ return new RouteInfo(new LinkAddress(host, 128), gateway);
+ }
+ }
+
private boolean isDefault() {
boolean val = false;
if (mGateway != null) {
@@ -128,6 +140,33 @@
}
}
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) return true;
+
+ if (!(obj instanceof RouteInfo)) return false;
+
+ RouteInfo target = (RouteInfo) obj;
+
+ boolean sameDestination = ( mDestination == null) ?
+ target.getDestination() == null
+ : mDestination.equals(target.getDestination());
+
+ boolean sameAddress = (mGateway == null) ?
+ target.getGateway() == null
+ : mGateway.equals(target.getGateway());
+
+ return sameDestination && sameAddress
+ && mIsDefault == target.mIsDefault;
+ }
+
+ @Override
+ public int hashCode() {
+ return (mDestination == null ? 0 : mDestination.hashCode())
+ + (mGateway == null ? 0 :mGateway.hashCode())
+ + (mIsDefault ? 3 : 7);
+ }
+
public static final Creator<RouteInfo> CREATOR =
new Creator<RouteInfo>() {
public RouteInfo createFromParcel(Parcel in) {
diff --git a/core/java/android/os/INetworkManagementService.aidl b/core/java/android/os/INetworkManagementService.aidl
index fe36786..ecc111b 100644
--- a/core/java/android/os/INetworkManagementService.aidl
+++ b/core/java/android/os/INetworkManagementService.aidl
@@ -20,6 +20,7 @@
import android.net.InterfaceConfiguration;
import android.net.INetworkManagementEventObserver;
import android.net.NetworkStats;
+import android.net.RouteInfo;
import android.net.wifi.WifiConfiguration;
/**
@@ -58,6 +59,22 @@
void setInterfaceConfig(String iface, in InterfaceConfiguration cfg);
/**
+ * Retrieves the network routes currently configured on the specified
+ * interface
+ */
+ RouteInfo[] getRoutes(String iface);
+
+ /**
+ * Add the specified route to the interface.
+ */
+ void addRoute(String iface, in RouteInfo route);
+
+ /**
+ * Remove the specified route from the interface.
+ */
+ void removeRoute(String iface, in RouteInfo route);
+
+ /**
* Shuts down the service
*/
void shutdown();
diff --git a/core/java/android/os/storage/StorageVolume.java b/core/java/android/os/storage/StorageVolume.java
index d79f6c8..d68e6fb 100644
--- a/core/java/android/os/storage/StorageVolume.java
+++ b/core/java/android/os/storage/StorageVolume.java
@@ -34,10 +34,10 @@
private final boolean mRemovable;
private final boolean mEmulated;
private final int mMtpReserveSpace;
+ private int mStorageId;
public StorageVolume(String path, String description,
- boolean removable, boolean emulated,
- int mtpReserveSpace) {
+ boolean removable, boolean emulated, int mtpReserveSpace) {
mPath = path;
mDescription = description;
mRemovable = removable;
@@ -45,6 +45,17 @@
mMtpReserveSpace = mtpReserveSpace;
}
+ // for parcelling only
+ private StorageVolume(String path, String description,
+ boolean removable, boolean emulated, int mtpReserveSpace, int storageId) {
+ mPath = path;
+ mDescription = description;
+ mRemovable = removable;
+ mEmulated = emulated;
+ mMtpReserveSpace = mtpReserveSpace;
+ mStorageId = storageId;
+ }
+
/**
* Returns the mount path for the volume.
*
@@ -82,6 +93,25 @@
}
/**
+ * Returns the MTP storage ID for the volume.
+ * this is also used for the storage_id column in the media provider.
+ *
+ * @return MTP storage ID
+ */
+ public int getStorageId() {
+ return mStorageId;
+ }
+
+ /**
+ * Do not call this unless you are MountService
+ */
+ public void setStorageId(int index) {
+ // storage ID is 0x00010001 for primary storage,
+ // then 0x00020001, 0x00030001, etc. for secondary storages
+ mStorageId = ((index + 1) << 16) + 1;
+ }
+
+ /**
* Number of megabytes of space to leave unallocated by MTP.
* MTP will subtract this value from the free space it reports back
* to the host via GetStorageInfo, and will not allow new files to
@@ -123,9 +153,11 @@
String description = in.readString();
int removable = in.readInt();
int emulated = in.readInt();
+ int storageId = in.readInt();
int mtpReserveSpace = in.readInt();
return new StorageVolume(path, description,
- removable == 1, emulated == 1, mtpReserveSpace);
+ removable == 1, emulated == 1,
+ mtpReserveSpace, storageId);
}
public StorageVolume[] newArray(int size) {
@@ -142,6 +174,7 @@
parcel.writeString(mDescription);
parcel.writeInt(mRemovable ? 1 : 0);
parcel.writeInt(mEmulated ? 1 : 0);
+ parcel.writeInt(mStorageId);
parcel.writeInt(mMtpReserveSpace);
}
}
diff --git a/core/java/android/server/BluetoothInputProfileHandler.java b/core/java/android/server/BluetoothInputProfileHandler.java
index e6513fd..247e297 100644
--- a/core/java/android/server/BluetoothInputProfileHandler.java
+++ b/core/java/android/server/BluetoothInputProfileHandler.java
@@ -60,7 +60,7 @@
return sInstance;
}
- synchronized boolean connectInputDevice(BluetoothDevice device,
+ boolean connectInputDevice(BluetoothDevice device,
BluetoothDeviceProfileState state) {
String objectPath = mBluetoothService.getObjectPathFromAddress(device.getAddress());
if (objectPath == null ||
@@ -78,7 +78,7 @@
return false;
}
- synchronized boolean connectInputDeviceInternal(BluetoothDevice device) {
+ boolean connectInputDeviceInternal(BluetoothDevice device) {
String objectPath = mBluetoothService.getObjectPathFromAddress(device.getAddress());
handleInputDeviceStateChange(device, BluetoothInputDevice.STATE_CONNECTING);
if (!mBluetoothService.connectInputDeviceNative(objectPath)) {
@@ -88,7 +88,7 @@
return true;
}
- synchronized boolean disconnectInputDevice(BluetoothDevice device,
+ boolean disconnectInputDevice(BluetoothDevice device,
BluetoothDeviceProfileState state) {
String objectPath = mBluetoothService.getObjectPathFromAddress(device.getAddress());
if (objectPath == null ||
@@ -105,7 +105,7 @@
return false;
}
- synchronized boolean disconnectInputDeviceInternal(BluetoothDevice device) {
+ boolean disconnectInputDeviceInternal(BluetoothDevice device) {
String objectPath = mBluetoothService.getObjectPathFromAddress(device.getAddress());
handleInputDeviceStateChange(device, BluetoothInputDevice.STATE_DISCONNECTING);
if (!mBluetoothService.disconnectInputDeviceNative(objectPath)) {
@@ -115,31 +115,31 @@
return true;
}
- synchronized int getInputDeviceConnectionState(BluetoothDevice device) {
+ int getInputDeviceConnectionState(BluetoothDevice device) {
if (mInputDevices.get(device) == null) {
return BluetoothInputDevice.STATE_DISCONNECTED;
}
return mInputDevices.get(device);
}
- synchronized List<BluetoothDevice> getConnectedInputDevices() {
+ List<BluetoothDevice> getConnectedInputDevices() {
List<BluetoothDevice> devices = lookupInputDevicesMatchingStates(
new int[] {BluetoothInputDevice.STATE_CONNECTED});
return devices;
}
- synchronized List<BluetoothDevice> getInputDevicesMatchingConnectionStates(int[] states) {
+ List<BluetoothDevice> getInputDevicesMatchingConnectionStates(int[] states) {
List<BluetoothDevice> devices = lookupInputDevicesMatchingStates(states);
return devices;
}
- synchronized int getInputDevicePriority(BluetoothDevice device) {
+ int getInputDevicePriority(BluetoothDevice device) {
return Settings.Secure.getInt(mContext.getContentResolver(),
Settings.Secure.getBluetoothInputDevicePriorityKey(device.getAddress()),
BluetoothInputDevice.PRIORITY_UNDEFINED);
}
- synchronized boolean setInputDevicePriority(BluetoothDevice device, int priority) {
+ boolean setInputDevicePriority(BluetoothDevice device, int priority) {
if (!BluetoothAdapter.checkBluetoothAddress(device.getAddress())) {
return false;
}
@@ -148,7 +148,7 @@
priority);
}
- synchronized List<BluetoothDevice> lookupInputDevicesMatchingStates(int[] states) {
+ List<BluetoothDevice> lookupInputDevicesMatchingStates(int[] states) {
List<BluetoothDevice> inputDevices = new ArrayList<BluetoothDevice>();
for (BluetoothDevice device: mInputDevices.keySet()) {
@@ -163,7 +163,7 @@
return inputDevices;
}
- private synchronized void handleInputDeviceStateChange(BluetoothDevice device, int state) {
+ private void handleInputDeviceStateChange(BluetoothDevice device, int state) {
int prevState;
if (mInputDevices.get(device) == null) {
prevState = BluetoothInputDevice.STATE_DISCONNECTED;
@@ -194,7 +194,7 @@
mBluetoothService.sendConnectionStateChange(device, state, prevState);
}
- synchronized void handleInputDevicePropertyChange(String address, boolean connected) {
+ void handleInputDevicePropertyChange(String address, boolean connected) {
int state = connected ? BluetoothInputDevice.STATE_CONNECTED :
BluetoothInputDevice.STATE_DISCONNECTED;
BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
@@ -202,7 +202,7 @@
handleInputDeviceStateChange(device, state);
}
- synchronized void setInitialInputDevicePriority(BluetoothDevice device, int state) {
+ void setInitialInputDevicePriority(BluetoothDevice device, int state) {
switch (state) {
case BluetoothDevice.BOND_BONDED:
if (getInputDevicePriority(device) == BluetoothInputDevice.PRIORITY_UNDEFINED) {
diff --git a/core/java/android/server/BluetoothPanProfileHandler.java b/core/java/android/server/BluetoothPanProfileHandler.java
index 8925856..0d63e19 100644
--- a/core/java/android/server/BluetoothPanProfileHandler.java
+++ b/core/java/android/server/BluetoothPanProfileHandler.java
@@ -76,17 +76,17 @@
}
}
- static synchronized BluetoothPanProfileHandler getInstance(Context context,
+ static BluetoothPanProfileHandler getInstance(Context context,
BluetoothService service) {
if (sInstance == null) sInstance = new BluetoothPanProfileHandler(context, service);
return sInstance;
}
- synchronized boolean isTetheringOn() {
+ boolean isTetheringOn() {
return mTetheringOn;
}
- synchronized boolean allowIncomingTethering() {
+ boolean allowIncomingTethering() {
if (isTetheringOn() && getConnectedPanDevices().size() < mMaxPanDevices)
return true;
return false;
@@ -94,7 +94,7 @@
private BroadcastReceiver mTetheringReceiver = null;
- synchronized void setBluetoothTethering(boolean value) {
+ void setBluetoothTethering(boolean value) {
if (!value) {
disconnectPanServerDevices();
}
@@ -104,7 +104,7 @@
filter.addAction(BluetoothAdapter.ACTION_STATE_CHANGED);
mTetheringReceiver = new BroadcastReceiver() {
@Override
- public synchronized void onReceive(Context context, Intent intent) {
+ public void onReceive(Context context, Intent intent) {
if (intent.getIntExtra(BluetoothAdapter.EXTRA_STATE, BluetoothAdapter.STATE_OFF)
== BluetoothAdapter.STATE_ON) {
mTetheringOn = true;
@@ -118,7 +118,7 @@
}
}
- synchronized int getPanDeviceConnectionState(BluetoothDevice device) {
+ int getPanDeviceConnectionState(BluetoothDevice device) {
BluetoothPanDevice panDevice = mPanDevices.get(device);
if (panDevice == null) {
return BluetoothPan.STATE_DISCONNECTED;
@@ -126,7 +126,7 @@
return panDevice.mState;
}
- synchronized boolean connectPanDevice(BluetoothDevice device) {
+ boolean connectPanDevice(BluetoothDevice device) {
String objectPath = mBluetoothService.getObjectPathFromAddress(device.getAddress());
if (DBG) Log.d(TAG, "connect PAN(" + objectPath + ")");
if (getPanDeviceConnectionState(device) != BluetoothPan.STATE_DISCONNECTED) {
@@ -158,7 +158,7 @@
}
}
- private synchronized boolean disconnectPanServerDevices() {
+ private boolean disconnectPanServerDevices() {
debugLog("disconnect all PAN devices");
for (BluetoothDevice device: mPanDevices.keySet()) {
@@ -187,7 +187,7 @@
return true;
}
- synchronized List<BluetoothDevice> getConnectedPanDevices() {
+ List<BluetoothDevice> getConnectedPanDevices() {
List<BluetoothDevice> devices = new ArrayList<BluetoothDevice>();
for (BluetoothDevice device: mPanDevices.keySet()) {
@@ -198,7 +198,7 @@
return devices;
}
- synchronized List<BluetoothDevice> getPanDevicesMatchingConnectionStates(int[] states) {
+ List<BluetoothDevice> getPanDevicesMatchingConnectionStates(int[] states) {
List<BluetoothDevice> devices = new ArrayList<BluetoothDevice>();
for (BluetoothDevice device: mPanDevices.keySet()) {
@@ -213,7 +213,7 @@
return devices;
}
- synchronized boolean disconnectPanDevice(BluetoothDevice device) {
+ boolean disconnectPanDevice(BluetoothDevice device) {
String objectPath = mBluetoothService.getObjectPathFromAddress(device.getAddress());
debugLog("disconnect PAN(" + objectPath + ")");
@@ -249,7 +249,7 @@
return true;
}
- synchronized void handlePanDeviceStateChange(BluetoothDevice device,
+ void handlePanDeviceStateChange(BluetoothDevice device,
String iface, int state, int role) {
int prevState;
String ifaceAddr = null;
@@ -304,7 +304,7 @@
mBluetoothService.sendConnectionStateChange(device, state, prevState);
}
- synchronized void handlePanDeviceStateChange(BluetoothDevice device,
+ void handlePanDeviceStateChange(BluetoothDevice device,
int state, int role) {
handlePanDeviceStateChange(device, null, state, role);
}
@@ -343,7 +343,7 @@
}
// configured when we start tethering
- private synchronized String enableTethering(String iface) {
+ private String enableTethering(String iface) {
debugLog("updateTetherState:" + iface);
IBinder b = ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE);
diff --git a/core/java/android/server/BluetoothService.java b/core/java/android/server/BluetoothService.java
index f98d275..2c79385 100644
--- a/core/java/android/server/BluetoothService.java
+++ b/core/java/android/server/BluetoothService.java
@@ -1928,120 +1928,163 @@
}
/**** Handlers for PAN Profile ****/
+ // TODO: This needs to be converted to a state machine.
- public synchronized boolean isTetheringOn() {
+ public boolean isTetheringOn() {
mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
- return mBluetoothPanProfileHandler.isTetheringOn();
+ synchronized (mBluetoothPanProfileHandler) {
+ return mBluetoothPanProfileHandler.isTetheringOn();
+ }
}
- /*package*/ synchronized boolean allowIncomingTethering() {
- return mBluetoothPanProfileHandler.allowIncomingTethering();
+ /*package*/boolean allowIncomingTethering() {
+ synchronized (mBluetoothPanProfileHandler) {
+ return mBluetoothPanProfileHandler.allowIncomingTethering();
+ }
}
- public synchronized void setBluetoothTethering(boolean value) {
+ public void setBluetoothTethering(boolean value) {
mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
- mBluetoothPanProfileHandler.setBluetoothTethering(value);
+ synchronized (mBluetoothPanProfileHandler) {
+ mBluetoothPanProfileHandler.setBluetoothTethering(value);
+ }
}
- public synchronized int getPanDeviceConnectionState(BluetoothDevice device) {
+ public int getPanDeviceConnectionState(BluetoothDevice device) {
mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
- return mBluetoothPanProfileHandler.getPanDeviceConnectionState(device);
+ synchronized (mBluetoothPanProfileHandler) {
+ return mBluetoothPanProfileHandler.getPanDeviceConnectionState(device);
+ }
}
- public synchronized boolean connectPanDevice(BluetoothDevice device) {
+ public boolean connectPanDevice(BluetoothDevice device) {
mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
"Need BLUETOOTH_ADMIN permission");
- return mBluetoothPanProfileHandler.connectPanDevice(device);
+ synchronized (mBluetoothPanProfileHandler) {
+ return mBluetoothPanProfileHandler.connectPanDevice(device);
+ }
}
- public synchronized List<BluetoothDevice> getConnectedPanDevices() {
+ public List<BluetoothDevice> getConnectedPanDevices() {
mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
- return mBluetoothPanProfileHandler.getConnectedPanDevices();
+ synchronized (mBluetoothPanProfileHandler) {
+ return mBluetoothPanProfileHandler.getConnectedPanDevices();
+ }
}
- public synchronized List<BluetoothDevice> getPanDevicesMatchingConnectionStates(
+ public List<BluetoothDevice> getPanDevicesMatchingConnectionStates(
int[] states) {
mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
- return mBluetoothPanProfileHandler.getPanDevicesMatchingConnectionStates(states);
+ synchronized (mBluetoothPanProfileHandler) {
+ return mBluetoothPanProfileHandler.getPanDevicesMatchingConnectionStates(states);
+ }
}
- public synchronized boolean disconnectPanDevice(BluetoothDevice device) {
+ public boolean disconnectPanDevice(BluetoothDevice device) {
mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
"Need BLUETOOTH_ADMIN permission");
- return mBluetoothPanProfileHandler.disconnectPanDevice(device);
+ synchronized (mBluetoothPanProfileHandler) {
+ return mBluetoothPanProfileHandler.disconnectPanDevice(device);
+ }
}
- /*package*/ synchronized void handlePanDeviceStateChange(BluetoothDevice device,
+ /*package*/void handlePanDeviceStateChange(BluetoothDevice device,
String iface,
int state,
int role) {
- mBluetoothPanProfileHandler.handlePanDeviceStateChange(device, iface, state, role);
+ synchronized (mBluetoothPanProfileHandler) {
+ mBluetoothPanProfileHandler.handlePanDeviceStateChange(device, iface, state, role);
+ }
}
- /*package*/ synchronized void handlePanDeviceStateChange(BluetoothDevice device,
+ /*package*/void handlePanDeviceStateChange(BluetoothDevice device,
int state, int role) {
- mBluetoothPanProfileHandler.handlePanDeviceStateChange(device, null, state, role);
+ synchronized (mBluetoothPanProfileHandler) {
+ mBluetoothPanProfileHandler.handlePanDeviceStateChange(device, null, state, role);
+ }
}
/**** Handlers for Input Device Profile ****/
+ // This needs to be converted to state machine
- public synchronized boolean connectInputDevice(BluetoothDevice device) {
+ public boolean connectInputDevice(BluetoothDevice device) {
mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
"Need BLUETOOTH_ADMIN permission");
BluetoothDeviceProfileState state = mDeviceProfileState.get(device.getAddress());
- return mBluetoothInputProfileHandler.connectInputDevice(device, state);
+ synchronized (mBluetoothInputProfileHandler) {
+ return mBluetoothInputProfileHandler.connectInputDevice(device, state);
+ }
}
- public synchronized boolean connectInputDeviceInternal(BluetoothDevice device) {
- return mBluetoothInputProfileHandler.connectInputDeviceInternal(device);
+ public boolean connectInputDeviceInternal(BluetoothDevice device) {
+ synchronized (mBluetoothInputProfileHandler) {
+ return mBluetoothInputProfileHandler.connectInputDeviceInternal(device);
+ }
}
- public synchronized boolean disconnectInputDevice(BluetoothDevice device) {
+ public boolean disconnectInputDevice(BluetoothDevice device) {
mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
"Need BLUETOOTH_ADMIN permission");
BluetoothDeviceProfileState state = mDeviceProfileState.get(device.getAddress());
- return mBluetoothInputProfileHandler.disconnectInputDevice(device, state);
+ synchronized (mBluetoothInputProfileHandler) {
+ return mBluetoothInputProfileHandler.disconnectInputDevice(device, state);
+ }
}
- public synchronized boolean disconnectInputDeviceInternal(BluetoothDevice device) {
- return mBluetoothInputProfileHandler.disconnectInputDeviceInternal(device);
+ public boolean disconnectInputDeviceInternal(BluetoothDevice device) {
+ synchronized (mBluetoothInputProfileHandler) {
+ return mBluetoothInputProfileHandler.disconnectInputDeviceInternal(device);
+ }
}
- public synchronized int getInputDeviceConnectionState(BluetoothDevice device) {
+ public int getInputDeviceConnectionState(BluetoothDevice device) {
mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
- return mBluetoothInputProfileHandler.getInputDeviceConnectionState(device);
-
+ synchronized (mBluetoothInputProfileHandler) {
+ return mBluetoothInputProfileHandler.getInputDeviceConnectionState(device);
+ }
}
- public synchronized List<BluetoothDevice> getConnectedInputDevices() {
+ public List<BluetoothDevice> getConnectedInputDevices() {
mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
- return mBluetoothInputProfileHandler.getConnectedInputDevices();
+ synchronized (mBluetoothInputProfileHandler) {
+ return mBluetoothInputProfileHandler.getConnectedInputDevices();
+ }
}
- public synchronized List<BluetoothDevice> getInputDevicesMatchingConnectionStates(
+ public List<BluetoothDevice> getInputDevicesMatchingConnectionStates(
int[] states) {
mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
- return mBluetoothInputProfileHandler.getInputDevicesMatchingConnectionStates(states);
+ synchronized (mBluetoothInputProfileHandler) {
+ return mBluetoothInputProfileHandler.getInputDevicesMatchingConnectionStates(states);
+ }
}
- public synchronized int getInputDevicePriority(BluetoothDevice device) {
+ public int getInputDevicePriority(BluetoothDevice device) {
mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
- return mBluetoothInputProfileHandler.getInputDevicePriority(device);
+ synchronized (mBluetoothInputProfileHandler) {
+ return mBluetoothInputProfileHandler.getInputDevicePriority(device);
+ }
}
- public synchronized boolean setInputDevicePriority(BluetoothDevice device, int priority) {
+ public boolean setInputDevicePriority(BluetoothDevice device, int priority) {
mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
"Need BLUETOOTH_ADMIN permission");
- return mBluetoothInputProfileHandler.setInputDevicePriority(device, priority);
+ synchronized (mBluetoothInputProfileHandler) {
+ return mBluetoothInputProfileHandler.setInputDevicePriority(device, priority);
+ }
}
- /*package*/synchronized List<BluetoothDevice> lookupInputDevicesMatchingStates(int[] states) {
- return mBluetoothInputProfileHandler.lookupInputDevicesMatchingStates(states);
+ /*package*/List<BluetoothDevice> lookupInputDevicesMatchingStates(int[] states) {
+ synchronized (mBluetoothInputProfileHandler) {
+ return mBluetoothInputProfileHandler.lookupInputDevicesMatchingStates(states);
+ }
}
- /*package*/ synchronized void handleInputDevicePropertyChange(String address, boolean connected) {
- mBluetoothInputProfileHandler.handleInputDevicePropertyChange(address, connected);
+ /*package*/void handleInputDevicePropertyChange(String address, boolean connected) {
+ synchronized (mBluetoothInputProfileHandler) {
+ mBluetoothInputProfileHandler.handleInputDevicePropertyChange(address, connected);
+ }
}
public boolean connectHeadset(String address) {
diff --git a/core/java/android/speech/tts/FileSynthesisRequest.java b/core/java/android/speech/tts/FileSynthesisRequest.java
index 7efc264..62be2bf 100644
--- a/core/java/android/speech/tts/FileSynthesisRequest.java
+++ b/core/java/android/speech/tts/FileSynthesisRequest.java
@@ -16,6 +16,7 @@
package android.speech.tts;
import android.media.AudioFormat;
+import android.os.Bundle;
import android.util.Log;
import java.io.File;
@@ -47,8 +48,8 @@
private boolean mStopped = false;
private boolean mDone = false;
- FileSynthesisRequest(String text, File fileName) {
- super(text);
+ FileSynthesisRequest(String text, Bundle params, File fileName) {
+ super(text, params);
mFileName = fileName;
}
diff --git a/core/java/android/speech/tts/PlaybackSynthesisRequest.java b/core/java/android/speech/tts/PlaybackSynthesisRequest.java
index dc5ff70..6f4c15b 100644
--- a/core/java/android/speech/tts/PlaybackSynthesisRequest.java
+++ b/core/java/android/speech/tts/PlaybackSynthesisRequest.java
@@ -17,6 +17,7 @@
import android.media.AudioFormat;
import android.media.AudioTrack;
+import android.os.Bundle;
import android.util.Log;
/**
@@ -52,8 +53,9 @@
private boolean mStopped = false;
private boolean mDone = false;
- PlaybackSynthesisRequest(String text, int streamType, float volume, float pan) {
- super(text);
+ PlaybackSynthesisRequest(String text, Bundle params,
+ int streamType, float volume, float pan) {
+ super(text, params);
mStreamType = streamType;
mVolume = volume;
mPan = pan;
diff --git a/core/java/android/speech/tts/SynthesisRequest.java b/core/java/android/speech/tts/SynthesisRequest.java
index 6df9af2..57ae10d 100644
--- a/core/java/android/speech/tts/SynthesisRequest.java
+++ b/core/java/android/speech/tts/SynthesisRequest.java
@@ -15,6 +15,8 @@
*/
package android.speech.tts;
+import android.os.Bundle;
+
/**
* A request for speech synthesis given to a TTS engine for processing.
*
@@ -28,14 +30,16 @@
public abstract class SynthesisRequest {
private final String mText;
+ private final Bundle mParams;
private String mLanguage;
private String mCountry;
private String mVariant;
private int mSpeechRate;
private int mPitch;
- public SynthesisRequest(String text) {
+ public SynthesisRequest(String text, Bundle params) {
mText = text;
+ mParams = new Bundle(params);
}
/**
@@ -104,6 +108,13 @@
}
/**
+ * Gets the additional params, if any.
+ */
+ public Bundle getParams() {
+ return mParams;
+ }
+
+ /**
* Gets the maximum number of bytes that the TTS engine can pass in a single call of
* {@link #audioAvailable}. This does not apply to {@link #completeAudioAvailable}.
*/
diff --git a/core/java/android/speech/tts/TextToSpeech.java b/core/java/android/speech/tts/TextToSpeech.java
index 1d26c22..4b19469 100755
--- a/core/java/android/speech/tts/TextToSpeech.java
+++ b/core/java/android/speech/tts/TextToSpeech.java
@@ -80,13 +80,13 @@
public static final int LANG_COUNTRY_VAR_AVAILABLE = 2;
/**
- * Denotes the language is available for the language and country specified
+ * Denotes the language is available for the language and country specified
* by the locale, but not the variant.
*/
public static final int LANG_COUNTRY_AVAILABLE = 1;
/**
- * Denotes the language is available for the language by the locale,
+ * Denotes the language is available for the language by the locale,
* but not the country and variant.
*/
public static final int LANG_AVAILABLE = 0;
@@ -424,6 +424,7 @@
private final Map<String, Uri> mEarcons;
private final Map<String, Uri> mUtterances;
private final Bundle mParams = new Bundle();
+ private String mCurrentEngine = null;
/**
* The constructor for the TextToSpeech class, using the default TTS engine.
@@ -524,6 +525,7 @@
dispatchOnInit(ERROR);
return false;
} else {
+ mCurrentEngine = engine;
return true;
}
}
@@ -685,6 +687,10 @@
* {@link Engine#KEY_PARAM_UTTERANCE_ID},
* {@link Engine#KEY_PARAM_VOLUME},
* {@link Engine#KEY_PARAM_PAN}.
+ * Engine specific parameters may be passed in but the parameter keys
+ * must be prefixed by the name of the engine they are intended for. For example
+ * the keys "com.svox.pico_foo" and "com.svox.pico:bar" will be passed to the
+ * engine named "com.svox.pico" if it is being used.
*
* @return {@link #ERROR} or {@link #SUCCESS}.
*/
@@ -714,6 +720,10 @@
* Supported parameter names:
* {@link Engine#KEY_PARAM_STREAM},
* {@link Engine#KEY_PARAM_UTTERANCE_ID}.
+ * Engine specific parameters may be passed in but the parameter keys
+ * must be prefixed by the name of the engine they are intended for. For example
+ * the keys "com.svox.pico_foo" and "com.svox.pico:bar" will be passed to the
+ * engine named "com.svox.pico" if it is being used.
*
* @return {@link #ERROR} or {@link #SUCCESS}.
*/
@@ -741,6 +751,10 @@
* @param params Parameters for the request. Can be null.
* Supported parameter names:
* {@link Engine#KEY_PARAM_UTTERANCE_ID}.
+ * Engine specific parameters may be passed in but the parameter keys
+ * must be prefixed by the name of the engine they are intended for. For example
+ * the keys "com.svox.pico_foo" and "com.svox.pico:bar" will be passed to the
+ * engine named "com.svox.pico" if it is being used.
*
* @return {@link #ERROR} or {@link #SUCCESS}.
*/
@@ -922,6 +936,10 @@
* @param params Parameters for the request. Can be null.
* Supported parameter names:
* {@link Engine#KEY_PARAM_UTTERANCE_ID}.
+ * Engine specific parameters may be passed in but the parameter keys
+ * must be prefixed by the name of the engine they are intended for. For example
+ * the keys "com.svox.pico_foo" and "com.svox.pico:bar" will be passed to the
+ * engine named "com.svox.pico" if it is being used.
* @param filename Absolute file filename to write the generated audio data to.It should be
* something like "/sdcard/myappsounds/mysound.wav".
*
@@ -945,6 +963,19 @@
copyStringParam(bundle, params, Engine.KEY_PARAM_UTTERANCE_ID);
copyFloatParam(bundle, params, Engine.KEY_PARAM_VOLUME);
copyFloatParam(bundle, params, Engine.KEY_PARAM_PAN);
+
+ // Copy over all parameters that start with the name of the
+ // engine that we are currently connected to. The engine is
+ // free to interpret them as it chooses.
+ if (!TextUtils.isEmpty(mCurrentEngine)) {
+ for (Map.Entry<String, String> entry : params.entrySet()) {
+ final String key = entry.getKey();
+ if (key != null && key.startsWith(mCurrentEngine)) {
+ bundle.putString(key, entry.getValue());
+ }
+ }
+ }
+
return bundle;
} else {
return mParams;
diff --git a/core/java/android/speech/tts/TextToSpeechService.java b/core/java/android/speech/tts/TextToSpeechService.java
index 590e2ef..f32474f 100644
--- a/core/java/android/speech/tts/TextToSpeechService.java
+++ b/core/java/android/speech/tts/TextToSpeechService.java
@@ -318,7 +318,7 @@
*/
private static abstract class SpeechItem {
private final String mCallingApp;
- private final Bundle mParams;
+ protected final Bundle mParams;
private boolean mStarted = false;
private boolean mStopped = false;
@@ -443,7 +443,8 @@
}
protected SynthesisRequest createSynthesisRequest() {
- return new PlaybackSynthesisRequest(mText, getStreamType(), getVolume(), getPan());
+ return new PlaybackSynthesisRequest(mText, mParams,
+ getStreamType(), getVolume(), getPan());
}
private void setRequestParams(SynthesisRequest request) {
@@ -513,7 +514,7 @@
@Override
protected SynthesisRequest createSynthesisRequest() {
- return new FileSynthesisRequest(getText(), mFile);
+ return new FileSynthesisRequest(getText(), mParams, mFile);
}
/**
diff --git a/core/java/android/view/IWindowManager.aidl b/core/java/android/view/IWindowManager.aidl
index 0be02a6..adafb59 100644
--- a/core/java/android/view/IWindowManager.aidl
+++ b/core/java/android/view/IWindowManager.aidl
@@ -56,6 +56,9 @@
void getDisplaySize(out Point size);
int getMaximumSizeDimension();
+ void setForcedDisplaySize(int longDimen, int shortDimen);
+ void clearForcedDisplaySize();
+
// These can only be called when injecting events to your own window,
// or by holding the INJECT_EVENTS permission. These methods may block
// until pending input events are finished being dispatched even when 'sync' is false.
diff --git a/core/java/android/view/LayoutInflater.java b/core/java/android/view/LayoutInflater.java
index 81346b4..332a0fa 100644
--- a/core/java/android/view/LayoutInflater.java
+++ b/core/java/android/view/LayoutInflater.java
@@ -16,6 +16,10 @@
package android.view;
+import android.graphics.Canvas;
+import android.os.Handler;
+import android.os.Message;
+import android.widget.FrameLayout;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
@@ -83,6 +87,7 @@
private static final String TAG_MERGE = "merge";
private static final String TAG_INCLUDE = "include";
+ private static final String TAG_1995 = "blink";
private static final String TAG_REQUEST_FOCUS = "requestFocus";
/**
@@ -454,7 +459,12 @@
rInflate(parser, root, attrs, false);
} else {
// Temp is the root view that was found in the xml
- View temp = createViewFromTag(root, name, attrs);
+ View temp;
+ if (TAG_1995.equals(name)) {
+ temp = new BlinkLayout(mContext, attrs);
+ } else {
+ temp = createViewFromTag(root, name, attrs);
+ }
ViewGroup.LayoutParams params = null;
@@ -605,10 +615,9 @@
* Throw an exception because the specified class is not allowed to be inflated.
*/
private void failNotAllowed(String name, String prefix, AttributeSet attrs) {
- InflateException ie = new InflateException(attrs.getPositionDescription()
+ throw new InflateException(attrs.getPositionDescription()
+ ": Class not allowed to be inflated "
+ (prefix != null ? (prefix + name) : name));
- throw ie;
}
/**
@@ -720,6 +729,12 @@
parseInclude(parser, parent, attrs);
} else if (TAG_MERGE.equals(name)) {
throw new InflateException("<merge /> must be the root element");
+ } else if (TAG_1995.equals(name)) {
+ final View view = new BlinkLayout(mContext, attrs);
+ final ViewGroup viewGroup = (ViewGroup) parent;
+ final ViewGroup.LayoutParams params = viewGroup.generateLayoutParams(attrs);
+ rInflate(parser, view, attrs, true);
+ viewGroup.addView(view, params);
} else {
final View view = createViewFromTag(parent, name, attrs);
final ViewGroup viewGroup = (ViewGroup) parent;
@@ -847,5 +862,64 @@
parser.getDepth() > currentDepth) && type != XmlPullParser.END_DOCUMENT) {
// Empty
}
- }
+ }
+
+ private static class BlinkLayout extends FrameLayout {
+ private static final int MESSAGE_BLINK = 0x42;
+ private static final int BLINK_DELAY = 500;
+
+ private boolean mBlink;
+ private boolean mBlinkState;
+ private final Handler mHandler;
+
+ public BlinkLayout(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ mHandler = new Handler(new Handler.Callback() {
+ @Override
+ public boolean handleMessage(Message msg) {
+ if (msg.what == MESSAGE_BLINK) {
+ if (mBlink) {
+ mBlinkState = !mBlinkState;
+ makeBlink();
+ }
+ invalidate();
+ return true;
+ }
+ return false;
+ }
+ });
+ }
+
+ private void makeBlink() {
+ Message message = mHandler.obtainMessage(MESSAGE_BLINK);
+ mHandler.sendMessageDelayed(message, BLINK_DELAY);
+ }
+
+ @Override
+ protected void onAttachedToWindow() {
+ super.onAttachedToWindow();
+
+ mBlink = true;
+ mBlinkState = true;
+
+ makeBlink();
+ }
+
+ @Override
+ protected void onDetachedFromWindow() {
+ super.onDetachedFromWindow();
+
+ mBlink = false;
+ mBlinkState = true;
+
+ mHandler.removeMessages(MESSAGE_BLINK);
+ }
+
+ @Override
+ protected void dispatchDraw(Canvas canvas) {
+ if (mBlinkState) {
+ super.dispatchDraw(canvas);
+ }
+ }
+ }
}
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index ecb6bbb..d5f573c 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -49,8 +49,6 @@
import android.os.Parcelable;
import android.os.RemoteException;
import android.os.SystemClock;
-import android.os.SystemProperties;
-import android.text.format.DateUtils;
import android.util.AttributeSet;
import android.util.Log;
import android.util.Pool;
@@ -1709,6 +1707,13 @@
*/
static final int DRAG_HOVERED = 0x00000002;
+ /**
+ * Indicates whether the view is drawn in right-to-left direction.
+ *
+ * @hide
+ */
+ static final int RESOLVED_LAYOUT_RTL = 0x00000004;
+
/* End of masks for mPrivateFlags2 */
static final int DRAG_MASK = DRAG_CAN_ACCEPT | DRAG_HOVERED;
@@ -8488,6 +8493,23 @@
mPrivateFlags &= ~AWAKEN_SCROLL_BARS_ON_ATTACH;
}
jumpDrawablesToCurrentState();
+
+ // We are supposing here that the parent directionality will be resolved before its children
+ // View horizontalDirection public attribute resolution to an internal var.
+ // Resolving the layout direction. LTR is set initially.
+ mPrivateFlags2 &= ~RESOLVED_LAYOUT_RTL;
+ switch (getHorizontalDirection()) {
+ case HORIZONTAL_DIRECTION_INHERIT:
+ // If this is root view, no need to look at parent's layout dir.
+ if (mParent != null && mParent instanceof ViewGroup &&
+ ((ViewGroup) mParent).isLayoutRtl()) {
+ mPrivateFlags2 |= RESOLVED_LAYOUT_RTL;
+ }
+ break;
+ case HORIZONTAL_DIRECTION_RTL:
+ mPrivateFlags2 |= RESOLVED_LAYOUT_RTL;
+ break;
+ }
}
/**
@@ -8876,6 +8898,12 @@
// Destroy any previous software drawing cache if needed
switch (mLayerType) {
+ case LAYER_TYPE_HARDWARE:
+ if (mHardwareLayer != null) {
+ mHardwareLayer.destroy();
+ mHardwareLayer = null;
+ }
+ // fall through - unaccelerated views may use software layer mechanism instead
case LAYER_TYPE_SOFTWARE:
if (mDrawingCache != null) {
mDrawingCache.recycle();
@@ -8887,12 +8915,6 @@
mUnscaledDrawingCache = null;
}
break;
- case LAYER_TYPE_HARDWARE:
- if (mHardwareLayer != null) {
- mHardwareLayer.destroy();
- mHardwareLayer = null;
- }
- break;
default:
break;
}
@@ -9975,6 +9997,16 @@
}
/**
+ * <p>Indicates whether or not this view's layout is right-to-left. This is resolved from
+ * layout attribute and/or the inherited value from the parent.</p>
+ *
+ * @return true if the layout is right-to-left.
+ */
+ public boolean isLayoutRtl() {
+ return (mPrivateFlags2 & RESOLVED_LAYOUT_RTL) == RESOLVED_LAYOUT_RTL;
+ }
+
+ /**
* Assign a size and position to a view and all of its
* descendants
*
diff --git a/core/java/android/view/ViewDebug.java b/core/java/android/view/ViewDebug.java
index 1534099..4aa8727 100644
--- a/core/java/android/view/ViewDebug.java
+++ b/core/java/android/view/ViewDebug.java
@@ -92,21 +92,6 @@
public static final boolean TRACE_RECYCLER = false;
/**
- * Enables or disables motion events tracing. Any invoker of
- * {@link #trace(View, MotionEvent, MotionEventTraceType)} should first check
- * that this value is set to true as not to affect performance.
- *
- * @hide
- */
- public static final boolean TRACE_MOTION_EVENTS = false;
-
- /**
- * The system property of dynamic switch for capturing view information
- * when it is set, we dump interested fields and methods for the view on focus
- */
- static final String SYSTEM_PROPERTY_CAPTURE_VIEW = "debug.captureview";
-
- /**
* The system property of dynamic switch for capturing event information
* when it is set, we log key events, touch/motion and trackball events
*/
@@ -170,12 +155,6 @@
@Debug.DebugProperty
public static boolean consistencyCheckEnabled = false;
- static {
- if (false) {
- Debug.setFieldsOn(ViewDebug.class, true);
- }
- }
-
/**
* This annotation can be used to mark fields and methods to be dumped by
* the view server. Only non-void methods with no arguments can be annotated
@@ -424,21 +403,6 @@
private static String sRecyclerTracePrefix;
/**
- * Defines the type of motion events trace to output to the motion events traces file.
- *
- * @hide
- */
- public enum MotionEventTraceType {
- DISPATCH,
- ON_INTERCEPT,
- ON_TOUCH
- }
-
- private static BufferedWriter sMotionEventTraces;
- private static ViewAncestor sMotionEventRoot;
- private static String sMotionEventTracePrefix;
-
- /**
* Returns the number of instanciated Views.
*
* @return The number of Views instanciated in the current process.
@@ -574,6 +538,7 @@
recyclerDump = new File(recyclerDump, sRecyclerTracePrefix + ".traces");
try {
if (recyclerDump.exists()) {
+ //noinspection ResultOfMethodCallIgnored
recyclerDump.delete();
}
final FileOutputStream file = new FileOutputStream(recyclerDump);
@@ -732,146 +697,6 @@
sHierarhcyRoot = null;
}
- /**
- * Outputs a trace to the currently opened traces file. The trace contains the class name
- * and instance's hashcode of the specified view as well as the supplied trace type.
- *
- * @param view the view to trace
- * @param event the event of the trace
- * @param type the type of the trace
- *
- * @hide
- */
- public static void trace(View view, MotionEvent event, MotionEventTraceType type) {
- if (sMotionEventTraces == null) {
- return;
- }
-
- try {
- sMotionEventTraces.write(type.name());
- sMotionEventTraces.write(' ');
- sMotionEventTraces.write(event.getAction());
- sMotionEventTraces.write(' ');
- sMotionEventTraces.write(view.getClass().getName());
- sMotionEventTraces.write('@');
- sMotionEventTraces.write(Integer.toHexString(view.hashCode()));
- sHierarchyTraces.newLine();
- } catch (IOException e) {
- Log.w("View", "Error while dumping trace of event " + event + " for view " + view);
- }
- }
-
- /**
- * Starts tracing the motion events for the hierarchy of the specificy view.
- * The trace is identified by a prefix, used to build the traces files names:
- * <code>/EXTERNAL/motion-events/PREFIX.traces</code> and
- * <code>/EXTERNAL/motion-events/PREFIX.tree</code>.
- *
- * Only one view hierarchy can be traced at the same time. After calling this method, any
- * other invocation will result in a <code>IllegalStateException</code> unless
- * {@link #stopMotionEventTracing()} is invoked before.
- *
- * Calling this method creates the file <code>/EXTERNAL/motion-events/PREFIX.traces</code>
- * containing all the traces (or method calls) relative to the specified view's hierarchy.
- *
- * This method will return immediately if TRACE_HIERARCHY is false.
- *
- * @param prefix the traces files name prefix
- * @param view the view whose hierarchy must be traced
- *
- * @see #stopMotionEventTracing()
- * @see #trace(View, MotionEvent, android.view.ViewDebug.MotionEventTraceType)
- *
- * @hide
- */
- public static void startMotionEventTracing(String prefix, View view) {
- //noinspection PointlessBooleanExpression,ConstantConditions
- if (!TRACE_MOTION_EVENTS) {
- return;
- }
-
- if (sMotionEventRoot != null) {
- throw new IllegalStateException("You must call stopMotionEventTracing() before running" +
- " a new trace!");
- }
-
- File hierarchyDump = new File(Environment.getExternalStorageDirectory(), "motion-events/");
- //noinspection ResultOfMethodCallIgnored
- hierarchyDump.mkdirs();
-
- hierarchyDump = new File(hierarchyDump, prefix + ".traces");
- sMotionEventTracePrefix = prefix;
-
- try {
- sMotionEventTraces = new BufferedWriter(new FileWriter(hierarchyDump), 32 * 1024);
- } catch (IOException e) {
- Log.e("View", "Could not dump view hierarchy");
- return;
- }
-
- sMotionEventRoot = (ViewAncestor) view.getRootView().getParent();
- }
-
- /**
- * Stops the current motion events tracing. This method closes the file
- * <code>/EXTERNAL/motion-events/PREFIX.traces</code>.
- *
- * Calling this method creates the file <code>/EXTERNAL/motion-events/PREFIX.tree</code>
- * containing the view hierarchy of the view supplied to
- * {@link #startMotionEventTracing(String, View)}.
- *
- * This method will return immediately if TRACE_HIERARCHY is false.
- *
- * @see #startMotionEventTracing(String, View)
- * @see #trace(View, MotionEvent, android.view.ViewDebug.MotionEventTraceType)
- *
- * @hide
- */
- public static void stopMotionEventTracing() {
- //noinspection PointlessBooleanExpression,ConstantConditions
- if (!TRACE_MOTION_EVENTS) {
- return;
- }
-
- if (sMotionEventRoot == null || sMotionEventTraces == null) {
- throw new IllegalStateException("You must call startMotionEventTracing() before" +
- " stopMotionEventTracing()!");
- }
-
- try {
- sMotionEventTraces.close();
- } catch (IOException e) {
- Log.e("View", "Could not write view traces");
- }
- sMotionEventTraces = null;
-
- File hierarchyDump = new File(Environment.getExternalStorageDirectory(), "motion-events/");
- //noinspection ResultOfMethodCallIgnored
- hierarchyDump.mkdirs();
- hierarchyDump = new File(hierarchyDump, sMotionEventTracePrefix + ".tree");
-
- BufferedWriter out;
- try {
- out = new BufferedWriter(new FileWriter(hierarchyDump), 8 * 1024);
- } catch (IOException e) {
- Log.e("View", "Could not dump view hierarchy");
- return;
- }
-
- View view = sMotionEventRoot.getView();
- if (view instanceof ViewGroup) {
- ViewGroup group = (ViewGroup) view;
- dumpViewHierarchy(group, out, 0);
- try {
- out.close();
- } catch (IOException e) {
- Log.e("View", "Could not dump view hierarchy");
- }
- }
-
- sHierarhcyRoot = null;
- }
-
static void dispatchCommand(View view, String command, String parameters,
OutputStream clientStream) throws IOException {
@@ -1069,8 +894,10 @@
try {
T[] data = operation.pre();
long start = Debug.threadCpuTimeNanos();
+ //noinspection unchecked
operation.run(data);
duration[0] = Debug.threadCpuTimeNanos() - start;
+ //noinspection unchecked
operation.post(data);
} finally {
latch.countDown();
@@ -1201,12 +1028,7 @@
cache[0] = captureView.createSnapshot(
Bitmap.Config.ARGB_8888, 0, skpiChildren);
} catch (OutOfMemoryError e) {
- try {
- cache[0] = captureView.createSnapshot(
- Bitmap.Config.ARGB_4444, 0, skpiChildren);
- } catch (OutOfMemoryError e2) {
- Log.w("View", "Out of memory for bitmap");
- }
+ Log.w("View", "Out of memory for bitmap");
} finally {
latch.countDown();
}
@@ -1316,7 +1138,6 @@
}
final HashMap<Class<?>, Field[]> map = sFieldsForClasses;
- final HashMap<AccessibleObject, ExportedProperty> annotations = sAnnotations;
Field[] fields = map.get(klass);
if (fields != null) {
@@ -1332,7 +1153,7 @@
if (field.isAnnotationPresent(ExportedProperty.class)) {
field.setAccessible(true);
foundFields.add(field);
- annotations.put(field, field.getAnnotation(ExportedProperty.class));
+ sAnnotations.put(field, field.getAnnotation(ExportedProperty.class));
}
}
@@ -1351,7 +1172,6 @@
}
final HashMap<Class<?>, Method[]> map = sMethodsForClasses;
- final HashMap<AccessibleObject, ExportedProperty> annotations = sAnnotations;
Method[] methods = map.get(klass);
if (methods != null) {
@@ -1369,7 +1189,7 @@
method.getReturnType() != Void.class) {
method.setAccessible(true);
foundMethods.add(method);
- annotations.put(method, method.getAnnotation(ExportedProperty.class));
+ sAnnotations.put(method, method.getAnnotation(ExportedProperty.class));
}
}
diff --git a/core/java/android/view/accessibility/AccessibilityRecord.java b/core/java/android/view/accessibility/AccessibilityRecord.java
index fecf9df..7819b17 100644
--- a/core/java/android/view/accessibility/AccessibilityRecord.java
+++ b/core/java/android/view/accessibility/AccessibilityRecord.java
@@ -341,7 +341,7 @@
*
* @return An instance.
*/
- protected static AccessibilityRecord obtain() {
+ public static AccessibilityRecord obtain() {
synchronized (sPoolLock) {
if (sPool != null) {
AccessibilityRecord record = sPool;
diff --git a/core/java/android/widget/ExpandableListView.java b/core/java/android/widget/ExpandableListView.java
index f862368..ead9b4f 100644
--- a/core/java/android/widget/ExpandableListView.java
+++ b/core/java/android/widget/ExpandableListView.java
@@ -599,12 +599,35 @@
* was already expanded, this will return false)
*/
public boolean expandGroup(int groupPos) {
- boolean retValue = mConnector.expandGroup(groupPos);
+ return expandGroup(groupPos, false);
+ }
+
+ /**
+ * Expand a group in the grouped list view
+ *
+ * @param groupPos the group to be expanded
+ * @param animate true if the expanding group should be animated in
+ * @return True if the group was expanded, false otherwise (if the group
+ * was already expanded, this will return false)
+ */
+ public boolean expandGroup(int groupPos, boolean animate) {
+ PositionMetadata pm = mConnector.getFlattenedPos(ExpandableListPosition.obtain(
+ ExpandableListPosition.GROUP, groupPos, -1, -1));
+ boolean retValue = mConnector.expandGroup(pm);
if (mOnGroupExpandListener != null) {
mOnGroupExpandListener.onGroupExpand(groupPos);
}
-
+
+ if (animate) {
+ final int groupFlatPos = pm.position.flatListPos;
+
+ final int shiftedGroupPosition = groupFlatPos + getHeaderViewsCount();
+ smoothScrollToPosition(shiftedGroupPosition + mAdapter.getChildrenCount(groupPos),
+ shiftedGroupPosition);
+ }
+ pm.recycle();
+
return retValue;
}
diff --git a/core/java/com/android/internal/widget/AbsActionBarView.java b/core/java/com/android/internal/widget/AbsActionBarView.java
index 7830dca..788883b 100644
--- a/core/java/com/android/internal/widget/AbsActionBarView.java
+++ b/core/java/com/android/internal/widget/AbsActionBarView.java
@@ -154,7 +154,7 @@
availableWidth -= child.getMeasuredWidth();
availableWidth -= spacing;
- return availableWidth;
+ return Math.max(0, availableWidth);
}
protected int positionChild(View child, int x, int y, int contentHeight) {
diff --git a/core/java/com/android/internal/widget/ActionBarView.java b/core/java/com/android/internal/widget/ActionBarView.java
index 13ccbba..f1887eb 100644
--- a/core/java/com/android/internal/widget/ActionBarView.java
+++ b/core/java/com/android/internal/widget/ActionBarView.java
@@ -713,48 +713,48 @@
mHomeLayout.measure(MeasureSpec.makeMeasureSpec(availableWidth, MeasureSpec.AT_MOST),
MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY));
final int homeWidth = mHomeLayout.getMeasuredWidth();
- availableWidth -= homeWidth;
- leftOfCenter -= homeWidth;
+ availableWidth = Math.max(0, availableWidth - homeWidth);
+ leftOfCenter = Math.max(0, availableWidth - homeWidth);
}
if (mMenuView != null && mMenuView.getParent() == this) {
availableWidth = measureChildView(mMenuView, availableWidth,
childSpecHeight, 0);
- rightOfCenter -= mMenuView.getMeasuredWidth();
+ rightOfCenter = Math.max(0, rightOfCenter - mMenuView.getMeasuredWidth());
}
boolean showTitle = mTitleLayout != null && mTitleLayout.getVisibility() != GONE &&
(mDisplayOptions & ActionBar.DISPLAY_SHOW_TITLE) != 0;
if (showTitle) {
availableWidth = measureChildView(mTitleLayout, availableWidth, childSpecHeight, 0);
- leftOfCenter -= mTitleLayout.getMeasuredWidth();
+ leftOfCenter = Math.max(0, leftOfCenter - mTitleLayout.getMeasuredWidth());
}
switch (mNavigationMode) {
case ActionBar.NAVIGATION_MODE_LIST:
if (mListNavLayout != null) {
final int itemPaddingSize = showTitle ? mItemPadding * 2 : mItemPadding;
- availableWidth -= itemPaddingSize;
- leftOfCenter -= itemPaddingSize;
+ availableWidth = Math.max(0, availableWidth - itemPaddingSize);
+ leftOfCenter = Math.max(0, leftOfCenter - itemPaddingSize);
mListNavLayout.measure(
MeasureSpec.makeMeasureSpec(availableWidth, MeasureSpec.AT_MOST),
MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY));
final int listNavWidth = mListNavLayout.getMeasuredWidth();
- availableWidth -= listNavWidth;
- leftOfCenter -= listNavWidth;
+ availableWidth = Math.max(0, availableWidth - listNavWidth);
+ leftOfCenter = Math.max(0, leftOfCenter - listNavWidth);
}
break;
case ActionBar.NAVIGATION_MODE_TABS:
if (mTabScrollView != null) {
final int itemPaddingSize = showTitle ? mItemPadding * 2 : mItemPadding;
- availableWidth -= itemPaddingSize;
- leftOfCenter -= itemPaddingSize;
+ availableWidth = Math.max(0, availableWidth - itemPaddingSize);
+ leftOfCenter = Math.max(0, leftOfCenter - itemPaddingSize);
mTabScrollView.measure(
MeasureSpec.makeMeasureSpec(availableWidth, MeasureSpec.AT_MOST),
MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY));
final int tabWidth = mTabScrollView.getMeasuredWidth();
- availableWidth -= tabWidth;
- leftOfCenter -= tabWidth;
+ availableWidth = Math.max(0, availableWidth - tabWidth);
+ leftOfCenter = Math.max(0, leftOfCenter - tabWidth);
}
break;
}
@@ -763,7 +763,8 @@
mIndeterminateProgressView.getVisibility() != GONE) {
availableWidth = measureChildView(mIndeterminateProgressView, availableWidth,
childSpecHeight, 0);
- rightOfCenter -= mIndeterminateProgressView.getMeasuredWidth();
+ rightOfCenter = Math.max(0,
+ rightOfCenter - mIndeterminateProgressView.getMeasuredWidth());
}
if ((mDisplayOptions & ActionBar.DISPLAY_SHOW_CUSTOM) != 0 && mCustomNavView != null) {
diff --git a/core/jni/android/graphics/Canvas.cpp b/core/jni/android/graphics/Canvas.cpp
index f5f26be..4a09232 100644
--- a/core/jni/android/graphics/Canvas.cpp
+++ b/core/jni/android/graphics/Canvas.cpp
@@ -73,20 +73,6 @@
static jboolean isOpaque(JNIEnv* env, jobject jcanvas) {
NPE_CHECK_RETURN_ZERO(env, jcanvas);
SkCanvas* canvas = GraphicsJNI::getNativeCanvas(env, jcanvas);
-
- /*
- Currently we cannot support transparency in GL-based canvas' at
- the view level. Therefore we cannot base our answer on the device's
- bitmap, but need to hard-code the answer. If we relax this
- limitation in views, we can simplify the following code as well.
-
- Use the getViewport() call to find out if we're gl-based...
- */
- if (canvas->getViewport(NULL)) {
- return true;
- }
-
- // normal technique, rely on the device's bitmap for the answer
return canvas->getDevice()->accessBitmap(false).isOpaque();
}
diff --git a/core/jni/android/graphics/NinePatchImpl.cpp b/core/jni/android/graphics/NinePatchImpl.cpp
index ff24a87..a3e36ee 100644
--- a/core/jni/android/graphics/NinePatchImpl.cpp
+++ b/core/jni/android/graphics/NinePatchImpl.cpp
@@ -116,9 +116,9 @@
paint = &defaultPaint;
}
- // if our canvas is GL, draw this as a mesh, which will be faster than
- // in parts (which is faster for raster)
- if (canvas && canvas->getViewport(NULL)) {
+ // if our SkCanvas were back by GL we should enable this and draw this as
+ // a mesh, which will be faster in most cases.
+ if (false) {
SkNinePatch::DrawMesh(canvas, bounds, bitmap,
chunk.xDivs, chunk.numXDivs,
chunk.yDivs, chunk.numYDivs,
diff --git a/core/jni/android/graphics/TextLayoutCache.cpp b/core/jni/android/graphics/TextLayoutCache.cpp
index 26aa7d9..a5b2006 100644
--- a/core/jni/android/graphics/TextLayoutCache.cpp
+++ b/core/jni/android/graphics/TextLayoutCache.cpp
@@ -547,6 +547,25 @@
LOGD(" -- isDevKernText=%d", paint->isDevKernText());
#endif
+ if (shaperItem.advances == NULL || shaperItem.num_glyphs == 0) {
+#if DEBUG_GLYPHS
+ LOGD("HARFBUZZ -- advances array is empty or num_glypth = 0");
+#endif
+ for (size_t i = 0; i < count; i++) {
+ outAdvances[i] = 0;
+ }
+ *outTotalAdvance = 0;
+
+ if (outGlyphs) {
+ *outGlyphsCount = 0;
+ *outGlyphs = new jchar[0];
+ }
+
+ // Cleaning
+ deleteGlyphArrays(&shaperItem);
+ HB_FreeFace(shaperItem.face);
+ return;
+ }
// Get Advances and their total
jfloat totalAdvance = outAdvances[0] = HBFixedToFloat(shaperItem.advances[shaperItem.log_clusters[0]]);
for (size_t i = 1; i < count; i++) {
diff --git a/core/jni/android_hardware_UsbDeviceConnection.cpp b/core/jni/android_hardware_UsbDeviceConnection.cpp
index 4d73bf3..68be9e1 100644
--- a/core/jni/android_hardware_UsbDeviceConnection.cpp
+++ b/core/jni/android_hardware_UsbDeviceConnection.cpp
@@ -83,6 +83,27 @@
return usb_device_get_fd(device);
}
+static jbyteArray
+android_hardware_UsbDeviceConnection_get_desc(JNIEnv *env, jobject thiz)
+{
+ char buffer[16384];
+ int fd = android_hardware_UsbDeviceConnection_get_fd(env, thiz);
+ if (fd < 0) return NULL;
+ lseek(fd, 0, SEEK_SET);
+ int length = read(fd, buffer, sizeof(buffer));
+ if (length < 0) return NULL;
+
+ jbyteArray ret = env->NewByteArray(length);
+ if (ret) {
+ jbyte* bytes = (jbyte*)env->GetPrimitiveArrayCritical(ret, 0);
+ if (bytes) {
+ memcpy(bytes, buffer, length);
+ env->ReleasePrimitiveArrayCritical(ret, bytes, 0);
+ }
+ }
+ return ret;
+}
+
static jboolean
android_hardware_UsbDeviceConnection_claim_interface(JNIEnv *env, jobject thiz,
int interfaceID, jboolean force)
@@ -211,6 +232,7 @@
(void *)android_hardware_UsbDeviceConnection_open},
{"native_close", "()V", (void *)android_hardware_UsbDeviceConnection_close},
{"native_get_fd", "()I", (void *)android_hardware_UsbDeviceConnection_get_fd},
+ {"native_get_desc", "()[B", (void *)android_hardware_UsbDeviceConnection_get_desc},
{"native_claim_interface", "(IZ)Z",(void *)android_hardware_UsbDeviceConnection_claim_interface},
{"native_release_interface","(I)Z", (void *)android_hardware_UsbDeviceConnection_release_interface},
{"native_control_request", "(IIII[BII)I",
diff --git a/core/jni/android_net_NetUtils.cpp b/core/jni/android_net_NetUtils.cpp
index 548376d..ddae505 100644
--- a/core/jni/android_net_NetUtils.cpp
+++ b/core/jni/android_net_NetUtils.cpp
@@ -26,10 +26,6 @@
extern "C" {
int ifc_enable(const char *ifname);
int ifc_disable(const char *ifname);
-int ifc_add_route(const char *ifname, const char *destStr, uint32_t prefixLen, const char *gwStr);
-int ifc_remove_host_routes(const char *ifname);
-int ifc_get_default_route(const char *ifname);
-int ifc_remove_default_route(const char *ifname);
int ifc_reset_connections(const char *ifname);
int dhcp_do_request(const char *ifname,
@@ -94,56 +90,6 @@
return (jint)result;
}
-static jint android_net_utils_addRoute(JNIEnv* env, jobject clazz, jstring ifname,
- jstring dst, jint prefixLength, jstring gw)
-{
- int result;
-
- const char *nameStr = env->GetStringUTFChars(ifname, NULL);
- const char *dstStr = env->GetStringUTFChars(dst, NULL);
- const char *gwStr = NULL;
- if (gw != NULL) {
- gwStr = env->GetStringUTFChars(gw, NULL);
- }
- result = ::ifc_add_route(nameStr, dstStr, prefixLength, gwStr);
- env->ReleaseStringUTFChars(ifname, nameStr);
- env->ReleaseStringUTFChars(dst, dstStr);
- if (gw != NULL) {
- env->ReleaseStringUTFChars(gw, gwStr);
- }
- return (jint)result;
-}
-
-static jint android_net_utils_removeHostRoutes(JNIEnv* env, jobject clazz, jstring ifname)
-{
- int result;
-
- const char *nameStr = env->GetStringUTFChars(ifname, NULL);
- result = ::ifc_remove_host_routes(nameStr);
- env->ReleaseStringUTFChars(ifname, nameStr);
- return (jint)result;
-}
-
-static jint android_net_utils_getDefaultRoute(JNIEnv* env, jobject clazz, jstring ifname)
-{
- int result;
-
- const char *nameStr = env->GetStringUTFChars(ifname, NULL);
- result = ::ifc_get_default_route(nameStr);
- env->ReleaseStringUTFChars(ifname, nameStr);
- return (jint)result;
-}
-
-static jint android_net_utils_removeDefaultRoute(JNIEnv* env, jobject clazz, jstring ifname)
-{
- int result;
-
- const char *nameStr = env->GetStringUTFChars(ifname, NULL);
- result = ::ifc_remove_default_route(nameStr);
- env->ReleaseStringUTFChars(ifname, nameStr);
- return (jint)result;
-}
-
static jint android_net_utils_resetConnections(JNIEnv* env, jobject clazz, jstring ifname)
{
int result;
@@ -260,12 +206,6 @@
{ "enableInterface", "(Ljava/lang/String;)I", (void *)android_net_utils_enableInterface },
{ "disableInterface", "(Ljava/lang/String;)I", (void *)android_net_utils_disableInterface },
- { "addRoute", "(Ljava/lang/String;Ljava/lang/String;ILjava/lang/String;)I",
- (void *)android_net_utils_addRoute },
- { "removeHostRoutes", "(Ljava/lang/String;)I", (void *)android_net_utils_removeHostRoutes },
- { "getDefaultRouteNative", "(Ljava/lang/String;)I",
- (void *)android_net_utils_getDefaultRoute },
- { "removeDefaultRoute", "(Ljava/lang/String;)I", (void *)android_net_utils_removeDefaultRoute },
{ "resetConnections", "(Ljava/lang/String;)I", (void *)android_net_utils_resetConnections },
{ "runDhcp", "(Ljava/lang/String;Landroid/net/DhcpInfoInternal;)Z", (void *)android_net_utils_runDhcp },
{ "runDhcpRenew", "(Ljava/lang/String;Landroid/net/DhcpInfoInternal;)Z", (void *)android_net_utils_runDhcpRenew },
diff --git a/core/res/res/drawable-hdpi/dialog_bottom_holo_dark.9.png b/core/res/res/drawable-hdpi/dialog_bottom_holo_dark.9.png
index 6c6252e..32c2c97 100644
--- a/core/res/res/drawable-hdpi/dialog_bottom_holo_dark.9.png
+++ b/core/res/res/drawable-hdpi/dialog_bottom_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/dialog_bottom_holo_light.9.png b/core/res/res/drawable-hdpi/dialog_bottom_holo_light.9.png
index 175c750..f1cba06 100644
--- a/core/res/res/drawable-hdpi/dialog_bottom_holo_light.9.png
+++ b/core/res/res/drawable-hdpi/dialog_bottom_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/dialog_full_holo_dark.9.png b/core/res/res/drawable-hdpi/dialog_full_holo_dark.9.png
index 6e9abe65..08b163a 100644
--- a/core/res/res/drawable-hdpi/dialog_full_holo_dark.9.png
+++ b/core/res/res/drawable-hdpi/dialog_full_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/dialog_full_holo_light.9.png b/core/res/res/drawable-hdpi/dialog_full_holo_light.9.png
index f96d09e..77ec017 100644
--- a/core/res/res/drawable-hdpi/dialog_full_holo_light.9.png
+++ b/core/res/res/drawable-hdpi/dialog_full_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/dialog_middle_holo_dark.9.png b/core/res/res/drawable-hdpi/dialog_middle_holo_dark.9.png
index 1f11f44..029f186 100644
--- a/core/res/res/drawable-hdpi/dialog_middle_holo_dark.9.png
+++ b/core/res/res/drawable-hdpi/dialog_middle_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/dialog_middle_holo_light.9.png b/core/res/res/drawable-hdpi/dialog_middle_holo_light.9.png
index 2e376cd..abaea2d 100644
--- a/core/res/res/drawable-hdpi/dialog_middle_holo_light.9.png
+++ b/core/res/res/drawable-hdpi/dialog_middle_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/dialog_top_holo_dark.9.png b/core/res/res/drawable-hdpi/dialog_top_holo_dark.9.png
index 73d56b7..acbd7cf 100644
--- a/core/res/res/drawable-hdpi/dialog_top_holo_dark.9.png
+++ b/core/res/res/drawable-hdpi/dialog_top_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/dialog_top_holo_light.9.png b/core/res/res/drawable-hdpi/dialog_top_holo_light.9.png
index 869decf..8982396 100644
--- a/core/res/res/drawable-hdpi/dialog_top_holo_light.9.png
+++ b/core/res/res/drawable-hdpi/dialog_top_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/toast_frame.9.png b/core/res/res/drawable-hdpi/toast_frame.9.png
index 736683e..08b163a 100644
--- a/core/res/res/drawable-hdpi/toast_frame.9.png
+++ b/core/res/res/drawable-hdpi/toast_frame.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/dialog_bottom_holo_dark.9.png b/core/res/res/drawable-mdpi/dialog_bottom_holo_dark.9.png
index 9471615..cc66804 100644
--- a/core/res/res/drawable-mdpi/dialog_bottom_holo_dark.9.png
+++ b/core/res/res/drawable-mdpi/dialog_bottom_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/dialog_bottom_holo_light.9.png b/core/res/res/drawable-mdpi/dialog_bottom_holo_light.9.png
index 0502b93..bc734c8 100644
--- a/core/res/res/drawable-mdpi/dialog_bottom_holo_light.9.png
+++ b/core/res/res/drawable-mdpi/dialog_bottom_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/dialog_full_holo_dark.9.png b/core/res/res/drawable-mdpi/dialog_full_holo_dark.9.png
index f364b2e..8603e93 100644
--- a/core/res/res/drawable-mdpi/dialog_full_holo_dark.9.png
+++ b/core/res/res/drawable-mdpi/dialog_full_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/dialog_full_holo_light.9.png b/core/res/res/drawable-mdpi/dialog_full_holo_light.9.png
index 91c2076..65a318c 100644
--- a/core/res/res/drawable-mdpi/dialog_full_holo_light.9.png
+++ b/core/res/res/drawable-mdpi/dialog_full_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/dialog_middle_holo_dark.9.png b/core/res/res/drawable-mdpi/dialog_middle_holo_dark.9.png
index 92788c9..e39a472 100644
--- a/core/res/res/drawable-mdpi/dialog_middle_holo_dark.9.png
+++ b/core/res/res/drawable-mdpi/dialog_middle_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/dialog_middle_holo_light.9.png b/core/res/res/drawable-mdpi/dialog_middle_holo_light.9.png
index 74b66f8..68f9e57 100644
--- a/core/res/res/drawable-mdpi/dialog_middle_holo_light.9.png
+++ b/core/res/res/drawable-mdpi/dialog_middle_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/dialog_top_holo_dark.9.png b/core/res/res/drawable-mdpi/dialog_top_holo_dark.9.png
index f25cfb6..32c49f2 100644
--- a/core/res/res/drawable-mdpi/dialog_top_holo_dark.9.png
+++ b/core/res/res/drawable-mdpi/dialog_top_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/dialog_top_holo_light.9.png b/core/res/res/drawable-mdpi/dialog_top_holo_light.9.png
index ff3ff06..60aa8cb 100644
--- a/core/res/res/drawable-mdpi/dialog_top_holo_light.9.png
+++ b/core/res/res/drawable-mdpi/dialog_top_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/toast_frame.9.png b/core/res/res/drawable-mdpi/toast_frame.9.png
index 1b06b7c8..8603e93 100755
--- a/core/res/res/drawable-mdpi/toast_frame.9.png
+++ b/core/res/res/drawable-mdpi/toast_frame.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/dialog_bottom_holo_dark.9.png b/core/res/res/drawable-xhdpi/dialog_bottom_holo_dark.9.png
new file mode 100644
index 0000000..b33e117
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/dialog_bottom_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/dialog_bottom_holo_light.9.png b/core/res/res/drawable-xhdpi/dialog_bottom_holo_light.9.png
new file mode 100644
index 0000000..d84d427
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/dialog_bottom_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/dialog_full_holo_dark.9.png b/core/res/res/drawable-xhdpi/dialog_full_holo_dark.9.png
new file mode 100644
index 0000000..9c0ff47
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/dialog_full_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/dialog_full_holo_light.9.png b/core/res/res/drawable-xhdpi/dialog_full_holo_light.9.png
new file mode 100644
index 0000000..331a4f2
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/dialog_full_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/dialog_middle_holo_dark.9.png b/core/res/res/drawable-xhdpi/dialog_middle_holo_dark.9.png
new file mode 100644
index 0000000..cdc887d
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/dialog_middle_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/dialog_middle_holo_light.9.png b/core/res/res/drawable-xhdpi/dialog_middle_holo_light.9.png
new file mode 100644
index 0000000..55c60b8
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/dialog_middle_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/dialog_top_holo_dark.9.png b/core/res/res/drawable-xhdpi/dialog_top_holo_dark.9.png
new file mode 100644
index 0000000..600efb3
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/dialog_top_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/dialog_top_holo_light.9.png b/core/res/res/drawable-xhdpi/dialog_top_holo_light.9.png
new file mode 100644
index 0000000..d33d033
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/dialog_top_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/toast_frame.9.png b/core/res/res/drawable-xhdpi/toast_frame.9.png
new file mode 100644
index 0000000..9c0ff47
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/toast_frame.9.png
Binary files differ
diff --git a/core/res/res/layout/alert_dialog_holo.xml b/core/res/res/layout/alert_dialog_holo.xml
index 57eb9c7..8ee91ca 100644
--- a/core/res/res/layout/alert_dialog_holo.xml
+++ b/core/res/res/layout/alert_dialog_holo.xml
@@ -22,6 +22,8 @@
android:id="@+id/parentPanel"
android:layout_width="match_parent"
android:layout_height="wrap_content"
+ android:layout_marginLeft="8dip"
+ android:layout_marginRight="8dip"
android:orientation="vertical">
<LinearLayout android:id="@+id/topPanel"
@@ -42,7 +44,7 @@
android:layout_height="wrap_content"
android:orientation="horizontal"
android:gravity="center_vertical|left"
- android:minHeight="60dip"
+ android:minHeight="@dimen/alert_dialog_title_height"
android:layout_marginLeft="32dip"
android:layout_marginRight="32dip">
<ImageView android:id="@+id/icon"
@@ -107,7 +109,7 @@
<LinearLayout android:id="@+id/buttonPanel"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:minHeight="54dip"
+ android:minHeight="@dimen/alert_dialog_button_bar_height"
android:orientation="vertical"
android:divider="?android:attr/dividerHorizontal"
android:showDividers="beginning"
@@ -132,6 +134,7 @@
android:layout_weight="1"
android:maxLines="2"
style="?android:attr/buttonBarButtonStyle"
+ android:minHeight="@dimen/alert_dialog_button_bar_height"
android:layout_height="wrap_content" />
<Button android:id="@+id/button3"
android:layout_width="0dip"
@@ -139,12 +142,14 @@
android:layout_weight="1"
android:maxLines="2"
style="?android:attr/buttonBarButtonStyle"
+ android:minHeight="@dimen/alert_dialog_button_bar_height"
android:layout_height="wrap_content" />
<Button android:id="@+id/button2"
android:layout_width="0dip"
android:layout_gravity="right"
android:layout_weight="1"
android:maxLines="2"
+ android:minHeight="@dimen/alert_dialog_button_bar_height"
style="?android:attr/buttonBarButtonStyle"
android:layout_height="wrap_content" />
<LinearLayout android:id="@+id/rightSpacer"
diff --git a/core/res/res/values-ar/strings.xml b/core/res/res/values-ar/strings.xml
index 73506df..6f70942 100644
--- a/core/res/res/values-ar/strings.xml
+++ b/core/res/res/values-ar/strings.xml
@@ -240,6 +240,10 @@
<string name="permdesc_batteryStats" msgid="5847319823772230560">"للسماح بتعديل إحصاءات البطارية المجمّعة. ليس للاستخدام بواسطة التطبيقات العادية."</string>
<string name="permlab_backup" msgid="470013022865453920">"التحكم في النسخة الاحتياطية للنظام واستعادتها"</string>
<string name="permdesc_backup" msgid="4837493065154256525">"للسماح للتطبيق بالتحكم في النسخة الاحتياطية للنظام وآلية الاستعادة. ليس للاستخدام بواسطة التطبيقات العادية."</string>
+ <!-- no translation found for permlab_confirm_full_backup (5557071325804469102) -->
+ <skip />
+ <!-- no translation found for permdesc_confirm_full_backup (9005017754175897954) -->
+ <skip />
<string name="permlab_internalSystemWindow" msgid="2148563628140193231">"عرض النوافذ غير المصرح بها"</string>
<string name="permdesc_internalSystemWindow" msgid="5895082268284998469">"للسماح بإنشاء نوافذ بقصد استخدامها بواسطة واجهة مستخدم النظام الداخلي. ليس للاستخدام بواسطة التطبيقات العادية."</string>
<string name="permlab_systemAlertWindow" msgid="3372321942941168324">"عرض تنبيهات مستوى النظام"</string>
@@ -446,6 +450,10 @@
<string name="permdesc_bluetooth" product="default" msgid="762515380679392945">"للسماح لتطبيق ما بعرض تهيئة هاتف البلوتوث المحلي، وإجراء اتصالات وقبولها باستخدام الأجهزة المقترنة."</string>
<string name="permlab_nfc" msgid="4423351274757876953">"التحكم في اتصال الحقل القريب"</string>
<string name="permdesc_nfc" msgid="9171401851954407226">"للسماح لتطبيق ما بالاتصال بعلامات اتصال حقل قريب (NFC)، والبطاقات وبرامج القراءة."</string>
+ <!-- no translation found for permlab_vpn (8345800584532175312) -->
+ <skip />
+ <!-- no translation found for permdesc_vpn (5617893078989944219) -->
+ <skip />
<string name="permlab_disableKeyguard" msgid="4977406164311535092">"تعطيل تأمين المفاتيح"</string>
<string name="permdesc_disableKeyguard" msgid="3189763479326302017">"للسماح لتطبيق ما بتعطيل تأمين المفاتيح وأي أمان كلمة مرور مرتبطة. ومثال صحيح لذلك هو تعطيل الهاتف لتأمين المفاتيح عند استلام مكالمة هاتفية واردة، ثم إعادة تمكين تأمين المفاتيح عند انتهاء المكالمة."</string>
<string name="permlab_readSyncSettings" msgid="6201810008230503052">"قراءة إعدادات المزامنة"</string>
@@ -1019,4 +1027,13 @@
<string name="choose_account_label" msgid="4191313562041125787">"حدد حسابًا."</string>
<string name="number_picker_increment_button" msgid="4830170763103463443">"زيادة"</string>
<string name="number_picker_decrement_button" msgid="2576606679160067262">"تناقص"</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>
+ <!-- no translation found for storage_internal (7556050805474115618) -->
+ <skip />
+ <!-- no translation found for storage_sd_card (8921771478629812343) -->
+ <skip />
+ <!-- no translation found for storage_usb (3017954059538517278) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-bg/strings.xml b/core/res/res/values-bg/strings.xml
index cd37ab1..b01b6bc 100644
--- a/core/res/res/values-bg/strings.xml
+++ b/core/res/res/values-bg/strings.xml
@@ -240,6 +240,10 @@
<string name="permdesc_batteryStats" msgid="5847319823772230560">"Разрешава промяна на събраните статистически данни за батерията. Не е предназначено за нормални приложения."</string>
<string name="permlab_backup" msgid="470013022865453920">"контролиране на създаването и възстановяването на резервни копия на системата"</string>
<string name="permdesc_backup" msgid="4837493065154256525">"Разрешава на приложението да контролира системния механизъм за създаване и възстановяване на резервни копия. Не е предназначено за нормални приложения."</string>
+ <!-- no translation found for permlab_confirm_full_backup (5557071325804469102) -->
+ <skip />
+ <!-- no translation found for permdesc_confirm_full_backup (9005017754175897954) -->
+ <skip />
<string name="permlab_internalSystemWindow" msgid="2148563628140193231">"показване на неупълномощени прозорци"</string>
<string name="permdesc_internalSystemWindow" msgid="5895082268284998469">"Разрешава създаването на прозорци, предназначени за употреба от вътрешния системен потребителски интерфейс. Не е предназначено за нормални приложения."</string>
<string name="permlab_systemAlertWindow" msgid="3372321942941168324">"показване на сигнали на ниво система"</string>
@@ -446,6 +450,10 @@
<string name="permdesc_bluetooth" product="default" msgid="762515380679392945">"Разрешава на приложението да вижда конфигурацията на локалния Bluetooth телефон и да изгражда и приема връзки със сдвоени устройства."</string>
<string name="permlab_nfc" msgid="4423351274757876953">"контролиране на комуникацията в близкото поле"</string>
<string name="permdesc_nfc" msgid="9171401851954407226">"Разрешава на приложението да комуникира с маркери, карти и четци, ползващи комуникация в близкото поле (NFC)."</string>
+ <!-- no translation found for permlab_vpn (8345800584532175312) -->
+ <skip />
+ <!-- no translation found for permdesc_vpn (5617893078989944219) -->
+ <skip />
<string name="permlab_disableKeyguard" msgid="4977406164311535092">"деактивиране на заключването на клавиатурата"</string>
<string name="permdesc_disableKeyguard" msgid="3189763479326302017">"Разрешава на приложението да деактивира заключването на клавиатурата и свързаната защита с парола. Това е допустимо, когато например телефонът деактивира заключването при получаване на входящо обаждане и после го активира отново, когато обаждането завърши."</string>
<string name="permlab_readSyncSettings" msgid="6201810008230503052">"четене на настройките за синхронизиране"</string>
@@ -1019,4 +1027,13 @@
<string name="choose_account_label" msgid="4191313562041125787">"Избор на профил"</string>
<string name="number_picker_increment_button" msgid="4830170763103463443">"Увеличаване"</string>
<string name="number_picker_decrement_button" msgid="2576606679160067262">"Намаляване"</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>
+ <!-- no translation found for storage_internal (7556050805474115618) -->
+ <skip />
+ <!-- no translation found for storage_sd_card (8921771478629812343) -->
+ <skip />
+ <!-- no translation found for storage_usb (3017954059538517278) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-ca/strings.xml b/core/res/res/values-ca/strings.xml
index 0e83243..eb48b67 100644
--- a/core/res/res/values-ca/strings.xml
+++ b/core/res/res/values-ca/strings.xml
@@ -240,6 +240,10 @@
<string name="permdesc_batteryStats" msgid="5847319823772230560">"Permet la modificació de les estadístiques de la bateria que es recopilen. No indicat per a les aplicacions normals."</string>
<string name="permlab_backup" msgid="470013022865453920">"controlar la còpia de seguretat i restauració del sistema"</string>
<string name="permdesc_backup" msgid="4837493065154256525">"Permet a l\'aplicació controlar el mecanisme de còpia de seguretat i restauració del sistema. No indicat per a les aplicacions normals."</string>
+ <!-- no translation found for permlab_confirm_full_backup (5557071325804469102) -->
+ <skip />
+ <!-- no translation found for permdesc_confirm_full_backup (9005017754175897954) -->
+ <skip />
<string name="permlab_internalSystemWindow" msgid="2148563628140193231">"visualitzar finestres no autoritzades"</string>
<string name="permdesc_internalSystemWindow" msgid="5895082268284998469">"Permet la creació de finestres que utilitzarà la interfície d\'usuari del sistema interna. No indicat per a les aplicacions normals."</string>
<string name="permlab_systemAlertWindow" msgid="3372321942941168324">"visualitzar les alertes del sistema"</string>
@@ -446,6 +450,10 @@
<string name="permdesc_bluetooth" product="default" msgid="762515380679392945">"Permet a una aplicació visualitzar la configuració del telèfon Bluetooth local i establir i acceptar connexions amb els dispositius emparellats."</string>
<string name="permlab_nfc" msgid="4423351274757876953">"controla Near Field Communication (NFC)"</string>
<string name="permdesc_nfc" msgid="9171401851954407226">"Permet que una aplicació es comuniqui amb les etiquetes, les targetes i els lectors de Near Field Communication (NFC)"</string>
+ <!-- no translation found for permlab_vpn (8345800584532175312) -->
+ <skip />
+ <!-- no translation found for permdesc_vpn (5617893078989944219) -->
+ <skip />
<string name="permlab_disableKeyguard" msgid="4977406164311535092">"desactivar el bloqueig del teclat"</string>
<string name="permdesc_disableKeyguard" msgid="3189763479326302017">"Permet a una aplicació desactivar el bloqueig del teclat i qualsevol element de seguretat de contrasenyes associat. Un exemple d\'això és la desactivació per part del telèfon del bloqueig del teclat en rebre una trucada telefònica entrant i després la reactivació del bloqueig del teclat quan finalitza la trucada."</string>
<string name="permlab_readSyncSettings" msgid="6201810008230503052">"llegir la configuració de sincronització"</string>
@@ -1019,4 +1027,13 @@
<string name="choose_account_label" msgid="4191313562041125787">"Selecciona un compte"</string>
<string name="number_picker_increment_button" msgid="4830170763103463443">"Incrementa"</string>
<string name="number_picker_decrement_button" msgid="2576606679160067262">"Disminueix"</string>
+ <string name="action_bar_home_description" msgid="5293600496601490216">"Torna a la pàgina d\'inici"</string>
+ <string name="action_bar_up_description" msgid="2237496562952152589">"Mou cap a dalt"</string>
+ <string name="action_menu_overflow_description" msgid="2295659037509008453">"Més opcions"</string>
+ <!-- no translation found for storage_internal (7556050805474115618) -->
+ <skip />
+ <!-- no translation found for storage_sd_card (8921771478629812343) -->
+ <skip />
+ <!-- no translation found for storage_usb (3017954059538517278) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-cs/strings.xml b/core/res/res/values-cs/strings.xml
index e2deb0f..8fb793f 100644
--- a/core/res/res/values-cs/strings.xml
+++ b/core/res/res/values-cs/strings.xml
@@ -240,6 +240,10 @@
<string name="permdesc_batteryStats" msgid="5847319823772230560">"Umožňuje změnu shromážděných statistických údajů o baterii. Není určeno pro běžné aplikace."</string>
<string name="permlab_backup" msgid="470013022865453920">"ovládání zálohování a obnovy systému"</string>
<string name="permdesc_backup" msgid="4837493065154256525">"Umožňuje aplikaci ovládat systémový mechanizmus pro zálohování a obnovu dat. Není určeno pro běžné aplikace."</string>
+ <!-- no translation found for permlab_confirm_full_backup (5557071325804469102) -->
+ <skip />
+ <!-- no translation found for permdesc_confirm_full_backup (9005017754175897954) -->
+ <skip />
<string name="permlab_internalSystemWindow" msgid="2148563628140193231">"zobrazení nepovolených oken"</string>
<string name="permdesc_internalSystemWindow" msgid="5895082268284998469">"Umožňuje vytvoření oken, která mají být použita interním systémem uživatelského rozhraní. Běžné aplikace toto nastavení nepoužívají."</string>
<string name="permlab_systemAlertWindow" msgid="3372321942941168324">"zobrazení upozornění systémové úrovně"</string>
@@ -446,6 +450,10 @@
<string name="permdesc_bluetooth" product="default" msgid="762515380679392945">"Umožňuje aplikaci zobrazit konfiguraci místního telefonu s rozhraním Bluetooth, vytvářet připojení ke spárovaným zařízením a přijímat tato připojení."</string>
<string name="permlab_nfc" msgid="4423351274757876953">"ovládat technologii NFC"</string>
<string name="permdesc_nfc" msgid="9171401851954407226">"Umožňuje aplikaci komunikovat se štítky, kartami a čtečkami s podporou technologie NFC."</string>
+ <!-- no translation found for permlab_vpn (8345800584532175312) -->
+ <skip />
+ <!-- no translation found for permdesc_vpn (5617893078989944219) -->
+ <skip />
<string name="permlab_disableKeyguard" msgid="4977406164311535092">"vypnutí zámku kláves"</string>
<string name="permdesc_disableKeyguard" msgid="3189763479326302017">"Umožňuje aplikaci vypnout zámek kláves a související zabezpečení heslem. Příkladem oprávněného použití této funkce je vypnutí zámku klávesnice při příchozím hovoru a jeho opětovné zapnutí po skončení hovoru."</string>
<string name="permlab_readSyncSettings" msgid="6201810008230503052">"čtení nastavení synchronizace"</string>
@@ -1019,4 +1027,13 @@
<string name="choose_account_label" msgid="4191313562041125787">"Vybrat účet"</string>
<string name="number_picker_increment_button" msgid="4830170763103463443">"Zvýšení"</string>
<string name="number_picker_decrement_button" msgid="2576606679160067262">"Snížení"</string>
+ <string name="action_bar_home_description" msgid="5293600496601490216">"Přejít na plochu"</string>
+ <string name="action_bar_up_description" msgid="2237496562952152589">"Přejít nahoru"</string>
+ <string name="action_menu_overflow_description" msgid="2295659037509008453">"Další možnosti"</string>
+ <!-- no translation found for storage_internal (7556050805474115618) -->
+ <skip />
+ <!-- no translation found for storage_sd_card (8921771478629812343) -->
+ <skip />
+ <!-- no translation found for storage_usb (3017954059538517278) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-da/strings.xml b/core/res/res/values-da/strings.xml
index 6bc1e29..b399621 100644
--- a/core/res/res/values-da/strings.xml
+++ b/core/res/res/values-da/strings.xml
@@ -240,6 +240,10 @@
<string name="permdesc_batteryStats" msgid="5847319823772230560">"Tillader ændring af indsamlede batteristatistikker. Ikke til brug for normale programmer."</string>
<string name="permlab_backup" msgid="470013022865453920">"kontroller sikkerhedskopiering af system, og gendan"</string>
<string name="permdesc_backup" msgid="4837493065154256525">"Tillader, at et program kontrollerer systemets sikkerhedskopierings- og gendannelsesfunktion. Ikke til brug til normale programmer."</string>
+ <!-- no translation found for permlab_confirm_full_backup (5557071325804469102) -->
+ <skip />
+ <!-- no translation found for permdesc_confirm_full_backup (9005017754175897954) -->
+ <skip />
<string name="permlab_internalSystemWindow" msgid="2148563628140193231">"vis uautoriserede vinduer"</string>
<string name="permdesc_internalSystemWindow" msgid="5895082268284998469">"Tillader oprettelse af vinduer, der er beregnet til at blive brugt af den interne systembrugergrænseflade. Ikke til brug for normale programmer."</string>
<string name="permlab_systemAlertWindow" msgid="3372321942941168324">"vis underretninger på systemniveau"</string>
@@ -446,6 +450,10 @@
<string name="permdesc_bluetooth" product="default" msgid="762515380679392945">"Tillader, at et program viser konfigurationen af den lokale Bluetooth-telefon samt opretter og accepterer forbindelse med parrede enheder."</string>
<string name="permlab_nfc" msgid="4423351274757876953">"kontrollere Near Field Communication"</string>
<string name="permdesc_nfc" msgid="9171401851954407226">"Tillader, at et program kommunikerer med tags, kort og læsere i Near Field Communication (NFC)."</string>
+ <!-- no translation found for permlab_vpn (8345800584532175312) -->
+ <skip />
+ <!-- no translation found for permdesc_vpn (5617893078989944219) -->
+ <skip />
<string name="permlab_disableKeyguard" msgid="4977406164311535092">"deaktiver tastaturlås"</string>
<string name="permdesc_disableKeyguard" msgid="3189763479326302017">"Tillader, at et program deaktiverer tastaturlåsen og al associeret adgangskodesikkerhed. Et legitimt eksempel på dette er, at telefonen deaktiverer tastaturlåsen, når der modtages et indgående telefonopkald, og genaktiverer tastaturlåsen, når opkaldet er afsluttet."</string>
<string name="permlab_readSyncSettings" msgid="6201810008230503052">"læs indstillinger for synkronisering"</string>
@@ -1019,4 +1027,13 @@
<string name="choose_account_label" msgid="4191313562041125787">"Vælg en konto"</string>
<string name="number_picker_increment_button" msgid="4830170763103463443">"Optælling"</string>
<string name="number_picker_decrement_button" msgid="2576606679160067262">"Nedtælling"</string>
+ <string name="action_bar_home_description" msgid="5293600496601490216">"Naviger hjem"</string>
+ <string name="action_bar_up_description" msgid="2237496562952152589">"Naviger op"</string>
+ <string name="action_menu_overflow_description" msgid="2295659037509008453">"Flere valgmuligheder"</string>
+ <!-- no translation found for storage_internal (7556050805474115618) -->
+ <skip />
+ <!-- no translation found for storage_sd_card (8921771478629812343) -->
+ <skip />
+ <!-- no translation found for storage_usb (3017954059538517278) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-de/strings.xml b/core/res/res/values-de/strings.xml
index a97c017..0837ee91 100644
--- a/core/res/res/values-de/strings.xml
+++ b/core/res/res/values-de/strings.xml
@@ -240,6 +240,10 @@
<string name="permdesc_batteryStats" msgid="5847319823772230560">"Ermöglicht die Änderung von gesammelten Akku-Daten. Nicht für normale Anwendungen vorgesehen."</string>
<string name="permlab_backup" msgid="470013022865453920">"Systemsicherung und -wiederherstellung kontrollieren"</string>
<string name="permdesc_backup" msgid="4837493065154256525">"Der Anwendung wird die Steuerung des Sicherungs- und Wiederherstellungsmechanismus des Systems ermöglicht. Nicht für normale Anwendungen vorgesehen."</string>
+ <!-- no translation found for permlab_confirm_full_backup (5557071325804469102) -->
+ <skip />
+ <!-- no translation found for permdesc_confirm_full_backup (9005017754175897954) -->
+ <skip />
<string name="permlab_internalSystemWindow" msgid="2148563628140193231">"nicht autorisierte Fenster anzeigen"</string>
<string name="permdesc_internalSystemWindow" msgid="5895082268284998469">"Ermöglicht die Erstellung von Fenstern, die von der Benutzeroberfläche des internen Systems verwendet werden. Nicht für normale Anwendungen geeignet."</string>
<string name="permlab_systemAlertWindow" msgid="3372321942941168324">"Warnungen auf Systemebene anzeigen"</string>
@@ -446,6 +450,10 @@
<string name="permdesc_bluetooth" product="default" msgid="762515380679392945">"Ermöglicht einer Anwendung, die Konfiguration des lokalen Bluetooth-Telefons einzusehen und Verbindungen mit Partnergeräten herzustellen und zu akzeptieren"</string>
<string name="permlab_nfc" msgid="4423351274757876953">"Nahfeldkommunikation steuern"</string>
<string name="permdesc_nfc" msgid="9171401851954407226">"Ermöglicht einer Anwendung die Kommunikation mit Tags für Nahfeldkommunikation, Karten und Lesegeräte"</string>
+ <!-- no translation found for permlab_vpn (8345800584532175312) -->
+ <skip />
+ <!-- no translation found for permdesc_vpn (5617893078989944219) -->
+ <skip />
<string name="permlab_disableKeyguard" msgid="4977406164311535092">"Tastensperre deaktivieren"</string>
<string name="permdesc_disableKeyguard" msgid="3189763479326302017">"Ermöglicht einer Anwendung, die Tastensperre sowie den damit verbundenen Passwortschutz zu deaktivieren. So wird die Tastensperre vom Telefon deaktiviert, wenn ein Anruf eingeht, und nach Beendigung des Anrufs wieder aktiviert."</string>
<string name="permlab_readSyncSettings" msgid="6201810008230503052">"Synchronisierungseinstellungen lesen"</string>
@@ -1019,4 +1027,13 @@
<string name="choose_account_label" msgid="4191313562041125787">"Konto auswählen"</string>
<string name="number_picker_increment_button" msgid="4830170763103463443">"Erhöhen"</string>
<string name="number_picker_decrement_button" msgid="2576606679160067262">"Verringern"</string>
+ <string name="action_bar_home_description" msgid="5293600496601490216">"Zur Startseite navigieren"</string>
+ <string name="action_bar_up_description" msgid="2237496562952152589">"Nach oben navigieren"</string>
+ <string name="action_menu_overflow_description" msgid="2295659037509008453">"Weitere Optionen"</string>
+ <!-- no translation found for storage_internal (7556050805474115618) -->
+ <skip />
+ <!-- no translation found for storage_sd_card (8921771478629812343) -->
+ <skip />
+ <!-- no translation found for storage_usb (3017954059538517278) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-el/strings.xml b/core/res/res/values-el/strings.xml
index 490dbde..df83d34 100644
--- a/core/res/res/values-el/strings.xml
+++ b/core/res/res/values-el/strings.xml
@@ -240,6 +240,10 @@
<string name="permdesc_batteryStats" msgid="5847319823772230560">"Επιτρέπει την τροποποίηση στατιστικών μπαταρίας που έχουν συλλεχθεί. Δεν πρέπει να χρησιμοποιείται από συνήθεις εφαρμογές."</string>
<string name="permlab_backup" msgid="470013022865453920">"αντίγραφο ασφαλείας και επαναφορά συστήματος"</string>
<string name="permdesc_backup" msgid="4837493065154256525">"Επιτρέπει στην εφαρμογή τον έλεγχο του μηχανισμού δημιουργίας αντιγράφων ασφαλείας και επαναφοράς του συστήματος. Δεν προορίζεται για χρήση από κανονικές εφαρμογές."</string>
+ <!-- no translation found for permlab_confirm_full_backup (5557071325804469102) -->
+ <skip />
+ <!-- no translation found for permdesc_confirm_full_backup (9005017754175897954) -->
+ <skip />
<string name="permlab_internalSystemWindow" msgid="2148563628140193231">"προβολή μη εξουσιοδοτημένων παραθύρων"</string>
<string name="permdesc_internalSystemWindow" msgid="5895082268284998469">"Επιτρέπει τη δημιουργία παραθύρων που πρόκειται να χρησιμοποιηθούν από την εσωτερική διεπαφή χρήστη του συστήματος. Δεν πρέπει να χρησιμοποιείται από κανονικές εφαρμογές."</string>
<string name="permlab_systemAlertWindow" msgid="3372321942941168324">"εμφάνιση ειδοποιήσεων επιπέδου συστήματος"</string>
@@ -446,6 +450,10 @@
<string name="permdesc_bluetooth" product="default" msgid="762515380679392945">"Επιτρέπει σε μια εφαρμογή να προβάλει τη διαμόρφωση του τοπικού τηλεφώνου Bluetooth και επίσης να πραγματοποιεί και να αποδέχεται συνδέσεις με συζευγμένες συσκευές."</string>
<string name="permlab_nfc" msgid="4423351274757876953">"έλεγχος Επικοινωνίας κοντινού πεδίου (Near Field Communication)"</string>
<string name="permdesc_nfc" msgid="9171401851954407226">"Επιτρέπει σε μια εφαρμογή την επικοινωνία με ετικέτες, τις κάρτες και τους αναγνώστες της Επικοινωνίας κοντινού πεδίου (NFC)."</string>
+ <!-- no translation found for permlab_vpn (8345800584532175312) -->
+ <skip />
+ <!-- no translation found for permdesc_vpn (5617893078989944219) -->
+ <skip />
<string name="permlab_disableKeyguard" msgid="4977406164311535092">"απενεργοποίηση κλειδώματος πληκτρολογίου"</string>
<string name="permdesc_disableKeyguard" msgid="3189763479326302017">"Επιτρέπει σε μια εφαρμογή την απενεργοποίηση του κλειδώματος πληκτρολογίου και άλλης σχετικής ασφάλειας με κωδικό πρόσβασης. Για παράδειγμα, η απενεργοποίηση του κλειδώματος πληκτρολογίου όταν λαμβάνεται εισερχόμενη τηλεφωνική κλήση και η επανενεργοποίηση του κλειδώματος πληκτρολογίου όταν η κλήση τερματιστεί."</string>
<string name="permlab_readSyncSettings" msgid="6201810008230503052">"ανάγνωση ρυθμίσεων συγχρονισμού"</string>
@@ -1019,4 +1027,13 @@
<string name="choose_account_label" msgid="4191313562041125787">"Επιλογή λογαριασμού"</string>
<string name="number_picker_increment_button" msgid="4830170763103463443">"Αύξηση"</string>
<string name="number_picker_decrement_button" msgid="2576606679160067262">"Μείωση"</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>
+ <!-- no translation found for storage_internal (7556050805474115618) -->
+ <skip />
+ <!-- no translation found for storage_sd_card (8921771478629812343) -->
+ <skip />
+ <!-- no translation found for storage_usb (3017954059538517278) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-en-rGB/strings.xml b/core/res/res/values-en-rGB/strings.xml
index 5fa87ad..fa81526 100644
--- a/core/res/res/values-en-rGB/strings.xml
+++ b/core/res/res/values-en-rGB/strings.xml
@@ -240,6 +240,8 @@
<string name="permdesc_batteryStats" msgid="5847319823772230560">"Allows the modification of collected battery statistics. Not for use by normal applications."</string>
<string name="permlab_backup" msgid="470013022865453920">"control system back up and restore"</string>
<string name="permdesc_backup" msgid="4837493065154256525">"Allows the application to control the system\'s back-up and restore mechanism. Not for use by normal applications."</string>
+ <string name="permlab_confirm_full_backup" msgid="5557071325804469102">"confirm a full backup or restore operation"</string>
+ <string name="permdesc_confirm_full_backup" msgid="9005017754175897954">"Allows the application to launch the full backup confirmation UI. Not to be used by any application."</string>
<string name="permlab_internalSystemWindow" msgid="2148563628140193231">"display unauthorised windows"</string>
<string name="permdesc_internalSystemWindow" msgid="5895082268284998469">"Allows the creation of windows that are intended to be used by the internal system user interface. Not for use by normal applications."</string>
<string name="permlab_systemAlertWindow" msgid="3372321942941168324">"display system-level alerts"</string>
@@ -446,6 +448,10 @@
<string name="permdesc_bluetooth" product="default" msgid="762515380679392945">"Allows an application to view configuration of the local Bluetooth phone and to make and accept connections with paired devices."</string>
<string name="permlab_nfc" msgid="4423351274757876953">"control Near-Field Communication"</string>
<string name="permdesc_nfc" msgid="9171401851954407226">"Allows an application to communicate with Near-Field Communication (NFC) tags, cards and readers."</string>
+ <!-- no translation found for permlab_vpn (8345800584532175312) -->
+ <skip />
+ <!-- no translation found for permdesc_vpn (5617893078989944219) -->
+ <skip />
<string name="permlab_disableKeyguard" msgid="4977406164311535092">"disable key lock"</string>
<string name="permdesc_disableKeyguard" msgid="3189763479326302017">"Allows an application to disable the key lock and any associated password security. A legitimate example of this is the phone disabling the key lock when receiving an incoming phone call, then re-enabling the key lock when the call is finished."</string>
<string name="permlab_readSyncSettings" msgid="6201810008230503052">"read sync settings"</string>
@@ -1019,4 +1025,13 @@
<string name="choose_account_label" msgid="4191313562041125787">"Select an account"</string>
<string name="number_picker_increment_button" msgid="4830170763103463443">"Increment"</string>
<string name="number_picker_decrement_button" msgid="2576606679160067262">"Decrement"</string>
+ <string name="action_bar_home_description" msgid="5293600496601490216">"Navigate home"</string>
+ <string name="action_bar_up_description" msgid="2237496562952152589">"Navigate up"</string>
+ <string name="action_menu_overflow_description" msgid="2295659037509008453">"More options"</string>
+ <!-- no translation found for storage_internal (7556050805474115618) -->
+ <skip />
+ <!-- no translation found for storage_sd_card (8921771478629812343) -->
+ <skip />
+ <!-- no translation found for storage_usb (3017954059538517278) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-es-rUS/strings.xml b/core/res/res/values-es-rUS/strings.xml
index 251869a..a0c228c 100644
--- a/core/res/res/values-es-rUS/strings.xml
+++ b/core/res/res/values-es-rUS/strings.xml
@@ -240,6 +240,10 @@
<string name="permdesc_batteryStats" msgid="5847319823772230560">"Admite la modificación de estadísticas recopiladas sobre la batería. Las aplicaciones normales no deben utilizarlo."</string>
<string name="permlab_backup" msgid="470013022865453920">"copia de seguridad y restauración del sistema de control"</string>
<string name="permdesc_backup" msgid="4837493065154256525">"Permite a la aplicación controlar el mecanismo de restauración y copia de seguridad de los sistemas. No es para uso de las aplicaciones normales."</string>
+ <!-- no translation found for permlab_confirm_full_backup (5557071325804469102) -->
+ <skip />
+ <!-- no translation found for permdesc_confirm_full_backup (9005017754175897954) -->
+ <skip />
<string name="permlab_internalSystemWindow" msgid="2148563628140193231">"mostrar ventanas no autorizadas"</string>
<string name="permdesc_internalSystemWindow" msgid="5895082268284998469">"Permite la creación de ventanas que la interfaz interna del usuario del sistema pretenda utilizar. Las aplicaciones normales no deben utilizarlo."</string>
<string name="permlab_systemAlertWindow" msgid="3372321942941168324">"mostrar alertas a nivel del sistema"</string>
@@ -446,6 +450,10 @@
<string name="permdesc_bluetooth" product="default" msgid="762515380679392945">"Admite una aplicación que ve la configuración del teléfono Bluetooth local, y realiza y acepta conexiones con dispositivos vinculados."</string>
<string name="permlab_nfc" msgid="4423351274757876953">"controlar la Transmisión de datos en proximidad"</string>
<string name="permdesc_nfc" msgid="9171401851954407226">"Permite que una aplicación se comunique con etiquetas, tarjetas y lectores de Transmisión de datos en proximidad (NFC)."</string>
+ <!-- no translation found for permlab_vpn (8345800584532175312) -->
+ <skip />
+ <!-- no translation found for permdesc_vpn (5617893078989944219) -->
+ <skip />
<string name="permlab_disableKeyguard" msgid="4977406164311535092">"desactivar el bloqueo"</string>
<string name="permdesc_disableKeyguard" msgid="3189763479326302017">"Admite una aplicación que desactiva el bloqueo y cualquier seguridad con contraseña relacionada. Un ejemplo legítimo de esto es el bloqueo desactivado por el teléfono cuando recibe una llamada telefónica entrante, y luego la reactivación del bloqueo cuando finaliza la llamada."</string>
<string name="permlab_readSyncSettings" msgid="6201810008230503052">"leer la configuración de sincronización"</string>
@@ -1019,4 +1027,13 @@
<string name="choose_account_label" msgid="4191313562041125787">"Seleccionar una cuenta"</string>
<string name="number_picker_increment_button" msgid="4830170763103463443">"Incremento"</string>
<string name="number_picker_decrement_button" msgid="2576606679160067262">"Decremento"</string>
+ <string name="action_bar_home_description" msgid="5293600496601490216">"Desplazarse hasta la página principal"</string>
+ <string name="action_bar_up_description" msgid="2237496562952152589">"Desplazarse hacia arriba"</string>
+ <string name="action_menu_overflow_description" msgid="2295659037509008453">"Más opciones"</string>
+ <!-- no translation found for storage_internal (7556050805474115618) -->
+ <skip />
+ <!-- no translation found for storage_sd_card (8921771478629812343) -->
+ <skip />
+ <!-- no translation found for storage_usb (3017954059538517278) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-es/strings.xml b/core/res/res/values-es/strings.xml
index 7e9c55f..9973f0b 100644
--- a/core/res/res/values-es/strings.xml
+++ b/core/res/res/values-es/strings.xml
@@ -240,6 +240,10 @@
<string name="permdesc_batteryStats" msgid="5847319823772230560">"Permite la modificación de estadísticas recopiladas sobre la batería. No está destinado al uso por parte de aplicaciones normales."</string>
<string name="permlab_backup" msgid="470013022865453920">"controlar las copias de seguridad y las restauraciones del sistema"</string>
<string name="permdesc_backup" msgid="4837493065154256525">"Permite que la aplicación controle el mecanismo de copia de seguridad y restauración del sistema. Este permiso no está destinado a aplicaciones normales."</string>
+ <!-- no translation found for permlab_confirm_full_backup (5557071325804469102) -->
+ <skip />
+ <!-- no translation found for permdesc_confirm_full_backup (9005017754175897954) -->
+ <skip />
<string name="permlab_internalSystemWindow" msgid="2148563628140193231">"mostrar ventanas no autorizadas"</string>
<string name="permdesc_internalSystemWindow" msgid="5895082268284998469">"Permite la creación de ventanas destinadas al uso por parte de la interfaz de usuario interna del sistema. No está destinado al uso por parte de aplicaciones normales."</string>
<string name="permlab_systemAlertWindow" msgid="3372321942941168324">"mostrar alertas de nivel del sistema"</string>
@@ -446,6 +450,10 @@
<string name="permdesc_bluetooth" product="default" msgid="762515380679392945">"Permite que una aplicación vea la configuración del teléfono Bluetooth local, y cree y acepte conexiones con los dispositivos sincronizados."</string>
<string name="permlab_nfc" msgid="4423351274757876953">"controlar Comunicación de campo cercano (NFC)"</string>
<string name="permdesc_nfc" msgid="9171401851954407226">"Permite que la aplicación se comunique con lectores, tarjetas y etiquetas de Comunicación de campo cercano (NFC)."</string>
+ <!-- no translation found for permlab_vpn (8345800584532175312) -->
+ <skip />
+ <!-- no translation found for permdesc_vpn (5617893078989944219) -->
+ <skip />
<string name="permlab_disableKeyguard" msgid="4977406164311535092">"inhabilitar bloqueo del teclado"</string>
<string name="permdesc_disableKeyguard" msgid="3189763479326302017">"Permite que una aplicación inhabilite el bloqueo del teclado y cualquier protección con contraseña asociada. Un ejemplo legítimo de este permiso es la inhabilitación por parte del teléfono del bloqueo del teclado cuando recibe 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>
@@ -1019,4 +1027,13 @@
<string name="choose_account_label" msgid="4191313562041125787">"Seleccionar una cuenta"</string>
<string name="number_picker_increment_button" msgid="4830170763103463443">"Aumentar"</string>
<string name="number_picker_decrement_button" msgid="2576606679160067262">"Disminuir"</string>
+ <string name="action_bar_home_description" msgid="5293600496601490216">"Ir al escritorio"</string>
+ <string name="action_bar_up_description" msgid="2237496562952152589">"Desplazarse hacia arriba"</string>
+ <string name="action_menu_overflow_description" msgid="2295659037509008453">"Más opciones"</string>
+ <!-- no translation found for storage_internal (7556050805474115618) -->
+ <skip />
+ <!-- no translation found for storage_sd_card (8921771478629812343) -->
+ <skip />
+ <!-- no translation found for storage_usb (3017954059538517278) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-fa/strings.xml b/core/res/res/values-fa/strings.xml
index 07c3785..7842216 100644
--- a/core/res/res/values-fa/strings.xml
+++ b/core/res/res/values-fa/strings.xml
@@ -240,6 +240,10 @@
<string name="permdesc_batteryStats" msgid="5847319823772230560">"امکان تغییر اطلاعات جمع آوری شده مربوط به باتری را فراهم می آورد. برای استفاده با برنامه های معمولی در نظر گرفته نشده است."</string>
<string name="permlab_backup" msgid="470013022865453920">"کنترل نسخه پشتیبان سیستم و بازیابی"</string>
<string name="permdesc_backup" msgid="4837493065154256525">"به برنامه کاربردی اجازه می دهد نسخه پشتیبان سیستم را کنترل کرده و مکانیسم آن را بازیابی کند. برای استفاده با برنامه های معمولی در نظر گرفته نشده است."</string>
+ <!-- no translation found for permlab_confirm_full_backup (5557071325804469102) -->
+ <skip />
+ <!-- no translation found for permdesc_confirm_full_backup (9005017754175897954) -->
+ <skip />
<string name="permlab_internalSystemWindow" msgid="2148563628140193231">"نمایش پنجره های غیرمجاز"</string>
<string name="permdesc_internalSystemWindow" msgid="5895082268284998469">"اجازه می دهد پنجره هایی ایجاد شوند که برای استفاده توسط رابط کاربر سیستم داخلی در نظر گرفته شده است. برای استفاده با برنامه های معمولی در نظر گرفته نشده است."</string>
<string name="permlab_systemAlertWindow" msgid="3372321942941168324">"هشدارهای سطح سیستم نمایش"</string>
@@ -446,6 +450,10 @@
<string name="permdesc_bluetooth" product="default" msgid="762515380679392945">"به یک برنامه کاربردی اجازه می دهد تا پیکربندی تلفن بلوتوث محلی را مشاهده کند، اتصال ها را با دستگاه های جفت شده برقرار کرده، آنها را بپذیرد."</string>
<string name="permlab_nfc" msgid="4423351274757876953">"کنترل ارتباط راه نزدیک"</string>
<string name="permdesc_nfc" msgid="9171401851954407226">"به یک برنامه کاربردی برای ارتباط با برچسب های ارتباط راه نزدیک (NFC)، کارت ها و خواننده ها اجازه می دهد."</string>
+ <!-- no translation found for permlab_vpn (8345800584532175312) -->
+ <skip />
+ <!-- no translation found for permdesc_vpn (5617893078989944219) -->
+ <skip />
<string name="permlab_disableKeyguard" msgid="4977406164311535092">"غیرفعال کردن قفل کلید"</string>
<string name="permdesc_disableKeyguard" msgid="3189763479326302017">"به یک برنامه کاربردی اجازه می دهد قفل کلید و حفاظت رمز ورود همراه با کلیه کلیدها را غیرفعال کند. یک نمونه قانونی از این مورد، غیرفعال شدن قفل کلید در هنگام دریافت تماس تلفنی و سپس فعال کردن قفل کلید پس از پایان تماس است."</string>
<string name="permlab_readSyncSettings" msgid="6201810008230503052">"خواندن تنظیمات همگام سازی"</string>
@@ -1019,4 +1027,13 @@
<string name="choose_account_label" msgid="4191313562041125787">"انتخاب یک حساب"</string>
<string name="number_picker_increment_button" msgid="4830170763103463443">"افزایش"</string>
<string name="number_picker_decrement_button" msgid="2576606679160067262">"کاهش"</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>
+ <!-- no translation found for storage_internal (7556050805474115618) -->
+ <skip />
+ <!-- no translation found for storage_sd_card (8921771478629812343) -->
+ <skip />
+ <!-- no translation found for storage_usb (3017954059538517278) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-fi/strings.xml b/core/res/res/values-fi/strings.xml
index cb47f70..631da31 100644
--- a/core/res/res/values-fi/strings.xml
+++ b/core/res/res/values-fi/strings.xml
@@ -240,6 +240,10 @@
<string name="permdesc_batteryStats" msgid="5847319823772230560">"Antaa sovelluksen muuttaa kerättyjä akkutietoja. Ei tavallisten sovelluksien käyttöön."</string>
<string name="permlab_backup" msgid="470013022865453920">"hallitse järjestelmän varmuuskopiointia ja palauttamista"</string>
<string name="permdesc_backup" msgid="4837493065154256525">"Antaa sovelluksen hallita järjestelmän varmuuskopio- ja palautusmekanismeja. Ei tavallisten sovelluksien käyttöön."</string>
+ <!-- no translation found for permlab_confirm_full_backup (5557071325804469102) -->
+ <skip />
+ <!-- no translation found for permdesc_confirm_full_backup (9005017754175897954) -->
+ <skip />
<string name="permlab_internalSystemWindow" msgid="2148563628140193231">"näytä luvattomia ikkunoita"</string>
<string name="permdesc_internalSystemWindow" msgid="5895082268284998469">"Antaa sovelluksen luoda ikkunoita, jotka on tarkoitettu sisäisen järjestelmän käyttöliittymän käyttöön. Ei tavallisten sovelluksien käyttöön."</string>
<string name="permlab_systemAlertWindow" msgid="3372321942941168324">"näytä järjestelmätason ilmoituksia"</string>
@@ -446,6 +450,10 @@
<string name="permdesc_bluetooth" product="default" msgid="762515380679392945">"Antaa sovelluksen tarkastella paikallisen Bluetooth-puhelimen asetuksia sekä muodostaa ja hyväksyä laitepariyhteyksiä muihin laitteisiin."</string>
<string name="permlab_nfc" msgid="4423351274757876953">"hallitse Near Field Communication -tunnistusta"</string>
<string name="permdesc_nfc" msgid="9171401851954407226">"Antaa sovelluksen viestiä Near Field Communication (NFC) -tunnisteiden, -korttien ja -lukijoiden kanssa."</string>
+ <!-- no translation found for permlab_vpn (8345800584532175312) -->
+ <skip />
+ <!-- no translation found for permdesc_vpn (5617893078989944219) -->
+ <skip />
<string name="permlab_disableKeyguard" msgid="4977406164311535092">"poista näppäinlukitus käytöstä"</string>
<string name="permdesc_disableKeyguard" msgid="3189763479326302017">"Antaa sovelluksen poistaa näppäinlukituksen ja siihen liittyvän salasanasuojauksen käytöstä. Esimerkki: puhelin poistaa näppäinlukituksen käytöstä saapuvan puhelun yhteydessä ja ottaa näppäinlukituksen takaisin käyttöön puhelun päätyttyä."</string>
<string name="permlab_readSyncSettings" msgid="6201810008230503052">"lue synkronointiasetuksia"</string>
@@ -1019,4 +1027,13 @@
<string name="choose_account_label" msgid="4191313562041125787">"Valitse tili"</string>
<string name="number_picker_increment_button" msgid="4830170763103463443">"Lisää"</string>
<string name="number_picker_decrement_button" msgid="2576606679160067262">"Vähennä"</string>
+ <string name="action_bar_home_description" msgid="5293600496601490216">"Siirry etusivulle"</string>
+ <string name="action_bar_up_description" msgid="2237496562952152589">"Siirry ylös"</string>
+ <string name="action_menu_overflow_description" msgid="2295659037509008453">"Lisää asetuksia"</string>
+ <!-- no translation found for storage_internal (7556050805474115618) -->
+ <skip />
+ <!-- no translation found for storage_sd_card (8921771478629812343) -->
+ <skip />
+ <!-- no translation found for storage_usb (3017954059538517278) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-fr/strings.xml b/core/res/res/values-fr/strings.xml
index f44421c..1160ab4 100644
--- a/core/res/res/values-fr/strings.xml
+++ b/core/res/res/values-fr/strings.xml
@@ -240,6 +240,10 @@
<string name="permdesc_batteryStats" msgid="5847319823772230560">"Autoriser la modification des statistiques de la batterie. Les applications normales n\'utilisent pas cette fonctionnalité."</string>
<string name="permlab_backup" msgid="470013022865453920">"contrôler la sauvegarde et la restauration du système"</string>
<string name="permdesc_backup" msgid="4837493065154256525">"Autorise l\'application à contrôler le mécanisme de sauvegarde et de restauration du système. Ne pas utiliser pour les applications standard."</string>
+ <!-- no translation found for permlab_confirm_full_backup (5557071325804469102) -->
+ <skip />
+ <!-- no translation found for permdesc_confirm_full_backup (9005017754175897954) -->
+ <skip />
<string name="permlab_internalSystemWindow" msgid="2148563628140193231">"Affichage de fenêtres non autorisées"</string>
<string name="permdesc_internalSystemWindow" msgid="5895082268284998469">"Permet de créer des fenêtres conçues pour l\'interface utilisateur du système interne. Les applications normales n\'utilisent pas cette fonctionnalité."</string>
<string name="permlab_systemAlertWindow" msgid="3372321942941168324">"Affichage d\'alertes système"</string>
@@ -446,6 +450,10 @@
<string name="permdesc_bluetooth" product="default" msgid="762515380679392945">"Permet à une application d\'obtenir la configuration du téléphone Bluetooth local, de se connecter à des appareils associés et d\'accepter leur connexion."</string>
<string name="permlab_nfc" msgid="4423351274757876953">"contrôler la communication en champ proche"</string>
<string name="permdesc_nfc" msgid="9171401851954407226">"Permet à une application de communiquer avec des tags, cartes et lecteurs prenant en charge la communication en champ proche (NFC)."</string>
+ <!-- no translation found for permlab_vpn (8345800584532175312) -->
+ <skip />
+ <!-- no translation found for permdesc_vpn (5617893078989944219) -->
+ <skip />
<string name="permlab_disableKeyguard" msgid="4977406164311535092">"Désactivation du verrouillage des touches"</string>
<string name="permdesc_disableKeyguard" msgid="3189763479326302017">"Permet à une application de désactiver le verrouillage des touches et toute sécurité par mot de passe. Exemple : Votre téléphone désactive le verrouillage du clavier lorsque vous recevez un appel, puis le réactive lorsque vous raccrochez."</string>
<string name="permlab_readSyncSettings" msgid="6201810008230503052">"Lecture des paramètres de synchronisation"</string>
@@ -1019,4 +1027,13 @@
<string name="choose_account_label" msgid="4191313562041125787">"Sélectionner un compte"</string>
<string name="number_picker_increment_button" msgid="4830170763103463443">"Augmenter"</string>
<string name="number_picker_decrement_button" msgid="2576606679160067262">"Diminuer"</string>
+ <string name="action_bar_home_description" msgid="5293600496601490216">"Retour à l\'accueil"</string>
+ <string name="action_bar_up_description" msgid="2237496562952152589">"Revenir en haut de la page"</string>
+ <string name="action_menu_overflow_description" msgid="2295659037509008453">"Plus d\'options"</string>
+ <!-- no translation found for storage_internal (7556050805474115618) -->
+ <skip />
+ <!-- no translation found for storage_sd_card (8921771478629812343) -->
+ <skip />
+ <!-- no translation found for storage_usb (3017954059538517278) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-h720dp/dimens.xml b/core/res/res/values-h720dp/dimens.xml
new file mode 100644
index 0000000..7f43946
--- /dev/null
+++ b/core/res/res/values-h720dp/dimens.xml
@@ -0,0 +1,24 @@
+<?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.
+*/
+-->
+<resources>
+ <!-- Dialog title height -->
+ <dimen name="alert_dialog_title_height">54dip</dimen>
+ <!-- Dialog button bar height -->
+ <dimen name="alert_dialog_button_bar_height">54dip</dimen>
+</resources>
diff --git a/core/res/res/values-hr/strings.xml b/core/res/res/values-hr/strings.xml
index 33af403a..cf3f502 100644
--- a/core/res/res/values-hr/strings.xml
+++ b/core/res/res/values-hr/strings.xml
@@ -240,6 +240,10 @@
<string name="permdesc_batteryStats" msgid="5847319823772230560">"Omogućuje izmjenu prikupljene statistike o bateriji. Nije za upotrebu na uobičajenim aplikacijama."</string>
<string name="permlab_backup" msgid="470013022865453920">"sigurnosna kopija i oporavak nadzornog sustava"</string>
<string name="permdesc_backup" msgid="4837493065154256525">"Aplikaciji omogućuje nadzor nad mehanizmom stvaranja sigurnosnih kopija i oporavka sustava. Nije za upotrebu na uobičajenim aplikacijama."</string>
+ <!-- no translation found for permlab_confirm_full_backup (5557071325804469102) -->
+ <skip />
+ <!-- no translation found for permdesc_confirm_full_backup (9005017754175897954) -->
+ <skip />
<string name="permlab_internalSystemWindow" msgid="2148563628140193231">"prikaz neovlaštenih prozora"</string>
<string name="permdesc_internalSystemWindow" msgid="5895082268284998469">"Omogućuje stvaranje prozora kojima je namjena da se koriste u korisničkom sučelju internog sustava. Nije za upotrebu na uobičajenim aplikacijama."</string>
<string name="permlab_systemAlertWindow" msgid="3372321942941168324">"prikaz upozorenja na razini sustava"</string>
@@ -446,6 +450,10 @@
<string name="permdesc_bluetooth" product="default" msgid="762515380679392945">"Aplikaciji omogućuje pregled konfiguracije lokalnog Bluetooth telefona i uspostavljanje i prihvaćanje veza sa sparenim uređajima."</string>
<string name="permlab_nfc" msgid="4423351274757876953">"upravljaj beskontaktnom (NFC) komunikacijom"</string>
<string name="permdesc_nfc" msgid="9171401851954407226">"Aplikaciji omogućuje komunikaciju s Near Field Communication (NFC) oznakama, karticama i čitačima."</string>
+ <!-- no translation found for permlab_vpn (8345800584532175312) -->
+ <skip />
+ <!-- no translation found for permdesc_vpn (5617893078989944219) -->
+ <skip />
<string name="permlab_disableKeyguard" msgid="4977406164311535092">"onemogući zaključavanje tipkovnice"</string>
<string name="permdesc_disableKeyguard" msgid="3189763479326302017">"Aplikaciji omogućuje isključivanje zaključavanja tipkovnice i svih povezanih sigurnosnih zaporki. Jasan primjer toga daje isključivanje zaključavanja telefona kod primanja poziva, koje se ponovno aktivira nakon završetka poziva."</string>
<string name="permlab_readSyncSettings" msgid="6201810008230503052">"čitanje postavki sinkronizacije"</string>
@@ -1019,4 +1027,13 @@
<string name="choose_account_label" msgid="4191313562041125787">"Odaberite račun"</string>
<string name="number_picker_increment_button" msgid="4830170763103463443">"Povećaj"</string>
<string name="number_picker_decrement_button" msgid="2576606679160067262">"Smanji"</string>
+ <string name="action_bar_home_description" msgid="5293600496601490216">"Kreni na početnu"</string>
+ <string name="action_bar_up_description" msgid="2237496562952152589">"Kreni gore"</string>
+ <string name="action_menu_overflow_description" msgid="2295659037509008453">"Više opcija"</string>
+ <!-- no translation found for storage_internal (7556050805474115618) -->
+ <skip />
+ <!-- no translation found for storage_sd_card (8921771478629812343) -->
+ <skip />
+ <!-- no translation found for storage_usb (3017954059538517278) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-hu/strings.xml b/core/res/res/values-hu/strings.xml
index e260c85..340c2f9 100644
--- a/core/res/res/values-hu/strings.xml
+++ b/core/res/res/values-hu/strings.xml
@@ -240,6 +240,10 @@
<string name="permdesc_batteryStats" msgid="5847319823772230560">"Lehetővé teszi a begyűjtött akkumulátoradatok módosítását. A normál alkalmazások nem használják ezt."</string>
<string name="permlab_backup" msgid="470013022865453920">"rendszer biztonsági mentésének és helyreállításának vezérlése"</string>
<string name="permdesc_backup" msgid="4837493065154256525">"Lehetővé teszi az alkalmazás számára a rendszer biztonsági mentési és helyreállítási mechanizmusának vezérlését. A normál alkalmazások nem használják ezt."</string>
+ <!-- no translation found for permlab_confirm_full_backup (5557071325804469102) -->
+ <skip />
+ <!-- no translation found for permdesc_confirm_full_backup (9005017754175897954) -->
+ <skip />
<string name="permlab_internalSystemWindow" msgid="2148563628140193231">"azonosítatlan ablakok megjelenítése"</string>
<string name="permdesc_internalSystemWindow" msgid="5895082268284998469">"Lehetővé teszi olyan ablakok létrehozását, amelyeket a belső rendszer felhasználói felülete általi használatra szántak. A normál alkalmazások nem használják ezt."</string>
<string name="permlab_systemAlertWindow" msgid="3372321942941168324">"rendszerszintű riasztások megjelenítése"</string>
@@ -446,6 +450,10 @@
<string name="permdesc_bluetooth" product="default" msgid="762515380679392945">"Lehetővé teszi egy alkalmazás számára a helyi Bluetooth telefon konfigurációjának megtekintését, valamint kapcsolatok kezdeményezését és fogadását a párosított eszközökkel."</string>
<string name="permlab_nfc" msgid="4423351274757876953">"NFC technológia vezérlése"</string>
<string name="permdesc_nfc" msgid="9171401851954407226">"Lehetővé teszi az alkalmazások számára, hogy NFC (Near Field Communication - kis hatósugarú vezeték nélküli kommunikáció) technológiát használó címkékkel, kártyákkal és leolvasókkal kommunikáljanak."</string>
+ <!-- no translation found for permlab_vpn (8345800584532175312) -->
+ <skip />
+ <!-- no translation found for permdesc_vpn (5617893078989944219) -->
+ <skip />
<string name="permlab_disableKeyguard" msgid="4977406164311535092">"billentyűzár kikapcsolása"</string>
<string name="permdesc_disableKeyguard" msgid="3189763479326302017">"Lehetővé teszi egy alkalmazás számára a billentyűzár és a kapcsolódó jelszavas biztonság kikapcsolását. Ennek egy szabályos példája, amikor a telefon kikapcsolja a billentyűzárat egy beérkező hívás fogadásakor, majd a hívás befejezése után újra bekapcsolja azt."</string>
<string name="permlab_readSyncSettings" msgid="6201810008230503052">"szinkronizálási beállítások olvasása"</string>
@@ -1019,4 +1027,13 @@
<string name="choose_account_label" msgid="4191313562041125787">"Fiók kiválasztása"</string>
<string name="number_picker_increment_button" msgid="4830170763103463443">"Növelés"</string>
<string name="number_picker_decrement_button" msgid="2576606679160067262">"Csökkentés"</string>
+ <string name="action_bar_home_description" msgid="5293600496601490216">"Ugrás a főoldalra"</string>
+ <string name="action_bar_up_description" msgid="2237496562952152589">"Felfele mozgás"</string>
+ <string name="action_menu_overflow_description" msgid="2295659037509008453">"További lehetőségek"</string>
+ <!-- no translation found for storage_internal (7556050805474115618) -->
+ <skip />
+ <!-- no translation found for storage_sd_card (8921771478629812343) -->
+ <skip />
+ <!-- no translation found for storage_usb (3017954059538517278) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-in/strings.xml b/core/res/res/values-in/strings.xml
index d57cc32..d224384 100644
--- a/core/res/res/values-in/strings.xml
+++ b/core/res/res/values-in/strings.xml
@@ -240,6 +240,10 @@
<string name="permdesc_batteryStats" msgid="5847319823772230560">"Mengizinkan modifikasi statistik baterai yang terkumpul. Tidak untuk digunakan untuk aplikasi normal."</string>
<string name="permlab_backup" msgid="470013022865453920">"mengontrol cadangan dan pemulihan sistem"</string>
<string name="permdesc_backup" msgid="4837493065154256525">"Mengizinkan aplikasi mengontrol cadangan sistem dan mengembalikan mekanisme. Tidak untuk digunakan oleh aplikasi normal."</string>
+ <!-- no translation found for permlab_confirm_full_backup (5557071325804469102) -->
+ <skip />
+ <!-- no translation found for permdesc_confirm_full_backup (9005017754175897954) -->
+ <skip />
<string name="permlab_internalSystemWindow" msgid="2148563628140193231">"tampilkan jendela yang tidak diizinkan"</string>
<string name="permdesc_internalSystemWindow" msgid="5895082268284998469">"Mengizinkan pembuatan jendela yang dimaksudkan untuk digunakan oleh antarmuka pengguna sistem internal. Bukan untuk digunakan oleh aplikasi normal."</string>
<string name="permlab_systemAlertWindow" msgid="3372321942941168324">"tampilkan lansiran tingkat sistem"</string>
@@ -446,6 +450,10 @@
<string name="permdesc_bluetooth" product="default" msgid="762515380679392945">"Mengizinkan aplikasi melihat konfigurasi ponsel Bluetooth lokal, dan membuat dan menerima panggilan dengan perangkat yang disandingkan."</string>
<string name="permlab_nfc" msgid="4423351274757876953">"kontrol NFC"</string>
<string name="permdesc_nfc" msgid="9171401851954407226">"Mengizinkan aplikasi berkomunikasi dengan tag, kartu, dan pembaca Near Field Communication (NFC)."</string>
+ <!-- no translation found for permlab_vpn (8345800584532175312) -->
+ <skip />
+ <!-- no translation found for permdesc_vpn (5617893078989944219) -->
+ <skip />
<string name="permlab_disableKeyguard" msgid="4977406164311535092">"nonaktifkan kunci tombol"</string>
<string name="permdesc_disableKeyguard" msgid="3189763479326302017">"Mengizinkan aplikasi menonaktifkan keylock dan keamanan sandi terkait mana pun. Contoh yang sah adalah ponsel menonaktifkan keylock ketika menerima panggilan telepon masuk, kemudian mengaktifkan keylock sekali lagi setelah panggilan selesai."</string>
<string name="permlab_readSyncSettings" msgid="6201810008230503052">"baca setelan sinkron"</string>
@@ -1019,4 +1027,13 @@
<string name="choose_account_label" msgid="4191313562041125787">"Pilih akun"</string>
<string name="number_picker_increment_button" msgid="4830170763103463443">"Penambahan"</string>
<string name="number_picker_decrement_button" msgid="2576606679160067262">"Pengurangan"</string>
+ <string name="action_bar_home_description" msgid="5293600496601490216">"Navigasi ke beranda"</string>
+ <string name="action_bar_up_description" msgid="2237496562952152589">"Navigasi naik"</string>
+ <string name="action_menu_overflow_description" msgid="2295659037509008453">"Opsi lainnya"</string>
+ <!-- no translation found for storage_internal (7556050805474115618) -->
+ <skip />
+ <!-- no translation found for storage_sd_card (8921771478629812343) -->
+ <skip />
+ <!-- no translation found for storage_usb (3017954059538517278) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-it/strings.xml b/core/res/res/values-it/strings.xml
index 0c77120..eb450bb 100644
--- a/core/res/res/values-it/strings.xml
+++ b/core/res/res/values-it/strings.xml
@@ -240,6 +240,8 @@
<string name="permdesc_batteryStats" msgid="5847319823772230560">"Consente la modifica delle statistiche sulla batteria raccolte. Da non usare per normali applicazioni."</string>
<string name="permlab_backup" msgid="470013022865453920">"controllo del backup di sistema e ripristino"</string>
<string name="permdesc_backup" msgid="4837493065154256525">"Consente all\'applicazione di controllare il meccanismo di backup e ripristino del sistema. Da non usare per normali applicazioni."</string>
+ <string name="permlab_confirm_full_backup" msgid="5557071325804469102">"conferma di un\'operazione completa di backup o di ripristino"</string>
+ <string name="permdesc_confirm_full_backup" msgid="9005017754175897954">"Consente all\'applicazione di lanciare l\'interfaccia utente di conferma del backup completo. Non utilizzabile da qualsiasi applicazione."</string>
<string name="permlab_internalSystemWindow" msgid="2148563628140193231">"visualizzazione finestre non autorizzate"</string>
<string name="permdesc_internalSystemWindow" msgid="5895082268284998469">"Consente la creazione di finestre destinate all\'uso nell\'interfaccia utente di sistema interna. Da non usare per normali applicazioni."</string>
<string name="permlab_systemAlertWindow" msgid="3372321942941168324">"visualizzazione avvisi di sistema"</string>
@@ -446,6 +448,10 @@
<string name="permdesc_bluetooth" product="default" msgid="762515380679392945">"Consente a un\'applicazione di visualizzare la configurazione del telefono Bluetooth locale e di stabilire e accettare connessioni con dispositivi associati."</string>
<string name="permlab_nfc" msgid="4423351274757876953">"controllo Near Field Communication"</string>
<string name="permdesc_nfc" msgid="9171401851954407226">"Consente a un\'applicazione di comunicare con tag, schede e lettori NFC (Near Field Communication)."</string>
+ <!-- no translation found for permlab_vpn (8345800584532175312) -->
+ <skip />
+ <!-- no translation found for permdesc_vpn (5617893078989944219) -->
+ <skip />
<string name="permlab_disableKeyguard" msgid="4977406164311535092">"disattivazione blocco tastiera"</string>
<string name="permdesc_disableKeyguard" msgid="3189763479326302017">"Consente la disattivazione da parte di un\'applicazione del blocco tastiera e di eventuali protezioni tramite password associate. Un valido esempio è la disattivazione da parte del telefono del blocco tastiera quando riceve una telefonata in entrata, e la successiva riattivazione del blocco al termine della chiamata."</string>
<string name="permlab_readSyncSettings" msgid="6201810008230503052">"lettura impostazioni di sincronizz."</string>
@@ -1019,4 +1025,13 @@
<string name="choose_account_label" msgid="4191313562041125787">"Seleziona un account"</string>
<string name="number_picker_increment_button" msgid="4830170763103463443">"Aumenta"</string>
<string name="number_picker_decrement_button" msgid="2576606679160067262">"Diminuisci"</string>
+ <string name="action_bar_home_description" msgid="5293600496601490216">"Vai alla home page"</string>
+ <string name="action_bar_up_description" msgid="2237496562952152589">"Vai in alto"</string>
+ <string name="action_menu_overflow_description" msgid="2295659037509008453">"Altre opzioni"</string>
+ <!-- no translation found for storage_internal (7556050805474115618) -->
+ <skip />
+ <!-- no translation found for storage_sd_card (8921771478629812343) -->
+ <skip />
+ <!-- no translation found for storage_usb (3017954059538517278) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-iw/strings.xml b/core/res/res/values-iw/strings.xml
index 323d409..3f3ae23 100644
--- a/core/res/res/values-iw/strings.xml
+++ b/core/res/res/values-iw/strings.xml
@@ -240,6 +240,10 @@
<string name="permdesc_batteryStats" msgid="5847319823772230560">"מאפשר שינוי של נתונים סטטיסטיים הנאספים על הסוללה. לא לשימוש של יישומים רגילים."</string>
<string name="permlab_backup" msgid="470013022865453920">"שלוט בגיבוי ובשחזור של המערכת"</string>
<string name="permdesc_backup" msgid="4837493065154256525">"מאפשר ליישום לשלוט במנגנון הגיבוי והשחזור של המערכת. לא לשימוש של יישומים רגילים."</string>
+ <!-- no translation found for permlab_confirm_full_backup (5557071325804469102) -->
+ <skip />
+ <!-- no translation found for permdesc_confirm_full_backup (9005017754175897954) -->
+ <skip />
<string name="permlab_internalSystemWindow" msgid="2148563628140193231">"הצג חלונות לא מורשים"</string>
<string name="permdesc_internalSystemWindow" msgid="5895082268284998469">"מאפשר יצירת חלונות המיועדים לשימוש של ממשק המשתמש במערכת הפנימית. לא לשימוש של יישומים רגילים."</string>
<string name="permlab_systemAlertWindow" msgid="3372321942941168324">"הצג התראות ברמת המערכת"</string>
@@ -446,6 +450,10 @@
<string name="permdesc_bluetooth" product="default" msgid="762515380679392945">"מאפשר ליישום להציג תצורה של מכשיר Bluetooth המקומי, וליצור ולקבל חיבורים עם מכשירים מותאמים."</string>
<string name="permlab_nfc" msgid="4423351274757876953">"שלוט ב-Near Field Communication"</string>
<string name="permdesc_nfc" msgid="9171401851954407226">"מאפשר ליישום לקיים תקשורת עם תגיות, כרטיסים וקוראים מסוג Near Field Communication (NFC)."</string>
+ <!-- no translation found for permlab_vpn (8345800584532175312) -->
+ <skip />
+ <!-- no translation found for permdesc_vpn (5617893078989944219) -->
+ <skip />
<string name="permlab_disableKeyguard" msgid="4977406164311535092">"השבת נעילת מקשים"</string>
<string name="permdesc_disableKeyguard" msgid="3189763479326302017">"מאפשר ליישום להשבית את נעילת המקשים ואבטחת סיסמה משויכת. דוגמה תקפה לכך היא טלפון המשבית את נעילת המקשים בעת קבלת שיחת טלפון נכנסת, ולאחר מכן מפעיל מחדש את נעילת המקשים עם סיום השיחה."</string>
<string name="permlab_readSyncSettings" msgid="6201810008230503052">"קרא הגדרות סנכרון"</string>
@@ -1019,4 +1027,13 @@
<string name="choose_account_label" msgid="4191313562041125787">"בחר חשבון"</string>
<string name="number_picker_increment_button" msgid="4830170763103463443">"הוספה"</string>
<string name="number_picker_decrement_button" msgid="2576606679160067262">"הפחתה"</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>
+ <!-- no translation found for storage_internal (7556050805474115618) -->
+ <skip />
+ <!-- no translation found for storage_sd_card (8921771478629812343) -->
+ <skip />
+ <!-- no translation found for storage_usb (3017954059538517278) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-ja/strings.xml b/core/res/res/values-ja/strings.xml
index 7f88103..4563091 100644
--- a/core/res/res/values-ja/strings.xml
+++ b/core/res/res/values-ja/strings.xml
@@ -240,6 +240,10 @@
<string name="permdesc_batteryStats" msgid="5847319823772230560">"収集した電池統計情報の変更を許可します。通常のアプリケーションでは使用しません。"</string>
<string name="permlab_backup" msgid="470013022865453920">"システムのバックアップと復元を制御する"</string>
<string name="permdesc_backup" msgid="4837493065154256525">"システムのバックアップと復元メカニズムの制御をアプリケーションに許可します。通常のアプリケーションでは使用しません。"</string>
+ <!-- no translation found for permlab_confirm_full_backup (5557071325804469102) -->
+ <skip />
+ <!-- no translation found for permdesc_confirm_full_backup (9005017754175897954) -->
+ <skip />
<string name="permlab_internalSystemWindow" msgid="2148563628140193231">"未許可のウィンドウの表示"</string>
<string name="permdesc_internalSystemWindow" msgid="5895082268284998469">"内部システムのユーザーインターフェースで使用するためのウィンドウ作成を許可します。通常のアプリケーションでは使用しません。"</string>
<string name="permlab_systemAlertWindow" msgid="3372321942941168324">"システムレベルの警告の表示"</string>
@@ -446,6 +450,10 @@
<string name="permdesc_bluetooth" product="default" msgid="762515380679392945">"このBluetooth端末の設定表示、および別の端末をペアとして設定し接続を承認することをアプリケーションに許可します。"</string>
<string name="permlab_nfc" msgid="4423351274757876953">"NFCの管理"</string>
<string name="permdesc_nfc" msgid="9171401851954407226">"NFCタグ、カード、リーダーとの通信をアプリケーションに許可します。"</string>
+ <!-- no translation found for permlab_vpn (8345800584532175312) -->
+ <skip />
+ <!-- no translation found for permdesc_vpn (5617893078989944219) -->
+ <skip />
<string name="permlab_disableKeyguard" msgid="4977406164311535092">"キーロックを無効にする"</string>
<string name="permdesc_disableKeyguard" msgid="3189763479326302017">"キーロックや関連するパスワードセキュリティを無効にすることをアプリケーションに許可します。正当な利用の例では、かかってきた電話を受信する際にキーロックを無効にし、通話の終了時にキーロックを有効にし直します。"</string>
<string name="permlab_readSyncSettings" msgid="6201810008230503052">"同期設定の読み取り"</string>
@@ -1019,4 +1027,13 @@
<string name="choose_account_label" msgid="4191313562041125787">"アカウントを選択"</string>
<string name="number_picker_increment_button" msgid="4830170763103463443">"増やす"</string>
<string name="number_picker_decrement_button" msgid="2576606679160067262">"減らす"</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>
+ <!-- no translation found for storage_internal (7556050805474115618) -->
+ <skip />
+ <!-- no translation found for storage_sd_card (8921771478629812343) -->
+ <skip />
+ <!-- no translation found for storage_usb (3017954059538517278) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-ko/strings.xml b/core/res/res/values-ko/strings.xml
index dc83e3b..3d692ea 100644
--- a/core/res/res/values-ko/strings.xml
+++ b/core/res/res/values-ko/strings.xml
@@ -240,6 +240,10 @@
<string name="permdesc_batteryStats" msgid="5847319823772230560">"수집된 배터리 통계를 수정할 수 있도록 합니다. 일반 애플리케이션에서는 사용하지 않습니다."</string>
<string name="permlab_backup" msgid="470013022865453920">"시스템 백업 및 복원 관리"</string>
<string name="permdesc_backup" msgid="4837493065154256525">"애플리케이션이 시스템의 백업 및 복원 매커니즘을 제어할 수 있도록 합니다. 일반 애플리케이션에서는 사용하지 않습니다."</string>
+ <!-- no translation found for permlab_confirm_full_backup (5557071325804469102) -->
+ <skip />
+ <!-- no translation found for permdesc_confirm_full_backup (9005017754175897954) -->
+ <skip />
<string name="permlab_internalSystemWindow" msgid="2148563628140193231">"인증되지 않은 창 표시"</string>
<string name="permdesc_internalSystemWindow" msgid="5895082268284998469">"내부 시스템 사용자 인터페이스에서 사용하는 창을 만들 수 있도록 합니다. 일반 애플리케이션에서는 사용하지 않습니다."</string>
<string name="permlab_systemAlertWindow" msgid="3372321942941168324">"시스템 수준 경고 표시"</string>
@@ -446,6 +450,10 @@
<string name="permdesc_bluetooth" product="default" msgid="762515380679392945">"애플리케이션이 로컬 Bluetooth 전화의 구성을 보고 페어링된 장치에 연결하며 연결을 수락할 수 있도록 합니다."</string>
<string name="permlab_nfc" msgid="4423351274757876953">"NFC(Near Field Communication) 제어"</string>
<string name="permdesc_nfc" msgid="9171401851954407226">"애플리케이션에서 NFC(Near Field Communication) 태그, 카드 및 리더와 통신할 수 있습니다."</string>
+ <!-- no translation found for permlab_vpn (8345800584532175312) -->
+ <skip />
+ <!-- no translation found for permdesc_vpn (5617893078989944219) -->
+ <skip />
<string name="permlab_disableKeyguard" msgid="4977406164311535092">"키 잠금 사용 중지"</string>
<string name="permdesc_disableKeyguard" msgid="3189763479326302017">"애플리케이션이 키 잠금 및 관련 비밀번호 보안을 사용 중지할 수 있도록 합니다. 예를 들어, 휴대전화가 수신전화를 받을 때 키 잠금을 사용 중지했다가 통화가 끝나면 키 잠금을 다시 사용할 수 있습니다."</string>
<string name="permlab_readSyncSettings" msgid="6201810008230503052">"동기화 설정 읽기"</string>
@@ -1019,4 +1027,13 @@
<string name="choose_account_label" msgid="4191313562041125787">"계정 선택"</string>
<string name="number_picker_increment_button" msgid="4830170763103463443">"올리기"</string>
<string name="number_picker_decrement_button" msgid="2576606679160067262">"줄이기"</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>
+ <!-- no translation found for storage_internal (7556050805474115618) -->
+ <skip />
+ <!-- no translation found for storage_sd_card (8921771478629812343) -->
+ <skip />
+ <!-- no translation found for storage_usb (3017954059538517278) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-large/strings.xml b/core/res/res/values-large/strings.xml
new file mode 100644
index 0000000..e998b9a
--- /dev/null
+++ b/core/res/res/values-large/strings.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** 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.
+*/
+-->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+
+ <!-- Do not translate. WebView User Agent targeted content -->
+ <string name="web_user_agent_target_content" translatable="false"></string>
+
+</resources>
diff --git a/core/res/res/values-lt/strings.xml b/core/res/res/values-lt/strings.xml
index 883b6f3..69457ef 100644
--- a/core/res/res/values-lt/strings.xml
+++ b/core/res/res/values-lt/strings.xml
@@ -240,6 +240,10 @@
<string name="permdesc_batteryStats" msgid="5847319823772230560">"Leidžia keisti surinktą akumuliatoriaus statistiką. Neskirta įprastų programų naudojimui."</string>
<string name="permlab_backup" msgid="470013022865453920">"valdyti sistemos atsarginę kopiją ir atkūrimą"</string>
<string name="permdesc_backup" msgid="4837493065154256525">"Leidžia programai valdyti atsarginę sistemos kopiją ir atkurti mechanizmą. Neskirta naudoti įprastose programose."</string>
+ <!-- no translation found for permlab_confirm_full_backup (5557071325804469102) -->
+ <skip />
+ <!-- no translation found for permdesc_confirm_full_backup (9005017754175897954) -->
+ <skip />
<string name="permlab_internalSystemWindow" msgid="2148563628140193231">"pateikti neteisėtus langus"</string>
<string name="permdesc_internalSystemWindow" msgid="5895082268284998469">"Leidžia sukurti langus, kurie bus naudojami vidinės sistemos naudotojo sąsajos. Neskirta naudoti įprastose programose."</string>
<string name="permlab_systemAlertWindow" msgid="3372321942941168324">"pateikti sistemos lygio įspėjimus"</string>
@@ -446,6 +450,10 @@
<string name="permdesc_bluetooth" product="default" msgid="762515380679392945">"Leidžia programai žiūrėti vietinio „Bluetooth“ telefono konfigūraciją ir užmegzti bei priimti susietų įrenginių ryšius."</string>
<string name="permlab_nfc" msgid="4423351274757876953">"valdyti artimo lauko perdavimą (angl. „Near Field Communication“)"</string>
<string name="permdesc_nfc" msgid="9171401851954407226">"Leidžiama programai perduoti artimo lauko perdavimo (angl. „Near Field Communication“, NFC) žymas, korteles ir skaitymo programas."</string>
+ <!-- no translation found for permlab_vpn (8345800584532175312) -->
+ <skip />
+ <!-- no translation found for permdesc_vpn (5617893078989944219) -->
+ <skip />
<string name="permlab_disableKeyguard" msgid="4977406164311535092">"išjungti užraktą"</string>
<string name="permdesc_disableKeyguard" msgid="3189763479326302017">"Leidžia programai išjungti užraktą ir visą susijusią slaptažodžio apsaugą. Patikimas pavyzdys būtų užrakto išjungimas telefone gaunant įeinantį skambutį ir įgalinant jį vėl, kai skambutis baigtas."</string>
<string name="permlab_readSyncSettings" msgid="6201810008230503052">"skaityti sinchronizavimo nustatymus"</string>
@@ -1019,4 +1027,13 @@
<string name="choose_account_label" msgid="4191313562041125787">"Pasirinkti paskyrą"</string>
<string name="number_picker_increment_button" msgid="4830170763103463443">"Padidinti"</string>
<string name="number_picker_decrement_button" msgid="2576606679160067262">"Sumažinti"</string>
+ <string name="action_bar_home_description" msgid="5293600496601490216">"Naršyti pagrindinį puslapį"</string>
+ <string name="action_bar_up_description" msgid="2237496562952152589">"Naršyti į viršų"</string>
+ <string name="action_menu_overflow_description" msgid="2295659037509008453">"Daugiau parinkčių"</string>
+ <!-- no translation found for storage_internal (7556050805474115618) -->
+ <skip />
+ <!-- no translation found for storage_sd_card (8921771478629812343) -->
+ <skip />
+ <!-- no translation found for storage_usb (3017954059538517278) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-lv/strings.xml b/core/res/res/values-lv/strings.xml
index f4ecff7..e931728 100644
--- a/core/res/res/values-lv/strings.xml
+++ b/core/res/res/values-lv/strings.xml
@@ -240,6 +240,10 @@
<string name="permdesc_batteryStats" msgid="5847319823772230560">"Ļauj pārveidot apkopoto akumulatora jaudas statistiku. Nav paredzēts izmantošanai parastajās lietojumprogrammās."</string>
<string name="permlab_backup" msgid="470013022865453920">"kontrolēt sistēmas dublējumu un atjaunošanu"</string>
<string name="permdesc_backup" msgid="4837493065154256525">"Ļauj lietojumprogrammai kontrolēt sistēmas dublēšanas un atjaunošanas mehānismu. Nav paredzēts izmantošanai parastajās lietojumprogrammās."</string>
+ <!-- no translation found for permlab_confirm_full_backup (5557071325804469102) -->
+ <skip />
+ <!-- no translation found for permdesc_confirm_full_backup (9005017754175897954) -->
+ <skip />
<string name="permlab_internalSystemWindow" msgid="2148563628140193231">"attēlot neautorizētus logus"</string>
<string name="permdesc_internalSystemWindow" msgid="5895082268284998469">"Ļauj izveidot logus, kas ir paredzēti izmantošanai iekšējās sistēmas lietotāja saskarnē. Nav paredzēts izmantošanai parastajās lietojumprogrammās."</string>
<string name="permlab_systemAlertWindow" msgid="3372321942941168324">"rādīt sistēmas līmeņa brīdinājumus"</string>
@@ -446,6 +450,10 @@
<string name="permdesc_bluetooth" product="default" msgid="762515380679392945">"Ļauj lietojumprogrammai skatīt vietējā Bluetooth tālruņa konfigurāciju, kā arī veidot un pieņemt savienojumus ar pārī savienotām ierīcēm."</string>
<string name="permlab_nfc" msgid="4423351274757876953">"kontrolē tuvlauka saziņu"</string>
<string name="permdesc_nfc" msgid="9171401851954407226">"Ļauj lietojumprogrammai sazināties ar tuvlauka saziņas (Near Field Communication — NFC) atzīmēm, kartēm un lasītājiem."</string>
+ <!-- no translation found for permlab_vpn (8345800584532175312) -->
+ <skip />
+ <!-- no translation found for permdesc_vpn (5617893078989944219) -->
+ <skip />
<string name="permlab_disableKeyguard" msgid="4977406164311535092">"atspējot atslēgas slēgu"</string>
<string name="permdesc_disableKeyguard" msgid="3189763479326302017">"Ļauj lietojumprogrammai atspējot atslēgas slēgu un jebkādu saistīto paroles drošību. Atbilstošs tā piemērs: tālrunis atspējo atslēgas slēgu, saņemot ienākošu tālruņa zvanu, pēc tam atkārtoti iespējo atslēgas slēgu, kad saruna ir pabeigta."</string>
<string name="permlab_readSyncSettings" msgid="6201810008230503052">"lasīt sinhronizācijas iestatījumus"</string>
@@ -1019,4 +1027,13 @@
<string name="choose_account_label" msgid="4191313562041125787">"Atlasīt kontu"</string>
<string name="number_picker_increment_button" msgid="4830170763103463443">"Palielināt"</string>
<string name="number_picker_decrement_button" msgid="2576606679160067262">"Samazināt"</string>
+ <string name="action_bar_home_description" msgid="5293600496601490216">"Pārvietoties uz sākuma ekrānu"</string>
+ <string name="action_bar_up_description" msgid="2237496562952152589">"Pārvietoties augšup"</string>
+ <string name="action_menu_overflow_description" msgid="2295659037509008453">"Vairāk opciju"</string>
+ <!-- no translation found for storage_internal (7556050805474115618) -->
+ <skip />
+ <!-- no translation found for storage_sd_card (8921771478629812343) -->
+ <skip />
+ <!-- no translation found for storage_usb (3017954059538517278) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-nb/strings.xml b/core/res/res/values-nb/strings.xml
index b5c0c71..6fe5dd7 100644
--- a/core/res/res/values-nb/strings.xml
+++ b/core/res/res/values-nb/strings.xml
@@ -240,6 +240,10 @@
<string name="permdesc_batteryStats" msgid="5847319823772230560">"Lar applikasjonen endre på innsamlet batteristatistikk. Ikke ment for vanlige applikasjoner."</string>
<string name="permlab_backup" msgid="470013022865453920">"kontrollere backup og gjenoppretting"</string>
<string name="permdesc_backup" msgid="4837493065154256525">"Lar applikasjonen kontrollere systemets backup- og gjenopprettingsmekanisme. Ikke ment for vanlige applikasjoner."</string>
+ <!-- no translation found for permlab_confirm_full_backup (5557071325804469102) -->
+ <skip />
+ <!-- no translation found for permdesc_confirm_full_backup (9005017754175897954) -->
+ <skip />
<string name="permlab_internalSystemWindow" msgid="2148563628140193231">"vis uautoriserte vinduer"</string>
<string name="permdesc_internalSystemWindow" msgid="5895082268284998469">"Tillater at det opprettes vinduer ment for bruk av systemets interne brukergrensesnitt. Ikke ment for vanlige applikasjoner."</string>
<string name="permlab_systemAlertWindow" msgid="3372321942941168324">"vise advarsler på systemnivå"</string>
@@ -446,6 +450,10 @@
<string name="permdesc_bluetooth" product="default" msgid="762515380679392945">"Lar applikasjonen se konfigurasjonen til den lokale Bluetooth-telefonen, og å opprette og godta tilkoblinger med parede enheter."</string>
<string name="permlab_nfc" msgid="4423351274757876953">"kontroller overføring av data med NFC-teknologi"</string>
<string name="permdesc_nfc" msgid="9171401851954407226">"Tillater programmet å kommunisere data via koder, kort og lesere for NFC-teknologi."</string>
+ <!-- no translation found for permlab_vpn (8345800584532175312) -->
+ <skip />
+ <!-- no translation found for permdesc_vpn (5617893078989944219) -->
+ <skip />
<string name="permlab_disableKeyguard" msgid="4977406164311535092">"slå av tastaturlås"</string>
<string name="permdesc_disableKeyguard" msgid="3189763479326302017">"Lar applikasjonen slå av tastaturlåsen og enhver tilknyttet passordsikkerhet. Et legitimt eksempel på dette er at telefonen slår av tastaturlåsen når den mottar et innkommende anrop, og så slår den på igjen når samtalen er over."</string>
<string name="permlab_readSyncSettings" msgid="6201810008230503052">"lese synkroniseringsinnstillinger"</string>
@@ -951,7 +959,7 @@
<string name="create_contact_using" msgid="4947405226788104538">"Lag kontakt"\n"med nummeret <xliff:g id="NUMBER">%s</xliff:g>"</string>
<string name="grant_credentials_permission_message_header" msgid="6824538733852821001">"Ett eller flere av de følgende programmene ber om tillatelse til å få tilgang til kontoen din fra nå av."</string>
<string name="grant_credentials_permission_message_footer" msgid="3125211343379376561">"Vil du tillate dette?"</string>
- <string name="grant_permissions_header_text" msgid="2722567482180797717">"Få tilgang til forespørsler"</string>
+ <string name="grant_permissions_header_text" msgid="2722567482180797717">"Forespørsel om tilgang"</string>
<string name="allow" msgid="7225948811296386551">"Tillat"</string>
<string name="deny" msgid="2081879885755434506">"Avslå"</string>
<string name="permission_request_notification_title" msgid="5390555465778213840">"Tillatelse forespurt"</string>
@@ -1019,4 +1027,13 @@
<string name="choose_account_label" msgid="4191313562041125787">"Velg en konto"</string>
<string name="number_picker_increment_button" msgid="4830170763103463443">"Øke"</string>
<string name="number_picker_decrement_button" msgid="2576606679160067262">"Senke"</string>
+ <string name="action_bar_home_description" msgid="5293600496601490216">"Gå til startsiden"</string>
+ <string name="action_bar_up_description" msgid="2237496562952152589">"Gå opp"</string>
+ <string name="action_menu_overflow_description" msgid="2295659037509008453">"Flere alternativer"</string>
+ <!-- no translation found for storage_internal (7556050805474115618) -->
+ <skip />
+ <!-- no translation found for storage_sd_card (8921771478629812343) -->
+ <skip />
+ <!-- no translation found for storage_usb (3017954059538517278) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-nl/strings.xml b/core/res/res/values-nl/strings.xml
index f7eef3e..81fa796 100644
--- a/core/res/res/values-nl/strings.xml
+++ b/core/res/res/values-nl/strings.xml
@@ -240,6 +240,10 @@
<string name="permdesc_batteryStats" msgid="5847319823772230560">"Hiermee kunnen verzamelde accustatistieken worden gewijzigd. Niet voor gebruik door normale toepassingen."</string>
<string name="permlab_backup" msgid="470013022865453920">"systeemback-up en -herstel beheren"</string>
<string name="permdesc_backup" msgid="4837493065154256525">"Hiermee kan de app het mechanisme voor systeemback-up en -herstel beheren. Niet voor gebruik door normale apps."</string>
+ <!-- no translation found for permlab_confirm_full_backup (5557071325804469102) -->
+ <skip />
+ <!-- no translation found for permdesc_confirm_full_backup (9005017754175897954) -->
+ <skip />
<string name="permlab_internalSystemWindow" msgid="2148563628140193231">"niet-geautoriseerde vensters weergeven"</string>
<string name="permdesc_internalSystemWindow" msgid="5895082268284998469">"Hiermee kunnen vensters worden gemaakt die door de interne systeemgebruikersinterface worden gebruikt. Niet voor gebruik door normale toepassingen."</string>
<string name="permlab_systemAlertWindow" msgid="3372321942941168324">"waarschuwingen op systeemniveau weergeven"</string>
@@ -446,6 +450,10 @@
<string name="permdesc_bluetooth" product="default" msgid="762515380679392945">"Hiermee kan een app de configuratie van een lokale Bluetooth-telefoon bekijken en verbindingen met gekoppelde apparaten maken en accepteren."</string>
<string name="permlab_nfc" msgid="4423351274757876953">"Near Field Communication regelen"</string>
<string name="permdesc_nfc" msgid="9171401851954407226">"Hiermee kan een app communiceren met NFC-tags (Near Field Communication), kaarten en lezers."</string>
+ <!-- no translation found for permlab_vpn (8345800584532175312) -->
+ <skip />
+ <!-- no translation found for permdesc_vpn (5617893078989944219) -->
+ <skip />
<string name="permlab_disableKeyguard" msgid="4977406164311535092">"toetsvergrendeling uitschakelen"</string>
<string name="permdesc_disableKeyguard" msgid="3189763479326302017">"Hiermee kan een app de toetsvergrendeling en bijbehorende wachtwoordbeveiliging uitschakelen. Een voorbeeld: de telefoon schakelt de toetsvergrendeling uit wanneer een oproep binnenkomt en schakelt de toetsvergrendeling weer in zodra de oproep wordt beëindigd."</string>
<string name="permlab_readSyncSettings" msgid="6201810008230503052">"synchronisatie-instellingen lezen"</string>
@@ -1019,4 +1027,13 @@
<string name="choose_account_label" msgid="4191313562041125787">"Selecteer een account"</string>
<string name="number_picker_increment_button" msgid="4830170763103463443">"Hoger"</string>
<string name="number_picker_decrement_button" msgid="2576606679160067262">"Lager"</string>
+ <string name="action_bar_home_description" msgid="5293600496601490216">"Navigeren naar startpositie"</string>
+ <string name="action_bar_up_description" msgid="2237496562952152589">"Omhoog navigeren"</string>
+ <string name="action_menu_overflow_description" msgid="2295659037509008453">"Meer opties"</string>
+ <!-- no translation found for storage_internal (7556050805474115618) -->
+ <skip />
+ <!-- no translation found for storage_sd_card (8921771478629812343) -->
+ <skip />
+ <!-- no translation found for storage_usb (3017954059538517278) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-pl/strings.xml b/core/res/res/values-pl/strings.xml
index 552ed0b..28a28a5 100644
--- a/core/res/res/values-pl/strings.xml
+++ b/core/res/res/values-pl/strings.xml
@@ -240,6 +240,10 @@
<string name="permdesc_batteryStats" msgid="5847319823772230560">"Pozwala na zmianę zebranych statystyk dotyczących baterii. Nie do wykorzystania przez normalne aplikacje."</string>
<string name="permlab_backup" msgid="470013022865453920">"kontrolowanie tworzenia i przywracania kopii zapasowych systemu"</string>
<string name="permdesc_backup" msgid="4837493065154256525">"Zezwala aplikacji na kontrolowanie mechanizmu tworzenia i przywracania kopii zapasowych systemu. Opcja nie jest przeznaczona dla zwykłych aplikacji."</string>
+ <!-- no translation found for permlab_confirm_full_backup (5557071325804469102) -->
+ <skip />
+ <!-- no translation found for permdesc_confirm_full_backup (9005017754175897954) -->
+ <skip />
<string name="permlab_internalSystemWindow" msgid="2148563628140193231">"wyświetlanie nieuwierzytelnionych okien"</string>
<string name="permdesc_internalSystemWindow" msgid="5895082268284998469">"Pozwala na tworzenie okien, które przeznaczone są do wykorzystania przez wewnętrzny interfejs użytkownika systemu. Nie do wykorzystania przez normalne aplikacje."</string>
<string name="permlab_systemAlertWindow" msgid="3372321942941168324">"wyświetlanie ostrzeżeń systemowych"</string>
@@ -446,6 +450,10 @@
<string name="permdesc_bluetooth" product="default" msgid="762515380679392945">"Pozwala aplikacji na wyświetlanie konfiguracji lokalnego telefonu Bluetooth oraz na tworzenie i akceptowanie połączeń ze sparowanymi urządzeniami."</string>
<string name="permlab_nfc" msgid="4423351274757876953">"kontrolowanie łączności Near Field Communication"</string>
<string name="permdesc_nfc" msgid="9171401851954407226">"Zezwala aplikacji na komunikowanie się z użyciem tagów, kart i czytników Near Field Communication (NFC)."</string>
+ <!-- no translation found for permlab_vpn (8345800584532175312) -->
+ <skip />
+ <!-- no translation found for permdesc_vpn (5617893078989944219) -->
+ <skip />
<string name="permlab_disableKeyguard" msgid="4977406164311535092">"wyłączanie blokady klawiatury"</string>
<string name="permdesc_disableKeyguard" msgid="3189763479326302017">"Pozwala aplikacji na wyłączenie blokady klawiatury i wszystkich związanych z tym haseł zabezpieczających. Typowym przykładem takiego działania jest wyłączanie blokady klawiatury, gdy pojawia się połączenie przychodzące, a następnie ponowne jej włączanie po zakończeniu połączenia."</string>
<string name="permlab_readSyncSettings" msgid="6201810008230503052">"czytanie ustawień synchronizowania"</string>
@@ -1019,4 +1027,13 @@
<string name="choose_account_label" msgid="4191313562041125787">"Wybierz konto"</string>
<string name="number_picker_increment_button" msgid="4830170763103463443">"Zwiększ"</string>
<string name="number_picker_decrement_button" msgid="2576606679160067262">"Zmniejsz"</string>
+ <string name="action_bar_home_description" msgid="5293600496601490216">"Przejdź do strony głównej"</string>
+ <string name="action_bar_up_description" msgid="2237496562952152589">"Przejdź wyżej"</string>
+ <string name="action_menu_overflow_description" msgid="2295659037509008453">"Więcej opcji"</string>
+ <!-- no translation found for storage_internal (7556050805474115618) -->
+ <skip />
+ <!-- no translation found for storage_sd_card (8921771478629812343) -->
+ <skip />
+ <!-- no translation found for storage_usb (3017954059538517278) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-pt-rPT/strings.xml b/core/res/res/values-pt-rPT/strings.xml
index c7282b5..e812d68 100644
--- a/core/res/res/values-pt-rPT/strings.xml
+++ b/core/res/res/values-pt-rPT/strings.xml
@@ -240,6 +240,10 @@
<string name="permdesc_batteryStats" msgid="5847319823772230560">"Permite a modificação das estatísticas recolhidas sobre a bateria. Não se destina a utilização por aplicações normais."</string>
<string name="permlab_backup" msgid="470013022865453920">"controlar a cópia de segurança e restauro do sistema"</string>
<string name="permdesc_backup" msgid="4837493065154256525">"Permite que a aplicação controle o mecanismo de cópia de segurança e restauro do sistema. Não deve ser utilizado por aplicações normais."</string>
+ <!-- no translation found for permlab_confirm_full_backup (5557071325804469102) -->
+ <skip />
+ <!-- no translation found for permdesc_confirm_full_backup (9005017754175897954) -->
+ <skip />
<string name="permlab_internalSystemWindow" msgid="2148563628140193231">"apresentar janelas não autorizadas"</string>
<string name="permdesc_internalSystemWindow" msgid="5895082268284998469">"Permite a criação de janelas destinadas a utilização pela interface de utilizador interna do sistema. Não se destina a utilização por aplicações normais."</string>
<string name="permlab_systemAlertWindow" msgid="3372321942941168324">"apresentar alertas ao nível do sistema"</string>
@@ -446,6 +450,10 @@
<string name="permdesc_bluetooth" product="default" msgid="762515380679392945">"Permite a uma aplicação ver a configuração do telefone Bluetooth local, bem como efectuar e aceitar ligações com dispositivos emparelhados."</string>
<string name="permlab_nfc" msgid="4423351274757876953">"controlo Near Field Communication"</string>
<string name="permdesc_nfc" msgid="9171401851954407226">"Permite que uma aplicação comunique com etiquetas, cartões e leitores Near Field Communication (NFC)."</string>
+ <!-- no translation found for permlab_vpn (8345800584532175312) -->
+ <skip />
+ <!-- no translation found for permdesc_vpn (5617893078989944219) -->
+ <skip />
<string name="permlab_disableKeyguard" msgid="4977406164311535092">"desactivar bloqueio de teclas"</string>
<string name="permdesc_disableKeyguard" msgid="3189763479326302017">"Permite a uma aplicação desactivar o bloqueio de teclas e qualquer segurança por palavra-passe associada. Um exemplo legítimo é a desactivação do bloqueio de teclas pelo telefone ao receber uma chamada, reactivando, em seguida, o bloqueio de teclas ao terminar a chamada."</string>
<string name="permlab_readSyncSettings" msgid="6201810008230503052">"ler definições de sincronização"</string>
@@ -1019,4 +1027,13 @@
<string name="choose_account_label" msgid="4191313562041125787">"Seleccionar conta"</string>
<string name="number_picker_increment_button" msgid="4830170763103463443">"Aumentar"</string>
<string name="number_picker_decrement_button" msgid="2576606679160067262">"Diminuir"</string>
+ <string name="action_bar_home_description" msgid="5293600496601490216">"Navegar para página inicial"</string>
+ <string name="action_bar_up_description" msgid="2237496562952152589">"Navegar para cima"</string>
+ <string name="action_menu_overflow_description" msgid="2295659037509008453">"Mais opções"</string>
+ <!-- no translation found for storage_internal (7556050805474115618) -->
+ <skip />
+ <!-- no translation found for storage_sd_card (8921771478629812343) -->
+ <skip />
+ <!-- no translation found for storage_usb (3017954059538517278) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-pt/strings.xml b/core/res/res/values-pt/strings.xml
index d459bb11..be6dcbe 100644
--- a/core/res/res/values-pt/strings.xml
+++ b/core/res/res/values-pt/strings.xml
@@ -240,6 +240,10 @@
<string name="permdesc_batteryStats" msgid="5847319823772230560">"Permite a modificação das estatísticas de bateria coletadas. Não deve ser usado por aplicativos normais."</string>
<string name="permlab_backup" msgid="470013022865453920">"controlar backup e restauração do sistema"</string>
<string name="permdesc_backup" msgid="4837493065154256525">"Permite que o aplicativo controle o mecanismo de backup e restauração do sistema. Não deve ser usado por aplicativos normais."</string>
+ <!-- no translation found for permlab_confirm_full_backup (5557071325804469102) -->
+ <skip />
+ <!-- no translation found for permdesc_confirm_full_backup (9005017754175897954) -->
+ <skip />
<string name="permlab_internalSystemWindow" msgid="2148563628140193231">"exibir janelas não autorizadas"</string>
<string name="permdesc_internalSystemWindow" msgid="5895082268284998469">"Permite a criação de janelas destinadas ao uso pela interface de usuário do sistema interno. Não deve ser usado por aplicativos normais."</string>
<string name="permlab_systemAlertWindow" msgid="3372321942941168324">"exibir alertas de nível do sistema"</string>
@@ -446,6 +450,10 @@
<string name="permdesc_bluetooth" product="default" msgid="762515380679392945">"Permite que um aplicativo veja a configuração do telefone Bluetooth local e que possa fazer e aceitar conexões com dispositivos pareados."</string>
<string name="permlab_nfc" msgid="4423351274757876953">"controlar a comunicação a curta distância"</string>
<string name="permdesc_nfc" msgid="9171401851954407226">"Permite que um aplicativo se comunique com tags, cartões e leitores de comunicação a curta distância (NFC)."</string>
+ <!-- no translation found for permlab_vpn (8345800584532175312) -->
+ <skip />
+ <!-- no translation found for permdesc_vpn (5617893078989944219) -->
+ <skip />
<string name="permlab_disableKeyguard" msgid="4977406164311535092">"desativar o bloqueio de teclas"</string>
<string name="permdesc_disableKeyguard" msgid="3189763479326302017">"Permite que um aplicativo desative o bloqueio de teclas e qualquer segurança por senha associada. Um exemplo legítimo disso é a desativação do bloqueio de teclas pelo telefone ao receber uma chamada e a reativação do bloqueio quando a chamada é finalizada."</string>
<string name="permlab_readSyncSettings" msgid="6201810008230503052">"ler as configurações de sincronização"</string>
@@ -1019,4 +1027,13 @@
<string name="choose_account_label" msgid="4191313562041125787">"Selecione uma conta"</string>
<string name="number_picker_increment_button" msgid="4830170763103463443">"Incremento"</string>
<string name="number_picker_decrement_button" msgid="2576606679160067262">"Redução"</string>
+ <string name="action_bar_home_description" msgid="5293600496601490216">"Navegar na página inicial"</string>
+ <string name="action_bar_up_description" msgid="2237496562952152589">"Navegar para cima"</string>
+ <string name="action_menu_overflow_description" msgid="2295659037509008453">"Mais opções"</string>
+ <!-- no translation found for storage_internal (7556050805474115618) -->
+ <skip />
+ <!-- no translation found for storage_sd_card (8921771478629812343) -->
+ <skip />
+ <!-- no translation found for storage_usb (3017954059538517278) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-rm/strings.xml b/core/res/res/values-rm/strings.xml
index 1f9a503..9865b47 100644
--- a/core/res/res/values-rm/strings.xml
+++ b/core/res/res/values-rm/strings.xml
@@ -246,6 +246,10 @@
<string name="permdesc_batteryStats" msgid="5847319823772230560">"Permetta da modifitgar las datas statisticas da l\'accu. Betg previs per applicaziuns normalas."</string>
<string name="permlab_backup" msgid="470013022865453920">"controllar las copias da segirezza e la restauraziun dal sistem"</string>
<string name="permdesc_backup" msgid="4837493065154256525">"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 permlab_confirm_full_backup (5557071325804469102) -->
+ <skip />
+ <!-- no translation found for permdesc_confirm_full_backup (9005017754175897954) -->
+ <skip />
<string name="permlab_internalSystemWindow" msgid="2148563628140193231">"mussar fanestras betg autorisadas"</string>
<string name="permdesc_internalSystemWindow" msgid="5895082268284998469">"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>
<string name="permlab_systemAlertWindow" msgid="3372321942941168324">"mussar avertiments dal sistem"</string>
@@ -460,6 +464,10 @@
<skip />
<!-- no translation found for permdesc_nfc (9171401851954407226) -->
<skip />
+ <!-- no translation found for permlab_vpn (8345800584532175312) -->
+ <skip />
+ <!-- no translation found for permdesc_vpn (5617893078989944219) -->
+ <skip />
<string name="permlab_disableKeyguard" msgid="4977406164311535092">"deactivar la bloccaziun da la tastatura"</string>
<string name="permdesc_disableKeyguard" msgid="3189763479326302017">"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>
<string name="permlab_readSyncSettings" msgid="6201810008230503052">"leger ils parameters da sincronisaziun"</string>
@@ -1115,4 +1123,16 @@
<skip />
<!-- no translation found for number_picker_decrement_button (2576606679160067262) -->
<skip />
+ <!-- no translation found for action_bar_home_description (5293600496601490216) -->
+ <skip />
+ <!-- no translation found for action_bar_up_description (2237496562952152589) -->
+ <skip />
+ <!-- no translation found for action_menu_overflow_description (2295659037509008453) -->
+ <skip />
+ <!-- no translation found for storage_internal (7556050805474115618) -->
+ <skip />
+ <!-- no translation found for storage_sd_card (8921771478629812343) -->
+ <skip />
+ <!-- no translation found for storage_usb (3017954059538517278) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-ro/strings.xml b/core/res/res/values-ro/strings.xml
index bf2eac9..0daabb8 100644
--- a/core/res/res/values-ro/strings.xml
+++ b/core/res/res/values-ro/strings.xml
@@ -240,6 +240,10 @@
<string name="permdesc_batteryStats" msgid="5847319823772230560">"Permite modificarea statisticilor colectate despre baterie. Nu se utilizează de aplicaţiile obişnuite."</string>
<string name="permlab_backup" msgid="470013022865453920">"controlare copiere de rezervă şi restabilire a sistemului"</string>
<string name="permdesc_backup" msgid="4837493065154256525">"Permite aplicaţiei să controleze mecanismul de copiere de rezervă şi restabilire. Nu se utilizează de aplicaţiile obişnuite."</string>
+ <!-- no translation found for permlab_confirm_full_backup (5557071325804469102) -->
+ <skip />
+ <!-- no translation found for permdesc_confirm_full_backup (9005017754175897954) -->
+ <skip />
<string name="permlab_internalSystemWindow" msgid="2148563628140193231">"afişare ferestre neautorizate"</string>
<string name="permdesc_internalSystemWindow" msgid="5895082268284998469">"Permite crearea de ferestre menite să fie utilizate de interfaţa utilizatorului a sistemului intern. Nu se utilizează de aplicaţiile obişnuite."</string>
<string name="permlab_systemAlertWindow" msgid="3372321942941168324">"afişare alerte la nivel de sistem"</string>
@@ -446,6 +450,10 @@
<string name="permdesc_bluetooth" product="default" msgid="762515380679392945">"Permite unei aplicaţii să vizualizeze configuraţia telefonului Bluetooth local, să efectueze şi să accepte conexiuni cu dispozitive pereche."</string>
<string name="permlab_nfc" msgid="4423351274757876953">"controlare schimb de date prin Near Field Communication"</string>
<string name="permdesc_nfc" msgid="9171401851954407226">"Permite unei aplicaţii să comunice cu etichetele, cardurile şi cititoarele NFC (Near Field Communication)."</string>
+ <!-- no translation found for permlab_vpn (8345800584532175312) -->
+ <skip />
+ <!-- no translation found for permdesc_vpn (5617893078989944219) -->
+ <skip />
<string name="permlab_disableKeyguard" msgid="4977406164311535092">"dezactivare blocare taste"</string>
<string name="permdesc_disableKeyguard" msgid="3189763479326302017">"Permite unei aplicaţii să dezactiveze blocarea tastelor şi orice modalitate asociată de securitate a parolelor. Un bun exemplu este deblocarea tastelor de către telefon atunci când se primeşte un apel şi reactivarea blocării tastelor la terminarea apelului."</string>
<string name="permlab_readSyncSettings" msgid="6201810008230503052">"citire setări sincronizare"</string>
@@ -1019,4 +1027,13 @@
<string name="choose_account_label" msgid="4191313562041125787">"Selectaţi un cont"</string>
<string name="number_picker_increment_button" msgid="4830170763103463443">"Incrementaţi"</string>
<string name="number_picker_decrement_button" msgid="2576606679160067262">"Decrementaţi"</string>
+ <string name="action_bar_home_description" msgid="5293600496601490216">"Navigaţi la ecranul de pornire"</string>
+ <string name="action_bar_up_description" msgid="2237496562952152589">"Navigaţi în sus"</string>
+ <string name="action_menu_overflow_description" msgid="2295659037509008453">"Mai multe opţiuni"</string>
+ <!-- no translation found for storage_internal (7556050805474115618) -->
+ <skip />
+ <!-- no translation found for storage_sd_card (8921771478629812343) -->
+ <skip />
+ <!-- no translation found for storage_usb (3017954059538517278) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-ru/strings.xml b/core/res/res/values-ru/strings.xml
index e51f1bd..083a044 100644
--- a/core/res/res/values-ru/strings.xml
+++ b/core/res/res/values-ru/strings.xml
@@ -240,6 +240,10 @@
<string name="permdesc_batteryStats" msgid="5847319823772230560">"Позволяет изменять собранную статистику батареи. Не предназначено для использования обычными приложениями."</string>
<string name="permlab_backup" msgid="470013022865453920">"управление резервным копированием и восстановлением системы"</string>
<string name="permdesc_backup" msgid="4837493065154256525">"Разрешает приложению контролировать механизмы резервного копирования и восстановления системы. Не используется обычными приложениями."</string>
+ <!-- no translation found for permlab_confirm_full_backup (5557071325804469102) -->
+ <skip />
+ <!-- no translation found for permdesc_confirm_full_backup (9005017754175897954) -->
+ <skip />
<string name="permlab_internalSystemWindow" msgid="2148563628140193231">"показывать неавторизованные окна"</string>
<string name="permdesc_internalSystemWindow" msgid="5895082268284998469">"Разрешает создание окон, предназначенных для использования внутренним пользовательским интерфейсом системы. Не предназначено для использования обычными приложениями."</string>
<string name="permlab_systemAlertWindow" msgid="3372321942941168324">"показывать оповещения системного уровня"</string>
@@ -446,6 +450,10 @@
<string name="permdesc_bluetooth" product="default" msgid="762515380679392945">"Позволяет приложению просматривать конфигурацию локального телефона Bluetooth, создавать подключения с сопряженными устройствами."</string>
<string name="permlab_nfc" msgid="4423351274757876953">"управлять радиосвязью ближнего действия"</string>
<string name="permdesc_nfc" msgid="9171401851954407226">"Позволяет приложению обмениваться данными с метками, картами и считывателями через радиосвязь ближнего действия (NFC)."</string>
+ <!-- no translation found for permlab_vpn (8345800584532175312) -->
+ <skip />
+ <!-- no translation found for permdesc_vpn (5617893078989944219) -->
+ <skip />
<string name="permlab_disableKeyguard" msgid="4977406164311535092">"отключать блокировку клавиатуры"</string>
<string name="permdesc_disableKeyguard" msgid="3189763479326302017">"Позволяет приложению отключить блокировку клавиатуры и другие функции защиты паролем. Примером допустимого использования этой функции является отключение блокировки клавиатуры при получении входящего вызова и включение блокировки после завершения разговора."</string>
<string name="permlab_readSyncSettings" msgid="6201810008230503052">"считывать настройки синхронизации"</string>
@@ -1019,4 +1027,13 @@
<string name="choose_account_label" msgid="4191313562041125787">"Выберите аккаунт"</string>
<string name="number_picker_increment_button" msgid="4830170763103463443">"Увеличить"</string>
<string name="number_picker_decrement_button" msgid="2576606679160067262">"Уменьшить"</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>
+ <!-- no translation found for storage_internal (7556050805474115618) -->
+ <skip />
+ <!-- no translation found for storage_sd_card (8921771478629812343) -->
+ <skip />
+ <!-- no translation found for storage_usb (3017954059538517278) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-sk/strings.xml b/core/res/res/values-sk/strings.xml
index deacc08..f55b0eb 100644
--- a/core/res/res/values-sk/strings.xml
+++ b/core/res/res/values-sk/strings.xml
@@ -240,6 +240,10 @@
<string name="permdesc_batteryStats" msgid="5847319823772230560">"Umožňuje zmenu zhromaždených štatistických údajov o batérii. Nie je určené pre bežné aplikácie."</string>
<string name="permlab_backup" msgid="470013022865453920">"Ovládať zálohovanie a obnovu systému"</string>
<string name="permdesc_backup" msgid="4837493065154256525">"Umožňuje aplikácii ovládať systémový mechanizmus na zálohovanie a obnovu údajov. Nie je určené pre bežné aplikácie."</string>
+ <!-- no translation found for permlab_confirm_full_backup (5557071325804469102) -->
+ <skip />
+ <!-- no translation found for permdesc_confirm_full_backup (9005017754175897954) -->
+ <skip />
<string name="permlab_internalSystemWindow" msgid="2148563628140193231">"zobrazenie neoprávnených okien"</string>
<string name="permdesc_internalSystemWindow" msgid="5895082268284998469">"Umožňuje vytvorenie okien, ktoré majú byť použité interným systémom používateľského rozhrania. Bežné aplikácie toto nastavenie nepoužívajú."</string>
<string name="permlab_systemAlertWindow" msgid="3372321942941168324">"zobrazenie upozornení systémovej úrovne"</string>
@@ -446,6 +450,10 @@
<string name="permdesc_bluetooth" product="default" msgid="762515380679392945">"Umožňuje aplikácii zobraziť konfiguráciu miestneho telefónu s rozhraním Bluetooth, vytvárať pripojenie na spárované zariadenia a prijímať tieto pripojenia."</string>
<string name="permlab_nfc" msgid="4423351274757876953">"ovládať technológiu Near Field Communication"</string>
<string name="permdesc_nfc" msgid="9171401851954407226">"Umožňuje aplikácii komunikovať so štítkami, kartami a čítačkami s podporou technológie Near Field Communication (NFC)."</string>
+ <!-- no translation found for permlab_vpn (8345800584532175312) -->
+ <skip />
+ <!-- no translation found for permdesc_vpn (5617893078989944219) -->
+ <skip />
<string name="permlab_disableKeyguard" msgid="4977406164311535092">"zakázanie uzamknutia klávesnice"</string>
<string name="permdesc_disableKeyguard" msgid="3189763479326302017">"Umožňuje aplikácii vypnúť uzamknutie klávesnice a súvisiace zabezpečenie heslom. Príkladom oprávneného použitia tejto funkcie je vypnutie uzamknutia klávesnice pri prichádzajúcom hovore a jej opätovné zapnutie po skončení hovoru."</string>
<string name="permlab_readSyncSettings" msgid="6201810008230503052">"čítanie nastavení synchronizácie"</string>
@@ -1019,4 +1027,13 @@
<string name="choose_account_label" msgid="4191313562041125787">"Vybrať účet"</string>
<string name="number_picker_increment_button" msgid="4830170763103463443">"Zvýšenie"</string>
<string name="number_picker_decrement_button" msgid="2576606679160067262">"Zníženie"</string>
+ <string name="action_bar_home_description" msgid="5293600496601490216">"Prejsť na plochu"</string>
+ <string name="action_bar_up_description" msgid="2237496562952152589">"Prejsť na"</string>
+ <string name="action_menu_overflow_description" msgid="2295659037509008453">"Viac možností"</string>
+ <!-- no translation found for storage_internal (7556050805474115618) -->
+ <skip />
+ <!-- no translation found for storage_sd_card (8921771478629812343) -->
+ <skip />
+ <!-- no translation found for storage_usb (3017954059538517278) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-sl/strings.xml b/core/res/res/values-sl/strings.xml
index 8b6c568..16c2c41 100644
--- a/core/res/res/values-sl/strings.xml
+++ b/core/res/res/values-sl/strings.xml
@@ -240,6 +240,10 @@
<string name="permdesc_batteryStats" msgid="5847319823772230560">"Dovoljuje spreminjanje zbranih statističnih podatkov baterije. Ni za uporabo z navadnimi programi."</string>
<string name="permlab_backup" msgid="470013022865453920">"nadzor varnostnega kopiranja sistema in obnovitev"</string>
<string name="permdesc_backup" msgid="4837493065154256525">"Programu dovoljuje nadzor mehanizma za varnostno kopiranje in obnovitev sistema. Ni za uporabo z navadnimi programi."</string>
+ <!-- no translation found for permlab_confirm_full_backup (5557071325804469102) -->
+ <skip />
+ <!-- no translation found for permdesc_confirm_full_backup (9005017754175897954) -->
+ <skip />
<string name="permlab_internalSystemWindow" msgid="2148563628140193231">"prikazovanje nepooblaščenih oken"</string>
<string name="permdesc_internalSystemWindow" msgid="5895082268284998469">"Dovoljuje ustvarjanje oken, ki jih bo uporabljal uporabniški vmesnik notranjega sistema. Ni za uporabo z navadnimi programi."</string>
<string name="permlab_systemAlertWindow" msgid="3372321942941168324">"prikaz opozoril na ravni sistema"</string>
@@ -446,6 +450,10 @@
<string name="permdesc_bluetooth" product="default" msgid="762515380679392945">"Programom dovoljuje ogled konfiguracije lokalnega telefona Bluetooth ter ustvarjanje in sprejemanje povezave s povezanimi napravami."</string>
<string name="permlab_nfc" msgid="4423351274757876953">"nadzor nad komunikacijo s tehnologijo bližnjega polja"</string>
<string name="permdesc_nfc" msgid="9171401851954407226">"Podpira komunikacijo med računalnikom in oznakami, karticami in bralniki komunikacije s tehnologijo bližnjega polja."</string>
+ <!-- no translation found for permlab_vpn (8345800584532175312) -->
+ <skip />
+ <!-- no translation found for permdesc_vpn (5617893078989944219) -->
+ <skip />
<string name="permlab_disableKeyguard" msgid="4977406164311535092">"onemogočanje zaklepa tipkovnice"</string>
<string name="permdesc_disableKeyguard" msgid="3189763479326302017">"Dovoljuje, da program onemogoči zaklep tipk in morebitno povezano varnostno geslo. Legitimen primer je onemogočenje zaklepa tipkovnice pri dohodnem klicu ter vnovičnem omogočanju zaklepa, ko je klic dokončan."</string>
<string name="permlab_readSyncSettings" msgid="6201810008230503052">"branje nastavitev sinhronizacije"</string>
@@ -1019,4 +1027,13 @@
<string name="choose_account_label" msgid="4191313562041125787">"Izberite račun"</string>
<string name="number_picker_increment_button" msgid="4830170763103463443">"Povečaj"</string>
<string name="number_picker_decrement_button" msgid="2576606679160067262">"Zmanjšaj"</string>
+ <string name="action_bar_home_description" msgid="5293600496601490216">"Krmarjenje domov"</string>
+ <string name="action_bar_up_description" msgid="2237496562952152589">"Krmarjenje navzgor"</string>
+ <string name="action_menu_overflow_description" msgid="2295659037509008453">"Več možnosti"</string>
+ <!-- no translation found for storage_internal (7556050805474115618) -->
+ <skip />
+ <!-- no translation found for storage_sd_card (8921771478629812343) -->
+ <skip />
+ <!-- no translation found for storage_usb (3017954059538517278) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-sr/strings.xml b/core/res/res/values-sr/strings.xml
index 2d7b968..cf56261 100644
--- a/core/res/res/values-sr/strings.xml
+++ b/core/res/res/values-sr/strings.xml
@@ -240,6 +240,10 @@
<string name="permdesc_batteryStats" msgid="5847319823772230560">"Омогућава измену прикупљене статистике о батерији. Не користе је обичне апликације."</string>
<string name="permlab_backup" msgid="470013022865453920">"контрола резервне копије система и враћање почетних вредности"</string>
<string name="permdesc_backup" msgid="4837493065154256525">"Омогућава да апликација контролише резервну копију система и механизам за враћање првобитних поставки. Не користе је обичне апликације."</string>
+ <!-- no translation found for permlab_confirm_full_backup (5557071325804469102) -->
+ <skip />
+ <!-- no translation found for permdesc_confirm_full_backup (9005017754175897954) -->
+ <skip />
<string name="permlab_internalSystemWindow" msgid="2148563628140193231">"приказ неовлашћених прозора"</string>
<string name="permdesc_internalSystemWindow" msgid="5895082268284998469">"Омогућава прављење прозора који су осмишљени за коришћење у корисничком интерфејсу интерног система. Не користе је обичне апликације."</string>
<string name="permlab_systemAlertWindow" msgid="3372321942941168324">"приказ упозорења на нивоу система"</string>
@@ -446,6 +450,10 @@
<string name="permdesc_bluetooth" product="default" msgid="762515380679392945">"Омогућава да апликација види конфигурацију локалног Bluetooth телефона, као и да успоставља и прихвата везе са упареним уређајима."</string>
<string name="permlab_nfc" msgid="4423351274757876953">"контрола комуникације у ужем пољу (Near Field Communication)"</string>
<string name="permdesc_nfc" msgid="9171401851954407226">"Омогућава апликацији да комуницира са ознакама, картицама и читачима комуникације у ужем пољу (Near Field Communication – NFC)."</string>
+ <!-- no translation found for permlab_vpn (8345800584532175312) -->
+ <skip />
+ <!-- no translation found for permdesc_vpn (5617893078989944219) -->
+ <skip />
<string name="permlab_disableKeyguard" msgid="4977406164311535092">"онемогућавање закључавања тастатуре"</string>
<string name="permdesc_disableKeyguard" msgid="3189763479326302017">"Омогућава да апликација онемогући закључавање тастатуре и свих безбедносних мера успостављених на основу лозинке. У оправдане примере додељивања такве дозволе спада онемогућавање закључавања тастатуре при пријему долазећег телефонског позива и поновно омогућавање тастатуре по његовом завршетку."</string>
<string name="permlab_readSyncSettings" msgid="6201810008230503052">"читање подешавања синхронизације"</string>
@@ -1019,4 +1027,13 @@
<string name="choose_account_label" msgid="4191313562041125787">"Избор налога"</string>
<string name="number_picker_increment_button" msgid="4830170763103463443">"Повећање"</string>
<string name="number_picker_decrement_button" msgid="2576606679160067262">"Смањење"</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>
+ <!-- no translation found for storage_internal (7556050805474115618) -->
+ <skip />
+ <!-- no translation found for storage_sd_card (8921771478629812343) -->
+ <skip />
+ <!-- no translation found for storage_usb (3017954059538517278) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-sv/strings.xml b/core/res/res/values-sv/strings.xml
index 114fc71..4d96aff 100644
--- a/core/res/res/values-sv/strings.xml
+++ b/core/res/res/values-sv/strings.xml
@@ -240,6 +240,10 @@
<string name="permdesc_batteryStats" msgid="5847319823772230560">"Tillåter att samlad batteristatistik ändras. Används inte av vanliga program."</string>
<string name="permlab_backup" msgid="470013022865453920">"kontrollera säkerhetskopiering och återställning av systemet"</string>
<string name="permdesc_backup" msgid="4837493065154256525">"Tillåter att programmet styr över systemets mekanism för säkerhetskopiering och återställning. Används inte av vanliga program."</string>
+ <!-- no translation found for permlab_confirm_full_backup (5557071325804469102) -->
+ <skip />
+ <!-- no translation found for permdesc_confirm_full_backup (9005017754175897954) -->
+ <skip />
<string name="permlab_internalSystemWindow" msgid="2148563628140193231">"visa otillåtna fönster"</string>
<string name="permdesc_internalSystemWindow" msgid="5895082268284998469">"Tillåter att fönster skapas och används av det interna systemgränssnittet. Används inte av vanliga program."</string>
<string name="permlab_systemAlertWindow" msgid="3372321942941168324">"visa varningar på systemnivå"</string>
@@ -446,6 +450,10 @@
<string name="permdesc_bluetooth" product="default" msgid="762515380679392945">"Tillåter att ett program ser den lokala Bluetooth-telefonens konfiguration, och skapar och accepterar anslutningar med parkopplade enheter."</string>
<string name="permlab_nfc" msgid="4423351274757876953">"kontrollera närfältskommunikationen"</string>
<string name="permdesc_nfc" msgid="9171401851954407226">"Tillåter att en app kommunicerar med taggar, kort och läsare för närfältskommunikation (NFC)."</string>
+ <!-- no translation found for permlab_vpn (8345800584532175312) -->
+ <skip />
+ <!-- no translation found for permdesc_vpn (5617893078989944219) -->
+ <skip />
<string name="permlab_disableKeyguard" msgid="4977406164311535092">"inaktivera tangentlås"</string>
<string name="permdesc_disableKeyguard" msgid="3189763479326302017">"Tillåter att ett program inaktiverar tangentlåset och tillhörande lösenordsskydd. Ett exempel på detta är att telefonen inaktiverar tangentlåset vid inkommande samtal och sedan aktiverar det igen när samtalet är avslutat."</string>
<string name="permlab_readSyncSettings" msgid="6201810008230503052">"läsa synkroniseringsinställningar"</string>
@@ -1019,4 +1027,13 @@
<string name="choose_account_label" msgid="4191313562041125787">"Välj ett konto"</string>
<string name="number_picker_increment_button" msgid="4830170763103463443">"Öka"</string>
<string name="number_picker_decrement_button" msgid="2576606679160067262">"Minska"</string>
+ <string name="action_bar_home_description" msgid="5293600496601490216">"Visa startsidan"</string>
+ <string name="action_bar_up_description" msgid="2237496562952152589">"Navigera uppåt"</string>
+ <string name="action_menu_overflow_description" msgid="2295659037509008453">"Fler alternativ"</string>
+ <!-- no translation found for storage_internal (7556050805474115618) -->
+ <skip />
+ <!-- no translation found for storage_sd_card (8921771478629812343) -->
+ <skip />
+ <!-- no translation found for storage_usb (3017954059538517278) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-th/strings.xml b/core/res/res/values-th/strings.xml
index 236c510c..75a886c 100644
--- a/core/res/res/values-th/strings.xml
+++ b/core/res/res/values-th/strings.xml
@@ -240,6 +240,10 @@
<string name="permdesc_batteryStats" msgid="5847319823772230560">"อนุญาตให้แก้ไขสถิติแบตเตอรี่ที่เก็บไว้ ห้ามใช้โดยแอปพลิเคชันทั่วไป"</string>
<string name="permlab_backup" msgid="470013022865453920">"ควบคุมการสำรองและคืนค่า"</string>
<string name="permdesc_backup" msgid="4837493065154256525">"อนุญาตให้แอปพลิเคชันควบคุมวิธีการสำรองและคืนค่าระบบ ห้ามใช้โดยแอปพลิเคชันทั่วไป"</string>
+ <!-- no translation found for permlab_confirm_full_backup (5557071325804469102) -->
+ <skip />
+ <!-- no translation found for permdesc_confirm_full_backup (9005017754175897954) -->
+ <skip />
<string name="permlab_internalSystemWindow" msgid="2148563628140193231">"แสดงหน้าต่างที่ไม่ได้รับอนุญาต"</string>
<string name="permdesc_internalSystemWindow" msgid="5895082268284998469">"อนุญาตให้สร้างหน้าต่างสำหรับใช้โดยส่วนติดต่อผู้ใช้ของระบบภายใน ห้ามใช้โดยแอปพลิเคชันทั่วไป"</string>
<string name="permlab_systemAlertWindow" msgid="3372321942941168324">"แสดงการแจ้งเตือนในระดับระบบ"</string>
@@ -446,6 +450,10 @@
<string name="permdesc_bluetooth" product="default" msgid="762515380679392945">"อนุญาตให้แอปพลิเคชันดูการกำหนดค่าของโทรศัพท์บลูทูธในพื้นที่ ตลอดจนเชื่อมต่อและยอมรับการเชื่อมต่อด้วยอุปกรณ์ที่จับคู่ไว้"</string>
<string name="permlab_nfc" msgid="4423351274757876953">"ควบคุม Near Field Communication"</string>
<string name="permdesc_nfc" msgid="9171401851954407226">"อนุญาตให้แอปพลิเคชันสื่อสารกับแท็ก Near Field Communication (NFC) การ์ด และโปรแกรมอ่าน"</string>
+ <!-- no translation found for permlab_vpn (8345800584532175312) -->
+ <skip />
+ <!-- no translation found for permdesc_vpn (5617893078989944219) -->
+ <skip />
<string name="permlab_disableKeyguard" msgid="4977406164311535092">"ปิดการใช้งานการล็อกปุ่มกด"</string>
<string name="permdesc_disableKeyguard" msgid="3189763479326302017">"อนุญาตให้แอปพลิเคชันปิดการใช้งานการล็อกปุ่มและการรักษาความปลอดภัยรหัสผ่านที่เกี่ยวข้องใดๆ ตัวอย่างการใช้งานของกรณีนี้คือ โทรศัพท์ปิดการใช้งานการล็อกปุ่มกดเมื่อมีสายเรียกเข้า จากนั้นจึงเปิดการใช้งานการล็อกปุ่มกดใหม่เมื่อวางสายแล้ว"</string>
<string name="permlab_readSyncSettings" msgid="6201810008230503052">"อ่านการตั้งค่าการซิงค์แล้ว"</string>
@@ -1019,4 +1027,13 @@
<string name="choose_account_label" msgid="4191313562041125787">"เลือกบัญชี"</string>
<string name="number_picker_increment_button" msgid="4830170763103463443">"การเพิ่ม"</string>
<string name="number_picker_decrement_button" msgid="2576606679160067262">"การลด"</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>
+ <!-- no translation found for storage_internal (7556050805474115618) -->
+ <skip />
+ <!-- no translation found for storage_sd_card (8921771478629812343) -->
+ <skip />
+ <!-- no translation found for storage_usb (3017954059538517278) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-tl/strings.xml b/core/res/res/values-tl/strings.xml
index cdb2808..cec9fae 100644
--- a/core/res/res/values-tl/strings.xml
+++ b/core/res/res/values-tl/strings.xml
@@ -240,6 +240,10 @@
<string name="permdesc_batteryStats" msgid="5847319823772230560">"Pinapayagan ang pagbabago ng mga nakolektang istatistika ng baterya. Hindi para sa paggamit ng mga normal na application."</string>
<string name="permlab_backup" msgid="470013022865453920">"kontrolin ang system backup at pagbawi"</string>
<string name="permdesc_backup" msgid="4837493065154256525">"Pinapayagan ang application na kontrolin ang mekanismo sa pag-backup at pagbalik ng system. Hindi para sa paggamit ng mga normal na application."</string>
+ <!-- no translation found for permlab_confirm_full_backup (5557071325804469102) -->
+ <skip />
+ <!-- no translation found for permdesc_confirm_full_backup (9005017754175897954) -->
+ <skip />
<string name="permlab_internalSystemWindow" msgid="2148563628140193231">"ipakita ang mga hindi pinahintulutang window"</string>
<string name="permdesc_internalSystemWindow" msgid="5895082268284998469">"Pinapayagan ang paglikha ng mga window na nilayon para sa paggamit ng user interface ng pangloob na system. Hindi para sa paggamit ng mga normal na application."</string>
<string name="permlab_systemAlertWindow" msgid="3372321942941168324">"ipakita ang mga alerto sa antas ng system"</string>
@@ -446,6 +450,10 @@
<string name="permdesc_bluetooth" product="default" msgid="762515380679392945">"Pinapayagan ang isang application na tingnan ang configuration ng lokal na Bluetooth na telepono, at upang gumawa at tumanggap ng mga koneksyon sa mga nakapares na device."</string>
<string name="permlab_nfc" msgid="4423351274757876953">"kontrolin ang Near Field Communication"</string>
<string name="permdesc_nfc" msgid="9171401851954407226">"Pinapayagan ang application na makipagkomunika sa mga Near Field Communication (NFC) na tag, card, at reader."</string>
+ <!-- no translation found for permlab_vpn (8345800584532175312) -->
+ <skip />
+ <!-- no translation found for permdesc_vpn (5617893078989944219) -->
+ <skip />
<string name="permlab_disableKeyguard" msgid="4977406164311535092">"huwag paganahin ang keylock"</string>
<string name="permdesc_disableKeyguard" msgid="3189763479326302017">"Pinapayagan ang isang application na huwag paganahin ang keylock at ang anumang nauugnay na seguridad sa password. Ang isang lehitimong halimbawa nito ay ang hindi pagpapagana ng telepono sa keylock kapag nakakatanggap ng papasok na tawag sa telepono, pagkatapos ay muling pagaganahin ang keylock kapag tapos na ang tawag."</string>
<string name="permlab_readSyncSettings" msgid="6201810008230503052">"basahin ang mga setting ng sync"</string>
@@ -1019,4 +1027,13 @@
<string name="choose_account_label" msgid="4191313562041125787">"Pumili ng account"</string>
<string name="number_picker_increment_button" msgid="4830170763103463443">"Taasan"</string>
<string name="number_picker_decrement_button" msgid="2576606679160067262">"Babaan"</string>
+ <string name="action_bar_home_description" msgid="5293600496601490216">"Magnabiga sa home"</string>
+ <string name="action_bar_up_description" msgid="2237496562952152589">"Magnabiga pataas"</string>
+ <string name="action_menu_overflow_description" msgid="2295659037509008453">"Higit pang mga pagpipilian"</string>
+ <!-- no translation found for storage_internal (7556050805474115618) -->
+ <skip />
+ <!-- no translation found for storage_sd_card (8921771478629812343) -->
+ <skip />
+ <!-- no translation found for storage_usb (3017954059538517278) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-tr/strings.xml b/core/res/res/values-tr/strings.xml
index 529632a..081fa10 100644
--- a/core/res/res/values-tr/strings.xml
+++ b/core/res/res/values-tr/strings.xml
@@ -240,6 +240,10 @@
<string name="permdesc_batteryStats" msgid="5847319823772230560">"Toplanan pil istatistiklerinin değiştirilmesine izin verir. Normal uygulamalarda kullanılmamalıdır."</string>
<string name="permlab_backup" msgid="470013022865453920">"sistem yedeğini kontrol et ve geri yükle"</string>
<string name="permdesc_backup" msgid="4837493065154256525">"Uygulamaya sistem yedekleme ve geri yükleme mekanizmasını denetleme izni verir. Normal uygulamalar tarafından kullanım için değildir."</string>
+ <!-- no translation found for permlab_confirm_full_backup (5557071325804469102) -->
+ <skip />
+ <!-- no translation found for permdesc_confirm_full_backup (9005017754175897954) -->
+ <skip />
<string name="permlab_internalSystemWindow" msgid="2148563628140193231">"yetkisiz pencereleri görüntüle"</string>
<string name="permdesc_internalSystemWindow" msgid="5895082268284998469">"Dahili sistem kullanıcı arayüzü tarafından kullanılmak üzere tasarlanmış pencerelerin oluşturulmasına izin verir. Normal uygulamalarda kullanılmaz."</string>
<string name="permlab_systemAlertWindow" msgid="3372321942941168324">"sistem düzeyi uyarıları görüntüle"</string>
@@ -446,6 +450,10 @@
<string name="permdesc_bluetooth" product="default" msgid="762515380679392945">"Uygulamaların yerel Bluetooth telefonunun yapılandırmasını görüntülemesine ve eşleşilmiş cihazlar ile bağlantı kurup kabul etmesine izin verir."</string>
<string name="permlab_nfc" msgid="4423351274757876953">"Yakın Alan İletişimini denetle"</string>
<string name="permdesc_nfc" msgid="9171401851954407226">"Bir uyg\'nın Yakın Alan İletişimi etiketleri, kartları ve okuyclr ile iletşm kurmasına izin verir."</string>
+ <!-- no translation found for permlab_vpn (8345800584532175312) -->
+ <skip />
+ <!-- no translation found for permdesc_vpn (5617893078989944219) -->
+ <skip />
<string name="permlab_disableKeyguard" msgid="4977406164311535092">"tuş kilidini devre dışı bırak"</string>
<string name="permdesc_disableKeyguard" msgid="3189763479326302017">"Uygulamaların tuş kilidini ve ilgili şifreli güvenlik önlemini devre dışı bırakmasına izin verir. Bunun geçerli bir örneği gelen bir çağrı alındığında tuş kilidinin devre dışı bırakılması, sonra çağrı bittiğinde kilidin yeniden devreye sokulmasıdır."</string>
<string name="permlab_readSyncSettings" msgid="6201810008230503052">"senk. ayarlarını oku"</string>
@@ -1019,4 +1027,13 @@
<string name="choose_account_label" msgid="4191313562041125787">"Bir hesap seçin"</string>
<string name="number_picker_increment_button" msgid="4830170763103463443">"Artır"</string>
<string name="number_picker_decrement_button" msgid="2576606679160067262">"Azalt"</string>
+ <string name="action_bar_home_description" msgid="5293600496601490216">"Ana sayfaya git"</string>
+ <string name="action_bar_up_description" msgid="2237496562952152589">"Yukarı git"</string>
+ <string name="action_menu_overflow_description" msgid="2295659037509008453">"Diğer seçenekler"</string>
+ <!-- no translation found for storage_internal (7556050805474115618) -->
+ <skip />
+ <!-- no translation found for storage_sd_card (8921771478629812343) -->
+ <skip />
+ <!-- no translation found for storage_usb (3017954059538517278) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-uk/strings.xml b/core/res/res/values-uk/strings.xml
index 4950ace..88ddc41 100644
--- a/core/res/res/values-uk/strings.xml
+++ b/core/res/res/values-uk/strings.xml
@@ -240,6 +240,10 @@
<string name="permdesc_batteryStats" msgid="5847319823772230560">"Дозволяє змінювати зібрану статистику батареї. Не для використання звичайними програмами."</string>
<string name="permlab_backup" msgid="470013022865453920">"контр. резерв. копіюв. і відн. сист."</string>
<string name="permdesc_backup" msgid="4837493065154256525">"Дозволяє програмі контролювати механізми резерв. копіюв. і відновл. системи. Не для викор. звичайними програмами."</string>
+ <!-- no translation found for permlab_confirm_full_backup (5557071325804469102) -->
+ <skip />
+ <!-- no translation found for permdesc_confirm_full_backup (9005017754175897954) -->
+ <skip />
<string name="permlab_internalSystemWindow" msgid="2148563628140193231">"відображати несанкціон. вікна"</string>
<string name="permdesc_internalSystemWindow" msgid="5895082268284998469">"Дозволяє створювати вікна, які мають використ-ся інтерфейсом користувача внутрішньої системи. Не для використання звичайними програмами."</string>
<string name="permlab_systemAlertWindow" msgid="3372321942941168324">"відобр. сповіщ. на рівні сист."</string>
@@ -446,6 +450,10 @@
<string name="permdesc_bluetooth" product="default" msgid="762515380679392945">"Дозволяє програмі переглядати конфігурацію локального Bluetooth телефону, створювати та приймати з\'єднання зі спареними пристроями."</string>
<string name="permlab_nfc" msgid="4423351274757876953">"контрол. Near Field Communication"</string>
<string name="permdesc_nfc" msgid="9171401851954407226">"Дозволяє прогр. обмін. даними з тегами, картками та читачами екрана Near Field Communication (NFC)."</string>
+ <!-- no translation found for permlab_vpn (8345800584532175312) -->
+ <skip />
+ <!-- no translation found for permdesc_vpn (5617893078989944219) -->
+ <skip />
<string name="permlab_disableKeyguard" msgid="4977406164311535092">"вимик. блок. клав."</string>
<string name="permdesc_disableKeyguard" msgid="3189763479326302017">"Дозволяє програмі вимикати блокування клавіатури та будь-який пов\'язаний захист паролем. Допустимий приклад, коли телефон вимикає блокування клавіат. при отриманні вхідного дзвінка, після завершення якого блокування клавіатури відновлюється."</string>
<string name="permlab_readSyncSettings" msgid="6201810008230503052">"чит. налашт-ня синхр."</string>
@@ -1019,4 +1027,13 @@
<string name="choose_account_label" msgid="4191313562041125787">"Вибрати обліковий запис"</string>
<string name="number_picker_increment_button" msgid="4830170763103463443">"Додати"</string>
<string name="number_picker_decrement_button" msgid="2576606679160067262">"Відняти"</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>
+ <!-- no translation found for storage_internal (7556050805474115618) -->
+ <skip />
+ <!-- no translation found for storage_sd_card (8921771478629812343) -->
+ <skip />
+ <!-- no translation found for storage_usb (3017954059538517278) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-vi/strings.xml b/core/res/res/values-vi/strings.xml
index ab097ad..01a320a 100644
--- a/core/res/res/values-vi/strings.xml
+++ b/core/res/res/values-vi/strings.xml
@@ -240,6 +240,8 @@
<string name="permdesc_batteryStats" msgid="5847319823772230560">"Cho phép sửa đổi các thống kê pin được thu thập. Không dành cho các ứng dụng thông thường."</string>
<string name="permlab_backup" msgid="470013022865453920">"kiểm soát sao lưu và khôi phục hệ thống"</string>
<string name="permdesc_backup" msgid="4837493065154256525">"Cho phép ứng dụng kiểm soát cơ chế sao lưu và khôi phục hệ thống. Không dành cho các ứng dụng thông thường."</string>
+ <string name="permlab_confirm_full_backup" msgid="5557071325804469102">"xác nhận bản sao lưu đầy đủ hoặc khôi phục hoạt động"</string>
+ <string name="permdesc_confirm_full_backup" msgid="9005017754175897954">"Cho phép ứng dụng khởi chạy toàn bộ Giao diện người dùng xác nhận sao lưu. Không được bất kỳ ứng dụng nào sử dụng."</string>
<string name="permlab_internalSystemWindow" msgid="2148563628140193231">"hiển thị các cửa sổ trái phép"</string>
<string name="permdesc_internalSystemWindow" msgid="5895082268284998469">"Cho phép tạo các cửa sổ được giao diện người dùng hệ thống nội bộ sử dụng. Không dành cho các ứng dụng thông thường."</string>
<string name="permlab_systemAlertWindow" msgid="3372321942941168324">"hiển thị thông báo cấp hệ thống"</string>
@@ -446,6 +448,10 @@
<string name="permdesc_bluetooth" product="default" msgid="762515380679392945">"Cho phép ứng dụng xem cấu hình của điện thoại Bluetooth nội hạt cũng như tạo và chấp nhận các kết nối với các thiết bị được ghép nối."</string>
<string name="permlab_nfc" msgid="4423351274757876953">"kiểm soát Liên lạc trường gần"</string>
<string name="permdesc_nfc" msgid="9171401851954407226">"Cho phép ứng dụng liên lạc với thẻ Liên lạc trường gần (NFC), thẻ và trình đọc."</string>
+ <!-- no translation found for permlab_vpn (8345800584532175312) -->
+ <skip />
+ <!-- no translation found for permdesc_vpn (5617893078989944219) -->
+ <skip />
<string name="permlab_disableKeyguard" msgid="4977406164311535092">"vô hiệu hoá khoá phím"</string>
<string name="permdesc_disableKeyguard" msgid="3189763479326302017">"Cho phép ứng dụng vô hiệu hoá khoá phím và bất kỳ bảo mật mật khẩu được liên kết nào. Ví dụ thích hợp của việc này là điện thoại vô hiệu hoá khoá phím khi nhận được cuộc gọi đến sau đó bật lại khoá phím khi cuộc gọi kết thúc."</string>
<string name="permlab_readSyncSettings" msgid="6201810008230503052">"đọc cài đặt đồng bộ hoá"</string>
@@ -1019,4 +1025,13 @@
<string name="choose_account_label" msgid="4191313562041125787">"Chọn tài khoản"</string>
<string name="number_picker_increment_button" msgid="4830170763103463443">"Tăng dần"</string>
<string name="number_picker_decrement_button" msgid="2576606679160067262">"Giảm dần"</string>
+ <string name="action_bar_home_description" msgid="5293600496601490216">"Điều hướng về trang chủ"</string>
+ <string name="action_bar_up_description" msgid="2237496562952152589">"Điều hướng lên trên"</string>
+ <string name="action_menu_overflow_description" msgid="2295659037509008453">"Tùy chọn khác"</string>
+ <!-- no translation found for storage_internal (7556050805474115618) -->
+ <skip />
+ <!-- no translation found for storage_sd_card (8921771478629812343) -->
+ <skip />
+ <!-- no translation found for storage_usb (3017954059538517278) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-zh-rCN/strings.xml b/core/res/res/values-zh-rCN/strings.xml
index 42a7995..3386f97 100644
--- a/core/res/res/values-zh-rCN/strings.xml
+++ b/core/res/res/values-zh-rCN/strings.xml
@@ -240,6 +240,10 @@
<string name="permdesc_batteryStats" msgid="5847319823772230560">"允许修改收集的电池使用情况统计信息。普通应用程序不能使用此权限。"</string>
<string name="permlab_backup" msgid="470013022865453920">"控制系统备份和还原"</string>
<string name="permdesc_backup" msgid="4837493065154256525">"允许应用程序控制系统的备份和还原机制。普通应用程序不能使用此权限。"</string>
+ <!-- no translation found for permlab_confirm_full_backup (5557071325804469102) -->
+ <skip />
+ <!-- no translation found for permdesc_confirm_full_backup (9005017754175897954) -->
+ <skip />
<string name="permlab_internalSystemWindow" msgid="2148563628140193231">"显示未授权的窗口"</string>
<string name="permdesc_internalSystemWindow" msgid="5895082268284998469">"允许创建专用于内部系统用户界面的窗口。普通应用程序不能使用此权限。"</string>
<string name="permlab_systemAlertWindow" msgid="3372321942941168324">"显示系统级警报"</string>
@@ -446,6 +450,10 @@
<string name="permdesc_bluetooth" product="default" msgid="762515380679392945">"允许应用程序查看本地蓝牙手机的配置,以及建立或接受与配对设备的连接。"</string>
<string name="permlab_nfc" msgid="4423351274757876953">"控制近距离通信"</string>
<string name="permdesc_nfc" msgid="9171401851954407226">"允许应用程序与近距离通信 (NFC) 标签、卡和读卡器进行通信。"</string>
+ <!-- no translation found for permlab_vpn (8345800584532175312) -->
+ <skip />
+ <!-- no translation found for permdesc_vpn (5617893078989944219) -->
+ <skip />
<string name="permlab_disableKeyguard" msgid="4977406164311535092">"停用键锁"</string>
<string name="permdesc_disableKeyguard" msgid="3189763479326302017">"允许应用程序停用键锁和任何关联的密码安全设置。例如,在手机上接听电话时停用键锁,在通话结束后重新启用键锁。"</string>
<string name="permlab_readSyncSettings" msgid="6201810008230503052">"读取同步设置"</string>
@@ -1019,4 +1027,13 @@
<string name="choose_account_label" msgid="4191313562041125787">"选择帐户"</string>
<string name="number_picker_increment_button" msgid="4830170763103463443">"增加"</string>
<string name="number_picker_decrement_button" msgid="2576606679160067262">"减少"</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>
+ <!-- no translation found for storage_internal (7556050805474115618) -->
+ <skip />
+ <!-- no translation found for storage_sd_card (8921771478629812343) -->
+ <skip />
+ <!-- no translation found for storage_usb (3017954059538517278) -->
+ <skip />
</resources>
diff --git a/core/res/res/values-zh-rTW/strings.xml b/core/res/res/values-zh-rTW/strings.xml
index 6d8e1f4..d4a0243 100644
--- a/core/res/res/values-zh-rTW/strings.xml
+++ b/core/res/res/values-zh-rTW/strings.xml
@@ -240,6 +240,10 @@
<string name="permdesc_batteryStats" msgid="5847319823772230560">"允修改收集到的電池用量統計資料。一般應用程式不應使用這項功能。"</string>
<string name="permlab_backup" msgid="470013022865453920">"控制系統備份與還原"</string>
<string name="permdesc_backup" msgid="4837493065154256525">"允許應用程式控制系統的備份與還原機制。一般應用程式不應使用這項功能。"</string>
+ <!-- no translation found for permlab_confirm_full_backup (5557071325804469102) -->
+ <skip />
+ <!-- no translation found for permdesc_confirm_full_backup (9005017754175897954) -->
+ <skip />
<string name="permlab_internalSystemWindow" msgid="2148563628140193231">"顯示未授權視窗"</string>
<string name="permdesc_internalSystemWindow" msgid="5895082268284998469">"允許內部系統使用介面建立視窗。一般應用程式不會使用此功能。"</string>
<string name="permlab_systemAlertWindow" msgid="3372321942941168324">"顯示系統警示"</string>
@@ -446,6 +450,10 @@
<string name="permdesc_bluetooth" product="default" msgid="762515380679392945">"允許應用程式檢視本機藍牙電話設定,並與其他配對裝置連線。"</string>
<string name="permlab_nfc" msgid="4423351274757876953">"控制近距離無線通訊"</string>
<string name="permdesc_nfc" msgid="9171401851954407226">"允許應用程式使用近距離無線通訊 (NFC) 標記、卡片及讀取程式進行通訊。"</string>
+ <!-- no translation found for permlab_vpn (8345800584532175312) -->
+ <skip />
+ <!-- no translation found for permdesc_vpn (5617893078989944219) -->
+ <skip />
<string name="permlab_disableKeyguard" msgid="4977406164311535092">"停用按鍵鎖定"</string>
<string name="permdesc_disableKeyguard" msgid="3189763479326302017">"允許應用程式停用按鍵鎖定以及其他相關的密碼安全性。例如:收到來電時解除按鍵鎖定,通話結束後重新啟動按鍵鎖定。"</string>
<string name="permlab_readSyncSettings" msgid="6201810008230503052">"讀取同步處理設定"</string>
@@ -1019,4 +1027,13 @@
<string name="choose_account_label" msgid="4191313562041125787">"選取帳戶"</string>
<string name="number_picker_increment_button" msgid="4830170763103463443">"增加"</string>
<string name="number_picker_decrement_button" msgid="2576606679160067262">"減少"</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>
+ <!-- no translation found for storage_internal (7556050805474115618) -->
+ <skip />
+ <!-- no translation found for storage_sd_card (8921771478629812343) -->
+ <skip />
+ <!-- no translation found for storage_usb (3017954059538517278) -->
+ <skip />
</resources>
diff --git a/core/res/res/values/attrs_manifest.xml b/core/res/res/values/attrs_manifest.xml
index 1463bc7..625afff 100644
--- a/core/res/res/values/attrs_manifest.xml
+++ b/core/res/res/values/attrs_manifest.xml
@@ -591,7 +591,7 @@
going in or out of car mode, night mode changing, etc. -->
<flag name="uiMode" value="0x0200" />
<!-- The physical screen size has changed. If applications don't
- target at least {@link android.os.Build.VERSION_CODES#ICE_CREAM_SANDWICH}
+ target at least {@link android.os.Build.VERSION_CODES#HONEYCOMB_MR2}
then the activity will always handle this itself (the change
will not result in a restart). -->
<flag name="screenSize" value="0x0400" />
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 990885d..4dd4ff2 100755
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -94,49 +94,6 @@
when there's no network connection. If the scan doesn't timeout, use zero -->
<integer name="config_radioScanningTimeout">0</integer>
- <!-- Set to true if the location returned Environment.getExternalStorageDirectory()
- is actually a subdirectory of the internal storage.
- If this is set then Environment.getExternalStorageState() will always return
- MEDIA_MOUNTED and Intent.ACTION_MEDIA_MOUNTED will be broadcast at boot time
- for backward compatibility with apps that require external storage. -->
- <bool name="config_emulateExternalStorage">false</bool>
-
- <!-- A product with no SD card == not removable. -->
- <bool name="config_externalStorageRemovable" product="nosdcard">false</bool>
- <!-- Configures whether the primary external storage device is
- removable. For example, if external storage is on an SD card,
- it is removable; if it is built in to the device, it is not removable.
- The default product has external storage on an SD card, which is
- removable. -->
- <bool name="config_externalStorageRemovable" product="default">true</bool>
-
- <!-- List of mount points for external storage devices.
- The first item on the list should be the primary external storage and should match the
- value returned by Environment.getExternalStorageDirectory (/mnt/sdcard).
- MTP storage IDs will be generated based on the position of the mountpoint in this list:
- 0x00010001 - ID for primary external storage (/mnt/sdcard)
- 0x00020001 - ID for first secondary external storage
- 0x00030001 - ID for second secondary external storage
- etc. -->
- <string-array translatable="false" name="config_externalStoragePaths">
- <item>"/mnt/sdcard"</item>
- </string-array>
-
- <!-- User visible descriptions of the volumes in the config_externalStoragePaths array. -->
- <string-array translatable="true" name="config_externalStorageDescriptions">
- <item>"SD card"</item>
- </string-array>
-
- <!-- Number of megabytes of space to leave unallocated by MTP.
- MTP will subtract this value from the free space it reports back
- to the host via GetStorageInfo, and will not allow new files to
- be added via MTP if there is less than this amount left free in the storage.
- If MTP has dedicated storage this value should be zero, but if MTP is
- sharing storage with the rest of the system, set this to a positive value
- to ensure that MTP activity does not result in the storage being
- too close to full. -->
- <integer name="config_mtpReserveSpaceMegabytes">0</integer>
-
<!-- XXXXX NOTE THE FOLLOWING RESOURCES USE THE WRONG NAMING CONVENTION.
Please don't copy them, copy anything else. -->
diff --git a/core/res/res/values/dimens.xml b/core/res/res/values/dimens.xml
index a1511b3..e405f20 100644
--- a/core/res/res/values/dimens.xml
+++ b/core/res/res/values/dimens.xml
@@ -19,9 +19,9 @@
-->
<resources>
<!-- The width that is used when creating thumbnails of applications. -->
- <dimen name="thumbnail_width">64dp</dimen>
+ <dimen name="thumbnail_width">120dp</dimen>
<!-- The height that is used when creating thumbnails of applications. -->
- <dimen name="thumbnail_height">100dp</dimen>
+ <dimen name="thumbnail_height">120dp</dimen>
<!-- The standard size (both width and height) of an application icon that
will be displayed in the app launcher and elsewhere. -->
<dimen name="app_icon_size">48dip</dimen>
@@ -80,6 +80,11 @@
<!-- Minimum width of the search view text entry area. -->
<dimen name="search_view_text_min_width">160dip</dimen>
+ <!-- Dialog title height -->
+ <dimen name="alert_dialog_title_height">48dip</dimen>
+ <!-- Dialog button bar height -->
+ <dimen name="alert_dialog_button_bar_height">48dip</dimen>
+
<!-- Default height of an action bar. -->
<dimen name="action_bar_default_height">48dip</dimen>
<!-- Vertical padding around action bar icons. -->
diff --git a/core/res/res/values/styles.xml b/core/res/res/values/styles.xml
index 2d44f62..26b5d95 100644
--- a/core/res/res/values/styles.xml
+++ b/core/res/res/values/styles.xml
@@ -574,12 +574,12 @@
<style name="Widget.ScrollView">
<item name="android:scrollbars">vertical</item>
- <item name="android:fadingEdge">none</item>
+ <item name="android:fadingEdge">vertical</item>
</style>
<style name="Widget.HorizontalScrollView">
<item name="android:scrollbars">horizontal</item>
- <item name="android:fadingEdge">none</item>
+ <item name="android:fadingEdge">horizontal</item>
</style>
<style name="Widget.ListView" parent="Widget.AbsListView">
@@ -1459,6 +1459,10 @@
</style>
<style name="Holo.ButtonBar" parent="ButtonBar">
+ <item name="android:paddingTop">0dip</item>
+ <item name="android:paddingLeft">0dip</item>
+ <item name="android:paddingRight">0dip</item>
+ <item name="android:paddingBottom">0dip</item>
<item name="divider">?android:attr/dividerVertical</item>
<item name="showDividers">middle</item>
<item name="dividerPadding">8dip</item>
diff --git a/data/fonts/MTLc3m.ttf b/data/fonts/MTLc3m.ttf
index 3cc5c96..86bdcc7 100644
--- a/data/fonts/MTLc3m.ttf
+++ b/data/fonts/MTLc3m.ttf
Binary files differ
diff --git a/data/fonts/MTLmr3m.ttf b/data/fonts/MTLmr3m.ttf
index 05b9093..76fe737 100644
--- a/data/fonts/MTLmr3m.ttf
+++ b/data/fonts/MTLmr3m.ttf
Binary files differ
diff --git a/docs/html/guide/appendix/install-location.jd b/docs/html/guide/appendix/install-location.jd
index 7f96809..617f4fc 100644
--- a/docs/html/guide/appendix/install-location.jd
+++ b/docs/html/guide/appendix/install-location.jd
@@ -171,6 +171,11 @@
<dd>The system delivers the {@link android.content.Intent#ACTION_BOOT_COMPLETED} broadcast
before the external storage is mounted to the device. If your application is installed on the
external storage, it can never receive this broadcast.</dd>
+ <dt>Copy Protection</dt>
+ <dd>Your application cannot be installed to a device's SD card if it uses Android Market's
+ Copy Protection feature. However, if you use Android Market's
+ <a href="{@docRoot}guide/publishing/licensing.html">Application Licensing</a> instead, your
+ application <em>can</em> be installed to internal or external storage, including SD cards.</dd>
</dl>
<p>If your application uses any of the features listed above, you <strong>should not</strong> allow
diff --git a/docs/html/guide/publishing/licensing.jd b/docs/html/guide/publishing/licensing.jd
index a9b182e..d89a8ca 100644
--- a/docs/html/guide/publishing/licensing.jd
+++ b/docs/html/guide/publishing/licensing.jd
@@ -263,15 +263,15 @@
you won't be able to upload a new version that uses licensing.</li>
</ul>
-<h4>Replacement for copy protection</h4>
+<h4>Replacement for Copy Protection</h4>
<p>Android Market Licensing is a flexible, secure mechanism for controlling
-access to your applications. It effectively replaces the copy-protection
+access to your applications. It effectively replaces the Copy Protection
mechanism offered on Android Market and gives you wider distribution
potential for your applications. </p>
<ul>
-<li>A limitation of the legacy copy-protection mechanism on Android Market is
+<li>A limitation of the legacy Copy Protection mechanism on Android Market is
that applications using it can be installed only on compatible devices that
provide a secure internal storage environment. For example, a copy-protected
application cannot be downloaded from Market to a device that provides root
diff --git a/docs/html/guide/topics/appwidgets/index.jd b/docs/html/guide/topics/appwidgets/index.jd
index 89306a2..e589292 100644
--- a/docs/html/guide/topics/appwidgets/index.jd
+++ b/docs/html/guide/topics/appwidgets/index.jd
@@ -7,7 +7,8 @@
<ul>
<li>App Widgets provide users access to some of your application features
directly from the Home screen (without the need to launch an activity)</li>
- <li>App Widgets are backed by a special kind of broadcast receiver that handles the App
+ <li>App Widgets are backed by a special kind of broadcast receiver that
+handles the App
Widget lifecycle</li>
</ul>
@@ -19,15 +20,28 @@
<li><a href="#CreatingLayout">Creating the App Widget Layout</a></li>
<li><a href="#AppWidgetProvider">Using the AppWidgetProvider Class</a>
<ol>
- <li><a href="#ProviderBroadcasts">Receiving App Widget broadcast Intents</a></li>
+ <li><a href="#ProviderBroadcasts">Receiving App Widget broadcast
+Intents</a></li>
</ol>
</li>
- <li><a href="#Configuring">Creating an App Widget Configuration Activity</a>
+ <li><a href="#Configuring">Creating an App Widget Configuration
+Activity</a>
<ol>
- <li><a href="#UpdatingFromTheConfiguration">Updating the App Widget from
+ <li><a href="#UpdatingFromTheConfiguration">Updating the App Widget
+from
the configuration Activity</a></li>
</ol>
</li>
+ <li><a href="#preview">Setting a Preview Image</a></li>
+ <li><a href="#collections">Using App Widgets with Collections</a>
+ <ol>
+ <li><a href="#collection_sample">Sample application</a></li>
+ <li><a href="#implementing_collections">Implementing app widgets with
+collections
+</a></li>
+ <li><a href="#fresh">Keeping Collection Data Fresh</a></li>
+ </ol>
+ </li>
</ol>
<h2>Key classes</h2>
@@ -39,25 +53,34 @@
<h2>See also</h2>
<ol>
- <li><a href="{@docRoot}guide/practices/ui_guidelines/widget_design.html">App Widget Design
+ <li><a
+href="{@docRoot}guide/practices/ui_guidelines/widget_design.html">App Widget
+Design
Guidelines</a></li>
- <li><a href="http://android-developers.blogspot.com/2009/04/introducing-home-screen-widgets-and.html">Introducing
+ <li><a
+href="http://android-developers.blogspot.com/2009/04/introducing-home-screen-
+widgets-and.html">Introducing
home screen widgets and the AppWidget framework »</a></li>
</ol>
</div>
</div>
-<p>App Widgets are miniature application views that can be embedded in other applications
-(such as the Home screen) and receive periodic updates. These views are referred
+<p>App Widgets are miniature application views that can be embedded in other
+applications
+(such as the Home screen) and receive periodic updates. These views are
+referred
to as Widgets in the user interface,
-and you can publish one with an App Widget provider. An application component that is
-able to hold other App Widgets is called an App Widget host. The screenshot below shows
+and you can publish one with an App Widget provider. An application component
+that is
+able to hold other App Widgets is called an App Widget host. The screenshot
+below shows
the Music App Widget.</p>
<img src="{@docRoot}images/appwidget.png" alt="" />
-<p>This document describes how to publish an App Widget using an App Widget provider.</p>
+<p>This document describes how to publish an App Widget using an App Widget
+provider.</p>
<h2 id="Basics">The Basics</h2>
@@ -66,18 +89,23 @@
<dl>
<dt>{@link android.appwidget.AppWidgetProviderInfo} object</dt>
- <dd>Describes the metadata for an App Widget, such as the App Widget's layout, update frequency,
+ <dd>Describes the metadata for an App Widget, such as the App Widget's layout,
+update frequency,
and the AppWidgetProvider class. This should be defined in XML.</dd>
<dt>{@link android.appwidget.AppWidgetProvider} class implementation</dt>
- <dd>Defines the basic methods that allow you to programmatically interface with the App Widget,
- based on broadcast events. Through it, you will receive broadcasts when the App Widget is updated,
+ <dd>Defines the basic methods that allow you to programmatically interface
+with the App Widget,
+ based on broadcast events. Through it, you will receive broadcasts when the
+App Widget is updated,
enabled, disabled and deleted.</dd>
<dt>View layout</dt>
<dd>Defines the initial layout for the App Widget, defined in XML.</dd>
</dl>
-<p>Additionally, you can implement an App Widget configuration Activity. This is an optional
-{@link android.app.Activity} that launches when the user adds your App Widget and allows him or her
+<p>Additionally, you can implement an App Widget configuration Activity. This is
+an optional
+{@link android.app.Activity} that launches when the user adds your App Widget
+and allows him or her
to modify App Widget settings at create-time.</p>
<p>The following sections describe how to setup each of these components.</p>
@@ -85,7 +113,8 @@
<h2 id="Manifest">Declaring an App Widget in the Manifest</h2>
-<p>First, declare the {@link android.appwidget.AppWidgetProvider} class in your application's
+<p>First, declare the {@link android.appwidget.AppWidgetProvider} class in your
+application's
<code>AndroidManifest.xml</code> file. For example:</p>
<pre>
@@ -98,24 +127,32 @@
</receiver>
</pre>
-<p>The <code><receiver></code> element requires the <code>android:name</code>
+<p>The <code><receiver></code> element requires the
+<code>android:name</code>
attribute, which specifies the {@link android.appwidget.AppWidgetProvider} used
by the App Widget.</p>
-<p>The <code><intent-filter></code> element must include an <code><action></code>
+<p>The <code><intent-filter></code> element must include an
+<code><action></code>
element with the <code>android:name</code> attribute. This attribute specifies
that the {@link android.appwidget.AppWidgetProvider} accepts the {@link
-android.appwidget.AppWidgetManager#ACTION_APPWIDGET_UPDATE ACTION_APPWIDGET_UPDATE} broadcast.
-This is the only broadcast that you must explicitly declare. The {@link android.appwidget.AppWidgetManager}
-automatically sends all other App Widget broadcasts to the AppWidgetProvider as necessary.</p>
+android.appwidget.AppWidgetManager#ACTION_APPWIDGET_UPDATE
+ACTION_APPWIDGET_UPDATE} broadcast.
+This is the only broadcast that you must explicitly declare. The {@link
+android.appwidget.AppWidgetManager}
+automatically sends all other App Widget broadcasts to the AppWidgetProvider as
+necessary.</p>
<p>The <code><meta-data></code> element specifies the
{@link android.appwidget.AppWidgetProviderInfo} resource and requires the
following attributes:</p>
<ul>
- <li><code>android:name</code> - Specifies the metadata name. Use <code>android.appwidget.provider</code>
- to identify the data as the {@link android.appwidget.AppWidgetProviderInfo} descriptor.</li>
- <li><code>android:resource</code> - Specifies the {@link android.appwidget.AppWidgetProviderInfo}
+ <li><code>android:name</code> - Specifies the metadata name. Use
+<code>android.appwidget.provider</code>
+ to identify the data as the {@link android.appwidget.AppWidgetProviderInfo}
+descriptor.</li>
+ <li><code>android:resource</code> - Specifies the {@link
+android.appwidget.AppWidgetProviderInfo}
resource location.</li>
</ul>
@@ -123,10 +160,13 @@
<h2 id="MetaData">Adding the AppWidgetProviderInfo Metadata</h2>
<p>The {@link android.appwidget.AppWidgetProviderInfo} defines the essential
-qualities of an App Widget, such as its minimum layout dimensions, its initial layout resource,
-how often to update the App Widget, and (optionally) a configuration Activity to launch at create-time.
+qualities of an App Widget, such as its minimum layout dimensions, its initial
+layout resource,
+how often to update the App Widget, and (optionally) a configuration Activity to
+launch at create-time.
Define the AppWidgetProviderInfo object in an XML resource using a single
-<code><appwidget-provider></code> element and save it in the project's <code>res/xml/</code>
+<code><appwidget-provider></code> element and save it in the project's
+<code>res/xml/</code>
folder.</p>
<p>For example:</p>
@@ -136,71 +176,131 @@
android:minWidth="294dp"
android:minHeight="72dp"
android:updatePeriodMillis="86400000"
+ android:previewImage="@drawable/preview"
android:initialLayout="@layout/example_appwidget"
- android:configure="com.example.android.ExampleAppWidgetConfigure" >
+ android:configure="com.example.android.ExampleAppWidgetConfigure"
+ android:resizeMode="horizontal|vertical">
</appwidget-provider>
</pre>
<p>Here's a summary of the <code><appwidget-provider></code> attributes:</p>
<ul>
- <li>The values for the <code>minWidth</code> and <code>minHeight</code> attributes specify the minimum
- area required by the App Widget's layout.
- <p>The default Home screen positions App Widgets in its window based on a grid of
- cells that have a defined height and width. If the values for an App Widget's minimum width
+ <li>The values for the <code>minWidth</code> and <code>minHeight</code>
+attributes specify the minimum
+ area required by the App Widget's layout.
+ <p>The default Home screen positions App Widgets in its window based on a
+grid of
+ cells that have a defined height and width. If the values for an App
+Widget's minimum width
or height don't match the dimensions of the cells,
then the App Widget dimensions round <em>up</em> to the nearest cell size.
- (See the <a href="{@docRoot}guide/practices/ui_guidelines/widget_design.html">App Widget Design
+ (See the <a
+href="{@docRoot}guide/practices/ui_guidelines/widget_design.html">App Widget
+Design
Guidelines</a> for more information on the Home screen cell sizes.)</p>
- <p>Because the Home screen's layout orientation (and thus, the cell sizes) can change,
- as a rule of thumb, you should assume the worst-case cell size of 74 pixels for the height
- <em>and</em> width of a cell. However, you must subtract 2 from the final dimension to account
- for any integer rounding errors that occur in the pixel count. To find your minimum width
+ <p>Because the Home screen's layout orientation (and thus, the cell sizes)
+can change,
+ as a rule of thumb, you should assume the worst-case cell size of 74 pixels
+for the height
+ <em>and</em> width of a cell. However, you must subtract 2 from the final
+dimension to account
+ for any integer rounding errors that occur in the pixel count. To find your
+minimum width
and height in density-independent pixels (dp), use this formula:<br/>
<code>(number of cells * 74) - 2</code><br/>
- Following this formula, you should use 72 dp for a height of one cell, 294 dp and for a width of four cells.</p>
+ Following this formula, you should use 72 dp for a height of one cell, 294
+dp and for a width of four cells.</p>
+<p class="note"><strong>Note:</strong> To make your app widget portable across
+devices, your app widget's minimum size should never be larger than 4 x 4 cells.
+See the <a
+href="{@docRoot}guide/practices/ui_guidelines/widget_design.htmll#sizes">App
+Widget Design Guidelines</a> for more discussion of Home screen cell sizes.</p>
</li>
- <li>The <code>updatePeriodMillis</code> attribute defines how often the App Widget framework should
- request an update from the {@link android.appwidget.AppWidgetProvider} by calling the
- {@link android.appwidget.AppWidgetProvider#onUpdate(Context,AppWidgetManager,int[])
- onUpdate()} method. The actual update is not guaranteed to occur exactly on time with this value
- and we suggest updating as infrequently as possible—perhaps no more than once an hour to
- conserve the battery. You might also allow the user to adjust the frequency in a
- configuration—some people might want a stock ticker to update every 15 minutes, or maybe
- only four times a day.
- <p class="note"><strong>Note:</strong> If the device is asleep when it is time for an update
- (as defined by <code>updatePeriodMillis</code>), then the device will wake up in order
- to perform the update. If you don't update more than once per hour, this probably won't
- cause significant problems for the battery life. If, however, you need to update more
- frequently and/or you do not need to update while the device is asleep, then you can instead
- perform updates based on an alarm that will not wake the device. To do so, set an alarm with
- an Intent that your AppWidgetProvider receives, using the {@link android.app.AlarmManager}.
- Set the alarm type to either {@link android.app.AlarmManager#ELAPSED_REALTIME} or
+ <li>The <code>updatePeriodMillis</code> attribute defines how often the App
+Widget framework should request an update from the {@link
+android.appwidget.AppWidgetProvider} by calling the
+{@link android.appwidget.AppWidgetProvider#onUpdate(android.content.Context,android.appwidget.AppWidgetManager,int[]) onUpdate()}
+callback method. The actual update
+is not guaranteed to occur exactly on time with this value and we suggest
+updating as infrequently as possible—perhaps no more than once an hour to
+conserve the battery. You might also allow the user to adjust the frequency in a
+configuration—some people might want a stock ticker to update every 15
+minutes, or maybe only four times a day.
+ <p class="note"><strong>Note:</strong> If the device is asleep when it
+is time for an update
+ (as defined by <code>updatePeriodMillis</code>), then the device will
+wake up in order
+ to perform the update. If you don't update more than once per hour, this
+probably won't
+ cause significant problems for the battery life. If, however, you need
+to update more
+ frequently and/or you do not need to update while the device is asleep,
+then you can instead
+ perform updates based on an alarm that will not wake the device. To do
+so, set an alarm with
+ an Intent that your AppWidgetProvider receives, using the {@link
+android.app.AlarmManager}.
+ Set the alarm type to either {@link
+android.app.AlarmManager#ELAPSED_REALTIME} or
{@link android.app.AlarmManager#RTC}, which will only
- deliver the alarm when the device is awake. Then set <code>updatePeriodMillis</code> to
+ deliver the alarm when the device is awake. Then set
+<code>updatePeriodMillis</code> to
zero (<code>"0"</code>).</p>
</li>
- <li>The <code>initialLayout</code> attribute points to the layout resource that defines the
+ <li>The <code>initialLayout</code> attribute points to the layout resource
+that defines the
App Widget layout.</li>
- <li>The <code>configure</code> attribute defines the {@link android.app.Activity} to launch when
- the user adds the App Widget, in order for him or her to configure App Widget properties. This is optional
- (read <a href="#Configuring">Creating an App Widget Configuration Activity</a> below).</li>
-</ul>
+ <li>The <code>configure</code> attribute defines the {@link
+android.app.Activity} to launch when
+ the user adds the App Widget, in order for him or her to configure App
+Widget properties. This is optional
+ (read <a href="#Configuring">Creating an App Widget Configuration
+Activity</a> below).</li>
+
+ <li>The <code>previewImage</code> attribute specifies a preview of what the
+app widget will look like after it's configured, which the user sees when
+selecting the app widget. If not supplied, the user instead sees your
+application's launcher icon. This field corresponds to the
+<code>android:previewImage</code> attribute in the <code><receiver></code>
+element in the <code>AndroidManifest.xml</code> file. For more discussion of
+using <code>previewImage</code>, see <a href="#preview">Setting a Preview
+Image</a>. Introduced in Android 3.0.</li>
-<p>See the {@link android.appwidget.AppWidgetProviderInfo} class for more information on the
+ <li>The <code>autoAdvanceViewId</code> attribute specifies the view ID of the
+app widget subview that should be auto-advanced by the widget's host. Introduced in Android 3.0.</li>
+
+<li>The <code>resizeMode</code> attribute specifies the rules by which a widget
+can be resized. You use this attribute to make homescreen widgets
+resizeable—horizontally, vertically, or on both axes. Users touch-hold a
+widget to show its resize handles, then drag the horizontal and/or vertical
+handles to change the size on the layout grid. Values for the
+<code>resizeMode</code> attribute include "horizontal", "vertical", and "none".
+To declare a widget as resizeable horizontally and vertically, supply the value
+"horizontal|vertical". Introduced in Android 3.1.</li> </ul>
+
+<p>See the {@link android.appwidget.AppWidgetProviderInfo} class for more
+information on the
attributes accepted by the <code><appwidget-provider></code> element.</p>
<h2 id="CreatingLayout">Creating the App Widget Layout</h2>
-<p>You must define an initial layout for your App Widget in XML and save it in the project's
-<code>res/layout/</code> directory. You can design your App Widget using the View objects listed
-below, but before you begin designing your App Widget, please read and understand the
-<a href="{@docRoot}guide/practices/ui_guidelines/widget_design.html">App Widget Design
+<p>You must define an initial layout for your App Widget in XML and save it in
+the project's
+<code>res/layout/</code> directory. You can design your App Widget using the
+View objects listed
+below, but before you begin designing your App Widget, please read and
+understand the
+<a href="{@docRoot}guide/practices/ui_guidelines/widget_design.html">App Widget
+Design
Guidelines</a>.</p>
<p>Creating the App Widget layout is simple if you're
-familiar with <a href="{@docRoot}guide/topics/ui/declaring-layout.html">Declaring Layout in XML</a>.
-However, you must be aware that App Widget layouts are based on {@link android.widget.RemoteViews},
+familiar with <a
+href="{@docRoot}guide/topics/ui/declaring-layout.html">Declaring Layout in
+XML</a>.
+However, you must be aware that App Widget layouts are based on {@link
+android.widget.RemoteViews},
which do not support every kind of layout or view widget.</p>
<p>A RemoteViews object (and, consequently, an App Widget) can support the
@@ -221,6 +321,7 @@
<li>{@link android.widget.ImageView}</li>
<li>{@link android.widget.ProgressBar}</li>
<li>{@link android.widget.TextView}</li>
+ <li>{@link android.widget.ViewFlipper}</li>
</ul>
<p>Descendants of these classes are not supported.</p>
@@ -230,66 +331,90 @@
<div class="sidebox-wrapper">
<div class="sidebox">
- <p>You must declare your AppWidgetProvider class implementation as a broadcast receiver
+ <p>You must declare your AppWidgetProvider class implementation as a
+broadcast receiver
using the <code><receiver></code> element in the AndroidManifest (see
<a href="#Manifest">Declaring an App Widget in the Manifest</a> above).</p>
</div>
</div>
-<p>The {@link android.appwidget.AppWidgetProvider} class extends BroadcastReceiver as a convenience
-class to handle the App Widget broadcasts. The AppWidgetProvider receives only the event broadcasts that
-are relevant to the App Widget, such as when the App Widget is updated, deleted, enabled, and disabled.
-When these broadcast events occur, the AppWidgetProvider receives the following method calls:</p>
+<p>The {@link android.appwidget.AppWidgetProvider} class extends
+BroadcastReceiver as a convenience
+class to handle the App Widget broadcasts. The AppWidgetProvider receives only
+the event broadcasts that
+are relevant to the App Widget, such as when the App Widget is updated, deleted,
+enabled, and disabled.
+When these broadcast events occur, the AppWidgetProvider receives the following
+method calls:</p>
<dl>
- <dt>{@link android.appwidget.AppWidgetProvider#onUpdate(Context,AppWidgetManager,int[])}</dt>
- <dd>This is called to update the App Widget at intervals defined by the <code>updatePeriodMillis</code>
+ <dt>
+ {@link android.appwidget.AppWidgetProvider#onUpdate(android.content.Context,android.appwidget.AppWidgetManager,int[]) onUpdate()}
+</dt>
+ <dd>This is called to update the App Widget at intervals defined by the
+<code>updatePeriodMillis</code>
attribute in the AppWidgetProviderInfo (see <a href="#MetaData">Adding the
AppWidgetProviderInfo Metadata</a> above). This method is also called
when the user adds the App Widget, so it should perform the essential setup,
such as define event handlers for Views and start a temporary
- {@link android.app.Service}, if necessary. However, if you have declared a configuration
- Activity, <strong>this method is not called</strong> when the user adds the App Widget,
+ {@link android.app.Service}, if necessary. However, if you have declared a
+configuration
+ Activity, <strong>this method is not called</strong> when the user adds the
+App Widget,
but is called for the subsequent updates. It is the responsibility of the
- configuration Activity to perform the first update when configuration is done.
- (See <a href="#Configuring">Creating an App Widget Configuration Activity</a> below.)</dd>
+ configuration Activity to perform the first update when configuration is
+done.
+ (See <a href="#Configuring">Creating an App Widget Configuration
+Activity</a> below.)</dd>
<dt>{@link android.appwidget.AppWidgetProvider#onDeleted(Context,int[])}</dt>
- <dd>This is called every time an App Widget is deleted from the App Widget host.</dd>
+ <dd>This is called every time an App Widget is deleted from the App Widget
+host.</dd>
<dt>{@link android.appwidget.AppWidgetProvider#onEnabled(Context)}</dt>
- <dd>This is called when an instance the App Widget is created for the first time. For example, if the user
+ <dd>This is called when an instance the App Widget is created for the first
+time. For example, if the user
adds two instances of your App Widget, this is only called the first time.
- If you need to open a new database or perform other setup that only needs to occur once
+ If you need to open a new database or perform other setup that only needs to
+occur once
for all App Widget instances, then this is a good place to do it.</dd>
<dt>{@link android.appwidget.AppWidgetProvider#onDisabled(Context)}</dt>
- <dd>This is called when the last instance of your App Widget is deleted from the App Widget host.
+ <dd>This is called when the last instance of your App Widget is deleted from
+the App Widget host.
This is where you should clean up any work done in
{@link android.appwidget.AppWidgetProvider#onEnabled(Context)},
such as delete a temporary database.</dd>
<dt>{@link android.appwidget.AppWidgetProvider#onReceive(Context,Intent)}</dt>
- <dd>This is called for every broadcast and before each of the above callback methods.
- You normally don't need to implement this method because the default AppWidgetProvider
+ <dd>This is called for every broadcast and before each of the above callback
+methods.
+ You normally don't need to implement this method because the default
+AppWidgetProvider
implementation filters all App Widget broadcasts and calls the above
methods as appropriate.</dd>
</dl>
-<p class="warning"><strong>Note:</strong> In Android 1.5, there is a known issue in which the
-<code>onDeleted()</code> method will not be called when it should be. To work around this issue,
-you can implement {@link android.appwidget.AppWidgetProvider#onReceive(Context,Intent)
+<p class="warning"><strong>Note:</strong> In Android 1.5, there is a known issue
+in which the
+<code>onDeleted()</code> method will not be called when it should be. To work
+around this issue,
+you can implement {@link
+android.appwidget.AppWidgetProvider#onReceive(Context,Intent)
onReceive()} as described in this
-<a href="http://groups.google.com/group/android-developers/msg/e405ca19df2170e2">Group post</a>
+<a
+href="http://groups.google.com/group/android-developers/msg/e405ca19df2170e2">
+Group post</a>
to receive the <code>onDeleted()</code> callback.
</p>
<p>The most important AppWidgetProvider callback is
-{@link android.appwidget.AppWidgetProvider#onUpdate(Context,AppWidgetManager,int[])
-onUpdated()} because it is called when each App Widget is added to a host (unless you use
-a configuration Activity). If your App Widget accepts any
-user interaction events, then you need to register the event handlers in this callback.
-If your App Widget doesn't create temporary
-files or databases, or perform other work that requires clean-up, then
-{@link android.appwidget.AppWidgetProvider#onUpdate(Context,AppWidgetManager,int[])
-onUpdated()} may be the only callback method you need to define. For example, if you want an App Widget
-with a button that launches an Activity when clicked, you could use the following
+{@link android.appwidget.AppWidgetProvider#onUpdate(android.content.Context, android.appwidget.AppWidgetManager, int[]) onUpdate()}
+because it is called when
+each App Widget is added to a host (unless you use a configuration Activity). If
+your App Widget accepts any user interaction events, then you need to register
+the event handlers in this callback. If your App Widget doesn't create temporary
+files or databases, or perform other work that requires clean-up, then
+{@link android.appwidget.AppWidgetProvider#onUpdate(android.content.Context, android.appwidget.AppWidgetManager, int[]) onUpdate()}
+may be the only callback
+method you need to define. For example, if you want an App Widget with a button
+that launches an Activity when clicked, you could use the following
implementation of AppWidgetProvider:</p>
<pre>
@@ -306,11 +431,12 @@
Intent intent = new Intent(context, ExampleActivity.class);
PendingIntent pendingIntent = PendingIntent.getActivity(context, 0, intent, 0);
- // Get the layout for the App Widget and attach an on-click listener to the button
+ // Get the layout for the App Widget and attach an on-click listener
+ // to the button
RemoteViews views = new RemoteViews(context.getPackageName(), R.layout.appwidget_provider_layout);
views.setOnClickPendingIntent(R.id.button, pendingIntent);
- // Tell the AppWidgetManager to perform an update on the current App Widget
+ // Tell the AppWidgetManager to perform an update on the current app widget
appWidgetManager.updateAppWidget(appWidgetId, views);
}
}
@@ -318,43 +444,51 @@
</pre>
<p>This AppWidgetProvider defines only the
-{@link android.appwidget.AppWidgetProvider#onUpdate(Context,AppWidgetManager,int[])
-onUpdated()} method for the purpose
-of defining a {@link android.app.PendingIntent} that launches an {@link android.app.Activity}
-and attaching it to the App Widget's button
-with {@link android.widget.RemoteViews#setOnClickPendingIntent(int,PendingIntent)}.
-Notice that it includes a loop that iterates through each entry in <code>appWidgetIds</code>, which
-is an array of IDs that identify each App Widget created by this provider.
-In this way, if the user creates more than one instance of the App Widget, then they are
-all updated simultaneously. However, only one <code>updatePeriodMillis</code> schedule will be
-managed for all instances of the App Widget. For example, if the update schedule is defined
-to be every two hours, and a second instance
-of the App Widget is added one hour after the first one, then they will both be updated
-on the period defined by the first one and the second update period will be ignored
-(they'll both be updated every two hours, not every hour).</p>
+{@link
+android.appwidget.AppWidgetProvider#onUpdate(android.content.Context, android.appwidget.AppWidgetManager, int[]) onUpdate()}
+method for the purpose of
+defining a {@link android.app.PendingIntent} that launches an {@link
+android.app.Activity} and attaching it to the App Widget's button with {@link
+android.widget.RemoteViews#setOnClickPendingIntent(int,PendingIntent)}. Notice
+that it includes a loop that iterates through each entry in
+<code>appWidgetIds</code>, which is an array of IDs that identify each App
+Widget created by this provider. In this way, if the user creates more than one
+instance of the App Widget, then they are all updated simultaneously. However,
+only one <code>updatePeriodMillis</code> schedule will be managed for all
+instances of the App Widget. For example, if the update schedule is defined to
+be every two hours, and a second instance of the App Widget is added one hour
+after the first one, then they will both be updated on the period defined by the
+first one and the second update period will be ignored (they'll both be updated
+every two hours, not every hour).</p>
-<p class="note"><strong>Note:</strong> Because {@link android.appwidget.AppWidgetProvider} is an
-extension of {@link android.content.BroadcastReceiver}, your process is not guaranteed to keep
-running after the callback methods return (see {@link android.content.BroadcastReceiver} for
-information about the broadcast lifecycle). If your App Widget setup process can take several
-seconds (perhaps while performing web requests) and you require that your process continues,
-consider starting a {@link android.app.Service}
-in the {@link android.appwidget.AppWidgetProvider#onUpdate(Context,AppWidgetManager,int[])
-onUpdated()} method. From within the Service, you can perform your own updates to the App Widget
-without worrying about the AppWidgetProvider closing down due to an
-<a href="{@docRoot}guide/practices/design/responsiveness.html">Application Not Responding</a>
-(ANR) error. See the
-<a href="http://code.google.com/p/wiktionary-android/source/browse/trunk/Wiktionary/src/com/example/android/wiktionary/WordWidget.java">Wiktionary
-sample's AppWidgetProvider</a> for an example of an App Widget running a {@link android.app.Service}.</p>
+<p class="note"><strong>Note:</strong> Because {@link
+android.appwidget.AppWidgetProvider} is an extension of {@link
+android.content.BroadcastReceiver}, your process is not guaranteed to keep
+running after the callback methods return (see {@link
+android.content.BroadcastReceiver} for information about the broadcast
+lifecycle). If your App Widget setup process can take several seconds (perhaps
+while performing web requests) and you require that your process continues,
+consider starting a {@link android.app.Service} in the
+{@link android.appwidget.AppWidgetProvider#onUpdate(Context,AppWidgetManager,int[]) onUpdate()}
+method. From within the Service, you can perform your own updates
+to the App Widget without worrying about the AppWidgetProvider closing down due
+to an <a href="{@docRoot}guide/practices/design/responsiveness.html">Application
+Not Responding</a> (ANR) error. See the <a
+href="http://code.google.com/p/wiktionary-android/source/browse/trunk/Wiktionary
+/src/com/example/android/wiktionary/WordWidget.java">Wiktionary sample's
+AppWidgetProvider</a> for an example of an App Widget running a {@link
+android.app.Service}.</p>
<p>Also see the <a
-href="{@docRoot}resources/samples/ApiDemos/src/com/example/android/apis/appwidget/ExampleAppWidgetProvider.html">
+href="{@docRoot}resources/samples/ApiDemos/src/com/example/android/apis/
+appwidget/ExampleAppWidgetProvider.html">
ExampleAppWidgetProvider.java</a> sample class.</p>
<h3 id="ProviderBroadcasts">Receiving App Widget broadcast Intents</h3>
-<p>{@link android.appwidget.AppWidgetProvider} is just a convenience class. If you would like
+<p>{@link android.appwidget.AppWidgetProvider} is just a convenience class. If
+you would like
to receive the App Widget broadcasts directly, you can implement your own
{@link android.content.BroadcastReceiver} or override the
{@link android.appwidget.AppWidgetProvider#onReceive(Context,Intent)} callback.
@@ -370,28 +504,36 @@
<h2 id="Configuring">Creating an App Widget Configuration Activity</h2>
-<p>If you would like the user to configure settings when he or she adds a new App Widget,
-you can create an App Widget configuration Activity. This {@link android.app.Activity}
-will be automatically launched by the App Widget host and allows the user to configure
-available settings for the App Widget at create-time, such as the App Widget color, size,
+<p>If you would like the user to configure settings when he or she adds a new
+App Widget,
+you can create an App Widget configuration Activity. This {@link
+android.app.Activity}
+will be automatically launched by the App Widget host and allows the user to
+configure
+available settings for the App Widget at create-time, such as the App Widget
+color, size,
update period or other functionality settings.</p>
-<p>The configuration Activity should be declared as a normal Activity in the Android manifest file.
+<p>The configuration Activity should be declared as a normal Activity in the
+Android manifest file.
However, it will be launched by the App Widget host with the {@link
-android.appwidget.AppWidgetManager#ACTION_APPWIDGET_CONFIGURE ACTION_APPWIDGET_CONFIGURE} action,
+android.appwidget.AppWidgetManager#ACTION_APPWIDGET_CONFIGURE
+ACTION_APPWIDGET_CONFIGURE} action,
so the Activity needs to accept this Intent. For example:</p>
<pre>
<activity android:name=".ExampleAppWidgetConfigure">
<intent-filter>
- <action android:name="android.appwidget.action.APPWIDGET_CONFIGURE" />
+ <action android:name="android.appwidget.action.APPWIDGET_CONFIGURE"/>
</intent-filter>
</activity>
</pre>
-<p>Also, the Activity must be declared in the AppWidgetProviderInfo XML file, with the
+<p>Also, the Activity must be declared in the AppWidgetProviderInfo XML file,
+with the
<code>android:configure</code> attribute (see <a href="#MetaData">Adding
-the AppWidgetProviderInfo Metadata</a> above). For example, the configuration Activity
+the AppWidgetProviderInfo Metadata</a> above). For example, the configuration
+Activity
can be declared like this:</p>
<pre>
@@ -402,32 +544,45 @@
</appwidget-provider>
</pre>
-<p>Notice that the Activity is declared with a fully-qualified namespace, because
+<p>Notice that the Activity is declared with a fully-qualified namespace,
+because
it will be referenced from outside your package scope.</p>
-<p>That's all you need to get started with a configuration Activity. Now all you need is the actual
-Activity. There are, however, two important things to remember when you implement the Activity:</p>
+<p>That's all you need to get started with a configuration Activity. Now all you
+need is the actual
+Activity. There are, however, two important things to remember when you
+implement the Activity:</p>
<ul>
- <li>The App Widget host calls the configuration Activity and the configuration Activity should always
+ <li>The App Widget host calls the configuration Activity and the configuration
+Activity should always
return a result. The result should include the App Widget ID
- passed by the Intent that launched the Activity (saved in the Intent extras as
+ passed by the Intent that launched the Activity (saved in the Intent extras
+as
{@link android.appwidget.AppWidgetManager#EXTRA_APPWIDGET_ID}).</li>
- <li>The {@link android.appwidget.AppWidgetProvider#onUpdate(Context,AppWidgetManager,int[])
- onUpdate()} method <strong>will not be called</strong> when the App Widget is created
- (the system will not send the ACTION_APPWIDGET_UPDATE broadcast when a configuration Activity
- is launched). It is the responsibility of the configuration Activity to request an update from the
+ <li>The
+ {@link android.appwidget.AppWidgetProvider#onUpdate(Context,AppWidgetManager,int[]) onUpdate()}
+ method <strong>will not be called</strong> when the App Widget
+is created
+ (the system will not send the ACTION_APPWIDGET_UPDATE broadcast when a
+configuration Activity
+ is launched). It is the responsibility of the configuration Activity to
+request an update from the
AppWidgetManager when the App Widget is first created. However,
- {@link android.appwidget.AppWidgetProvider#onUpdate(Context,AppWidgetManager,int[])
- onUpdate()} will be called for subsequent updates—it is only skipped the first time.</li>
+{@link android.appwidget.AppWidgetProvider#onUpdate(Context,AppWidgetManager,int[]) onUpdate()}
+ will be called for subsequent updates—it is only skipped
+the first time.</li>
</ul>
-<p>See the code snippets in the following section for an example of how to return a result
+<p>See the code snippets in the following section for an example of how to
+return a result
from the configuration and update the App Widget.</p>
-<h3 id="UpdatingFromTheConfiguration">Updating the App Widget from the configuration Activity</h3>
+<h3 id="UpdatingFromTheConfiguration">Updating the App Widget from the
+configuration Activity</h3>
-<p>When an App Widget uses a configuration Activity, it is the responsibility of the Activity
+<p>When an App Widget uses a configuration Activity, it is the responsibility of
+the Activity
to update the App Widget when configuration is complete.
You can do so by requesting an update directly from the
{@link android.appwidget.AppWidgetManager}.</p>
@@ -448,20 +603,24 @@
</pre>
</li>
<li>Perform your App Widget configuration.</li>
- <li>When the configuration is complete, get an instance of the AppWidgetManager by calling
+ <li>When the configuration is complete, get an instance of the
+AppWidgetManager by calling
{@link android.appwidget.AppWidgetManager#getInstance(Context)}:
<pre>
AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(context);
</pre>
</li>
- <li>Update the App Widget with a {@link android.widget.RemoteViews} layout by calling
+ <li>Update the App Widget with a {@link android.widget.RemoteViews} layout by
+calling
{@link android.appwidget.AppWidgetManager#updateAppWidget(int,RemoteViews)}:
<pre>
-RemoteViews views = new RemoteViews(context.getPackageName(), R.layout.example_appwidget);
+RemoteViews views = new RemoteViews(context.getPackageName(),
+R.layout.example_appwidget);
appWidgetManager.updateAppWidget(mAppWidgetId, views);
</pre>
</li>
- <li>Finally, create the return Intent, set it with the Activity result, and finish the Activity:</li>
+ <li>Finally, create the return Intent, set it with the Activity result, and
+finish the Activity:</li>
<pre>
Intent resultValue = new Intent();
resultValue.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, mAppWidgetId);
@@ -471,14 +630,657 @@
</li>
</ol>
-<p class="note"><strong>Tip:</strong> When your configuration Activity first opens, set
-the Activity result to RESULT_CANCELED. This way, if the user backs-out of the Activity before
-reaching the end, the App Widget host is notified that the configuration was cancelled and the
+<p class="note"><strong>Tip:</strong> When your configuration Activity first
+opens, set
+the Activity result to RESULT_CANCELED. This way, if the user backs-out of the
+Activity before
+reaching the end, the App Widget host is notified that the configuration was
+cancelled and the
App Widget will not be added.</p>
<p>See the <a
-href="{@docRoot}resources/samples/ApiDemos/src/com/example/android/apis/appwidget/ExampleAppWidgetConfigure.html">
+href="{@docRoot}resources/samples/ApiDemos/src/com/example/android/apis/
+appwidget/ExampleAppWidgetConfigure.html">
ExampleAppWidgetConfigure.java</a> sample class in ApiDemos for an example.</p>
+<h2 id="preview">Setting a Preview Image</h2>
+
+<p>Android 3.0 introduces the {@link
+
+
+android.appwidget.AppWidgetProviderInfo#previewImage} field, which specifies a
+preview of what the app widget looks like. This preview is shown to the user from the
+widget picker. If this field is not supplied, the app widget's icon is used for
+the preview.</p>
+
+<p>This is how you specify this setting in XML:</p>
+
+<pre><appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android"
+ ...
+ android:previewImage="@drawable/preview">
+</appwidget-provider></pre>
+
+<p>To help create a preview image for your app widget (to specify in the {@link
+android.appwidget.AppWidgetProviderInfo#previewImage} field), the Android
+emulator includes an application called "Widget Preview." To create a
+preview image, launch this application, select the app widget for your
+application and set it up how you'd like your preview image to appear, then save
+it and place it in your application's drawable resources.</p>
+
+<h2 id="collections">Using App Widgets with Collections</h2>
+
+<p>Android 3.0 introduces App Widgets with collections. These kinds of App
+Widgets use the {@link android.widget.RemoteViewsService} to display collections
+that are backed by remote data, such as from a <a
+href="{@docRoot}guide/topics/providers/content-providers.html">content
+provider</a>. The data provided by the {@link android.widget.RemoteViewsService}
+is presented in the App Widget using one of the following view types, which
+we’ll refer to as “collection views:”</p>
+
+<dl>
+ <dt>{@link android.widget.ListView}</dt>
+ <dd>A view that shows items in a
+vertically scrolling
+list. For an example, see the Gmail app widget. </dd>
+<dt>{@link android.widget.GridView}</dt>
+<dd>A view that shows items in
+two-dimensional scrolling grid. For an example, see the Bookmarks app
+widget.</dd>
+<dt>{@link android.widget.StackView}</dt>
+<dd>A
+stacked card view (kind of like a rolodex), where the user can flick the front
+card up/down to see the previous/next card, respectively. Examples include
+the YouTube and Books app widgets. </dd>
+<dt>{@link android.widget.AdapterViewFlipper}</dt>
+<dd>An adapter-backed simple
+{@link
+android.widget.ViewAnimator} that animates between two or more views. Only one
+child is shown at a time. </dd>
+</dl>
+
+<p>As stated above, these collection views display collections backed by remote
+data. This means that they use an {@link android.widget.Adapter} to bind their
+user interface to their data. An {@link android.widget.Adapter} binds individual
+items from a set of data into individual {@link android.view.View} objects.
+Because these collection views are backed by adapters, the Android framework
+must include extra architecture to support their use in app widgets. In the
+context of an app widget, the {@link android.widget.Adapter} is replaced by a
+{@link android.widget.RemoteViewsService.RemoteViewsFactory RemoteViewsFactory},
+which is simply a thin wrapper around the {@link android.widget.Adapter}
+interface.
+ When
+requested for a specific item in the collection, the {@link
+android.widget.RemoteViewsService.RemoteViewsFactory RemoteViewsFactory} creates
+and returns the item for the collection as a {@link android.widget.RemoteViews}
+object.
+In order to include a collection view in your app widget, you
+must implement {@link android.widget.RemoteViewsService} and {@link
+android.widget.RemoteViewsService.RemoteViewsFactory RemoteViewsFactory}.</p>
+
+<p> {@link android.widget.RemoteViewsService} is a service that allows a remote
+adapter to request {@link
+android.widget.RemoteViews} objects. {@link
+android.widget.RemoteViewsService.RemoteViewsFactory RemoteViewsFactory} is an
+interface for an adapter between a collection view (such as {@link
+android.widget.ListView}, {@link android.widget.GridView}, and so on) and the
+underlying data for that view. From the <a
+href="{@docRoot}resources/samples/StackWidget/index.html">StackView Widget
+sample</a>, here is an example of the boilerplate code you use to implement
+this service and interface:
+</p>
+
+<pre>
+public class StackWidgetService extends RemoteViewsService {
+ @Override
+ public RemoteViewsFactory onGetViewFactory(Intent intent) {
+ return new StackRemoteViewsFactory(this.getApplicationContext(), intent);
+ }
+}
+
+class StackRemoteViewsFactory implements RemoteViewsService.RemoteViewsFactory {
+
+//... include adapter-like methods here. See the StackView Widget sample.
+
+}
+</pre>
+
+<h3 id="collection_sample">Sample application</h3>
+
+<p>The code excerpts in this section are drawn from the <a
+href="{@docRoot}resources/samples/StackWidget/index.html">StackView Widget
+sample</a>:</p>
+
+<p>
+<img src="{@docRoot}resources/samples/images/StackWidget.png" alt="StackView
+Widget" />
+</p>
+
+<p>This sample consists of a stack of 10 views, which display the values
+<code>"0!"</code> through <code>"9!"</code> The sample
+app widget has these primary behaviors:</p>
+
+<ul>
+
+ <li>The user can vertically fling the top view in the
+app widget to display the next or previous view. This is a built-in StackView
+behavior.</li>
+
+ <li>Without any user interaction, the app widget automatically advances
+through
+its views in sequence, like a slide show. This is due to the setting
+<code>android:autoAdvanceViewId="@id/stack_view"</code> in the
+<code>res/xml/stackwidgetinfo.xml</code> file. This setting applies to the view
+ID,
+which in this case is the view ID of the stack view.</li>
+
+ <li>If the user touches the top view, the app widget displays the {@link
+android.widget.Toast} message "Touched view <em>n</em>," where
+<em>n</em> is the index (position) of the touched view. For more discussion of
+how this is implemented, see
+<a href="#behavior">Adding behavior to individual items</a>.</li>
+
+</ul>
+<h3 id="implementing_collections">Implementing app widgets with collections</h3>
+
+<p>To implement an App Widget with collections, you follow the same basic steps
+you would use to implement any app widget. The following sections describe the
+additional steps you need to perform to implement an App Widget with
+collections.</p>
+
+<h4>Manifest for app widgets with collections</h4>
+
+<p> In addition to the requirements listed in <a href="#Manifest">Declaring an
+App Widget in the Manifest</a>, to make it possible for App Widgets with
+collections to bind to your {@link android.widget.RemoteViewsService}, you must
+declare the service in your manifest file with the permission {@link
+android.Manifest.permission#BIND_REMOTEVIEWS}. This prevents other applications
+from freely accessing your app widget's data. For example, when creating an App
+Widget that uses {@link android.widget.RemoteViewsService} to populate a
+collection view, the manifest entry may look like this:</p>
+
+<pre><service android:name="MyWidgetService"
+...
+android:permission="android.permission.BIND_REMOTEVIEWS" /></pre>
+
+<p>The line <code>android:name="MyWidgetService"</code>
+refers to your subclass of {@link android.widget.RemoteViewsService}. </p>
+
+<h4>Layout for app widgets with collections</h4>
+
+<p>The main requirement for your app widget layout XML file is that it
+include one of the collection views: {@link android.widget.ListView},
+{@link android.widget.GridView}, {@link android.widget.StackView}, or
+{@link android.widget.AdapterViewFlipper}. Here is the
+<code>widget_layout.xml</code> for
+the <a href="{@docRoot}resources/samples/StackWidget/index.html">StackView
+Widget sample</a>:</p>
+
+<pre><?xml version="1.0" encoding="utf-8"?>
+
+<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
+ <StackView xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/stack_view"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:gravity="center"
+ android:loopViews="true" />
+ <TextView xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/empty_view"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:gravity="center"
+ android:background="@drawable/widget_item_background"
+ android:textColor="#ffffff"
+ android:textStyle="bold"
+ android:text="@string/empty_view_text"
+ android:textSize="20sp" />
+</FrameLayout></pre>
+
+<p> Note that empty views must be siblings of the collection view for which the
+empty view represents empty state. </p>
+
+<p>In addition to the layout file for your entire app widget, you must create
+another layout file that defines the layout for each item in the collection (for
+example, a layout for each book in a collection of books). For example, the <a
+href="{@docRoot}resources/samples/StackWidget/index.html">StackView Widget
+sample</a> only has one layout file, <code>widget_item.xml</code>, since all
+items use the same layout. But the <a
+href="{@docRoot}resources/samples/WeatherListWidget/index.html">
+WeatherListWidget sample</a> has two layout files:
+<code>dark_widget_item.xml</code> and <code>light_widget_item.xml</code>.</p>
+
+
+
+<h4 id="AppWidgetProvider-collections">AppWidgetProvider class for app widgets with collections</h4>
+
+<p>As with a regular app widget, the bulk of your code in your {@link
+android.appwidget.AppWidgetProvider} subclass typically goes in {@link
+android.appwidget.AppWidgetProvider#onUpdate(android.content.Context,
+android.appwidget.AppWidgetManager, int[]) onUpdate()}. The major difference in
+your implementation for {@link
+android.appwidget.AppWidgetProvider#onUpdate(android.content.Context,
+android.appwidget.AppWidgetManager, int[]) onUpdate()} when creating an app
+widget with collections is that you must call {@link
+android.widget.RemoteViews#setRemoteAdapter setRemoteAdapter()}. This tells the
+collection view where to get its data. The {@link
+android.widget.RemoteViewsService} can then return your implementation of {@link
+android.widget.RemoteViewsService.RemoteViewsFactory RemoteViewsFactory}, and
+the widget can serve up the appropriate data. When you call this method, you
+must pass an intent that points to your implementation of {@link
+android.widget.RemoteViewsService} and the App Widget ID that specifies the app
+widget to update.</p>
+
+
+<p>For example, here's how the StackView Widget sample implements the {@link
+android.appwidget.AppWidgetProvider#onUpdate(android.content.Context,
+android.appwidget.AppWidgetManager, int[]) onUpdate()} callback method to set
+the {@link
+android.widget.RemoteViewsService} as the remote adapter for the app widget
+collection:</p>
+
+<pre>public void onUpdate(Context context, AppWidgetManager appWidgetManager,
+int[] appWidgetIds) {
+ // update each of the app widgets with the remote adapter
+ for (int i = 0; i < appWidgetIds.length; ++i) {
+
+ // Set up the intent that starts the StackViewService, which will
+ // provide the views for this collection.
+ Intent intent = new Intent(context, StackWidgetService.class);
+ // Add the app widget ID to the intent extras.
+ intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetIds[i]);
+ intent.setData(Uri.parse(intent.toUri(Intent.URI_INTENT_SCHEME)));
+ // Instantiate the RemoteViews object for the App Widget layout.
+ RemoteViews rv = new RemoteViews(context.getPackageName(), R.layout.widget_layout);
+ // Set up the RemoteViews object to use a RemoteViews adapter.
+ // This adapter connects
+ // to a RemoteViewsService through the specified intent.
+ // This is how you populate the data.
+ rv.setRemoteAdapter(appWidgetIds[i], R.id.stack_view, intent);
+
+ // The empty view is displayed when the collection has no items.
+ // It should be in the same layout used to instantiate the RemoteViews
+ // object above.
+ rv.setEmptyView(R.id.stack_view, R.id.empty_view);
+
+ //
+ // Do additional processing specific to this app widget...
+ //
+
+ appWidgetManager.updateAppWidget(appWidgetIds[i], rv);
+ }
+ super.onUpdate(context, appWidgetManager, appWidgetIds);
+}</pre>
+
+<h4>RemoteViewsService class</h4>
+
+<div class="sidebox-wrapper">
+<div class="sidebox">
+<h3>Persisting data</h3>
+ <p>You can’t rely on a single instance of your service, or any data it
+contains, to persist. You should therefore not store any data in your {@link
+android.widget.RemoteViewsService} (unless it is static). If you want your
+app widget’s data to persist, the best approach is to use a {@link
+android.content.ContentProvider} whose data persists beyond the process
+lifecycle.</p> </div>
+</div>
+
+<p>As described above, your {@link android.widget.RemoteViewsService} subclass
+provides the {@link android.widget.RemoteViewsService.RemoteViewsFactory
+RemoteViewsFactory} used to populate the remote collection view.</p>
+
+<p>Specifically, you need to
+perform these steps:</p>
+
+<ol>
+ <li>Subclass {@link android.widget.RemoteViewsService}. {@link
+android.widget.RemoteViewsService} is the service through which
+a remote adapter can request {@link android.widget.RemoteViews}. </li>
+
+ <li>In your {@link android.widget.RemoteViewsService} subclass, include a
+class that implements the {@link
+android.widget.RemoteViewsService.RemoteViewsFactory RemoteViewsFactory}
+interface. {@link android.widget.RemoteViewsService.RemoteViewsFactory
+RemoteViewsFactory} is an interface for an adapter between a remote collection
+view (such as {@link android.widget.ListView}, {@link android.widget.GridView},
+and so on) and the underlying data for that view. Your implementation is
+responsible for making a {@link android.widget.RemoteViews} object for each
+item in the data set. This interface is a thin wrapper around {@link
+android.widget.Adapter}.</li>
+</ol>
+
+<p>The primary contents of the {@link android.widget.RemoteViewsService}
+implementation is its {@link
+android.widget.RemoteViewsService.RemoteViewsFactory RemoteViewsFactory},
+described below.</p>
+
+<h4>RemoteViewsFactory interface</h4>
+
+<p>Your custom class that implements the {@link
+android.widget.RemoteViewsService.RemoteViewsFactory RemoteViewsFactory}
+interface provides the app widget with the data for the items in its collection.
+To
+do this, it combines your app widget item XML layout file with a source of data.
+This source of data could be anything from a database to a simple array. In the
+<a href="{@docRoot}resources/samples/StackWidget/index.html">StackView Widget
+sample</a>, the data source is an array of <code>WidgetItems</code>. The {@link
+android.widget.RemoteViewsService.RemoteViewsFactory RemoteViewsFactory}
+functions as an adapter to glue the data to the remote collection view.</p>
+
+<p>The two most important methods you need to implement for your
+
+{@link android.widget.RemoteViewsService.RemoteViewsFactory RemoteViewsFactory}
+subclass are
+{@link android.widget.RemoteViewsService.RemoteViewsFactory#onCreate()
+onCreate()} and
+{@link android.widget.RemoteViewsService.RemoteViewsFactory#getViewAt(int)
+getViewAt()}
+.</p>
+
+<p>The system calls {@link
+android.widget.RemoteViewsService.RemoteViewsFactory#onCreate() onCreate()} when
+creating your factory for the first time. This is where you set up any
+connections and/or cursors to your data source. For example, the <a
+href="{@docRoot}resources/samples/StackWidget/index.html">StackView Widget
+sample</a> uses {@link
+android.widget.RemoteViewsService.RemoteViewsFactory#onCreate() onCreate()} to
+initialize an array of <code>WidgetItem</code> objects. When your app widget is
+active, the system accesses these objects using their index position in the
+array and the text they contain is displayed </p>
+
+<p>Here is an excerpt from the the <a
+href="{@docRoot}resources/samples/StackWidget/index.html">StackView Widget</a>
+sample's
+{@link android.widget.RemoteViewsService.RemoteViewsFactory
+RemoteViewsFactory} implementation that shows portions of the {@link
+android.widget.RemoteViewsService.RemoteViewsFactory#onCreate() onCreate()}
+method:</p>
+
+<pre>class StackRemoteViewsFactory implements
+RemoteViewsService.RemoteViewsFactory {
+ private static final int mCount = 10;
+ private List<WidgetItem> mWidgetItems = new ArrayList<WidgetItem>();
+ private Context mContext;
+ private int mAppWidgetId;
+
+ public StackRemoteViewsFactory(Context context, Intent intent) {
+ mContext = context;
+ mAppWidgetId = intent.getIntExtra(AppWidgetManager.EXTRA_APPWIDGET_ID,
+ AppWidgetManager.INVALID_APPWIDGET_ID);
+ }
+
+ public void onCreate() {
+ // In onCreate() you setup any connections / cursors to your data source. Heavy lifting,
+ // for example downloading or creating content etc, should be deferred to onDataSetChanged()
+ // or getViewAt(). Taking more than 20 seconds in this call will result in an ANR.
+ for (int i = 0; i < mCount; i++) {
+ mWidgetItems.add(new WidgetItem(i + "!"));
+ }
+ ...
+ }
+...</pre>
+
+<p>The {@link android.widget.RemoteViewsService.RemoteViewsFactory
+RemoteViewsFactory} method {@link
+android.widget.RemoteViewsService.RemoteViewsFactory#getViewAt(int) getViewAt()}
+returns a {@link android.widget.RemoteViews} object corresponding to the data at
+the specified <code>position</code> in the data set. Here is an excerpt from
+the <a
+href="http://developer.android.com/resources/samples/StackWidget/index.html">
+StackView Widget</a> sample's {@link
+android.widget.RemoteViewsService.RemoteViewsFactory RemoteViewsFactory}
+implementation:</p>
+
+<pre>public RemoteViews getViewAt(int position) {
+
+ // Construct a remote views item based on the app widget item XML file,
+ // and set the text based on the position.
+ RemoteViews rv = new RemoteViews(mContext.getPackageName(), R.layout.widget_item);
+ rv.setTextViewText(R.id.widget_item, mWidgetItems.get(position).text);
+
+ ...
+ // Return the remote views object.
+ return rv;
+}</pre>
+
+<h4 id="behavior">Adding behavior to individual items</h4>
+
+<p>The above sections show you how to bind your data to your app widget
+collection. But what if you want to add dynamic behavior to the individual items
+in your collection view?</p>
+
+<p> As described in <a href="#AppWidgetProvider">Using the AppWidgetProvider
+Class</a>, you normally use {@link
+android.widget.RemoteViews#setOnClickPendingIntent(int,
+android.app.PendingIntent) setOnClickPendingIntent()} to set an object's click
+behavior—such as to cause a button to launch an {@link
+android.app.Activity}. But this approach is not allowed for child views in an
+individual collection item (to clarify, you could use {@link
+android.widget.RemoteViews#setOnClickPendingIntent(int,
+android.app.PendingIntent) setOnClickPendingIntent()} to set up a global button
+in the Gmail app widget that launches the app, for example, but not on the
+individual list items). Instead, to add click behavior to individual items in a
+collection, you use {@link
+android.widget.RemoteViews#setOnClickFillInIntent(int, android.content.Intent)
+setOnClickFillInIntent()}. This entails setting up up a pending intent template
+for your collection view, and then setting a fill-in intent on each item in the
+collection via your {@link android.widget.RemoteViewsService.RemoteViewsFactory
+RemoteViewsFactory}.</p>
+<p>This section uses the <a
+href="{@docRoot}resources/samples/StackWidget/index.html">StackView Widget
+sample</a> to describe how to add behavior to individual items. In the <a
+href="{@docRoot}resources/samples/StackWidget/index.html">StackView Widget
+sample</a>, if the user touches the top view, the app widget displays the {@link
+android.widget.Toast} message "Touched view <em>n</em>," where
+<em>n</em> is the index (position) of the touched view. This is how it
+works:</p>
+
+<ul>
+ <li>The <code>StackWidgetProvider</code> (an {@link
+android.appwidget.AppWidgetProvider} subclass) creates a pending intent that has
+a custom action called <code>TOAST_ACTION</code>.</li>
+ <li>When the user touches a view, the intent is fired and it broadcasts
+<code>TOAST_ACTION</code>.</li>
+
+ <li>This broadcast is intercepted by the <code>StackWidgetProvider</code>'s
+{@link android.appwidget.AppWidgetProvider#onReceive(android.content.Context,
+android.content.Intent) onReceive()} method, and the app widget displays the
+{@link
+android.widget.Toast} message for the touched view. The data for the collection
+items is provided by the {@link
+android.widget.RemoteViewsService.RemoteViewsFactory RemoteViewsFactory}, via
+the {@link android.widget.RemoteViewsService}.</li>
+</ul>
+
+<p class="note"><strong>Note:</strong> The <a
+href="{@docRoot}resources/samples/StackWidget/index.html">StackView Widget
+sample</a> uses a broadcast, but typically an app widget would simply launch an
+activity in a scenario like this one.</p>
+
+<h5>Setting up the pending intent template</h5>
+
+<p>The <code>StackWidgetProvider</code> ({@link
+android.appwidget.AppWidgetProvider} subclass) sets up a pending intent.
+Individuals items of a collection cannot set up their own pending intents.
+Instead, the collection as a whole sets up a pending intent template, and the
+individual items set a fill-in intent to create unique behavior on an
+item-by-item
+basis.</p>
+
+<p>This class also receives the broadcast that is sent when the user touches a
+view. It processes this event in its {@link
+android.appwidget.AppWidgetProvider#onReceive(android.content.Context,
+android.content.Intent) onReceive()} method. If the intent's action is
+<code>TOAST_ACTION</code>, the app widget displays a {@link
+android.widget.Toast}
+message for the current view.</p>
+
+<pre>public class StackWidgetProvider extends AppWidgetProvider {
+ public static final String TOAST_ACTION = "com.example.android.stackwidget.TOAST_ACTION";
+ public static final String EXTRA_ITEM = "com.example.android.stackwidget.EXTRA_ITEM";
+
+ ...
+
+ // Called when the BroadcastReceiver receives an Intent broadcast.
+ // Checks to see whether the intent's action is TOAST_ACTION. If it is, the app widget
+ // displays a Toast message for the current item.
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ AppWidgetManager mgr = AppWidgetManager.getInstance(context);
+ if (intent.getAction().equals(TOAST_ACTION)) {
+ int appWidgetId = intent.getIntExtra(AppWidgetManager.EXTRA_APPWIDGET_ID,
+ AppWidgetManager.INVALID_APPWIDGET_ID);
+ int viewIndex = intent.getIntExtra(EXTRA_ITEM, 0);
+ Toast.makeText(context, "Touched view " + viewIndex, Toast.LENGTH_SHORT).show();
+ }
+ super.onReceive(context, intent);
+ }
+
+ @Override
+ public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) {
+ // update each of the app widgets with the remote adapter
+ for (int i = 0; i < appWidgetIds.length; ++i) {
+
+ // Sets up the intent that points to the StackViewService that will
+ // provide the views for this collection.
+ Intent intent = new Intent(context, StackWidgetService.class);
+ intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetIds[i]);
+ // When intents are compared, the extras are ignored, so we need to embed the extras
+ // into the data so that the extras will not be ignored.
+ intent.setData(Uri.parse(intent.toUri(Intent.URI_INTENT_SCHEME)));
+ RemoteViews rv = new RemoteViews(context.getPackageName(), R.layout.widget_layout);
+ rv.setRemoteAdapter(appWidgetIds[i], R.id.stack_view, intent);
+
+ // The empty view is displayed when the collection has no items. It should be a sibling
+ // of the collection view.
+ rv.setEmptyView(R.id.stack_view, R.id.empty_view);
+
+ // This section makes it possible for items to have individualized behavior.
+ // It does this by setting up a pending intent template. Individuals items of a collection
+ // cannot set up their own pending intents. Instead, the collection as a whole sets
+ // up a pending intent template, and the individual items set a fillInIntent
+ // to create unique behavior on an item-by-item basis.
+ Intent toastIntent = new Intent(context, StackWidgetProvider.class);
+ // Set the action for the intent.
+ // When the user touches a particular view, it will have the effect of
+ // broadcasting TOAST_ACTION.
+ toastIntent.setAction(StackWidgetProvider.TOAST_ACTION);
+ toastIntent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetIds[i]);
+ intent.setData(Uri.parse(intent.toUri(Intent.URI_INTENT_SCHEME)));
+ PendingIntent toastPendingIntent = PendingIntent.getBroadcast(context, 0, toastIntent,
+ PendingIntent.FLAG_UPDATE_CURRENT);
+ rv.setPendingIntentTemplate(R.id.stack_view, toastPendingIntent);
+
+ appWidgetManager.updateAppWidget(appWidgetIds[i], rv);
+ }
+ super.onUpdate(context, appWidgetManager, appWidgetIds);
+ }
+}</pre>
+
+<h5><strong>Setting the fill-in Intent</strong></h5>
+
+<p>Your {@link android.widget.RemoteViewsService.RemoteViewsFactory
+RemoteViewsFactory} must set a fill-in intent on each item in the collection.
+This makes it possible to distinguish the individual on-click action of a given
+item. The fill-in intent is then combined with the {@link
+android.app.PendingIntent} template in order to determine the final intent that
+will be executed when the item is clicked. </p>
+
+<pre>
+public class StackWidgetService extends RemoteViewsService {
+ @Override
+ public RemoteViewsFactory onGetViewFactory(Intent intent) {
+ return new StackRemoteViewsFactory(this.getApplicationContext(), intent);
+ }
+}
+
+class StackRemoteViewsFactory implements RemoteViewsService.RemoteViewsFactory {
+ private static final int mCount = 10;
+ private List<WidgetItem> mWidgetItems = new ArrayList<WidgetItem>();
+ private Context mContext;
+ private int mAppWidgetId;
+
+ public StackRemoteViewsFactory(Context context, Intent intent) {
+ mContext = context;
+ mAppWidgetId = intent.getIntExtra(AppWidgetManager.EXTRA_APPWIDGET_ID,
+ AppWidgetManager.INVALID_APPWIDGET_ID);
+ }
+
+ // Initialize the data set.
+ public void onCreate() {
+ // In onCreate() you set up any connections / cursors to your data source. Heavy lifting,
+ // for example downloading or creating content etc, should be deferred to onDataSetChanged()
+ // or getViewAt(). Taking more than 20 seconds in this call will result in an ANR.
+ for (int i = 0; i < mCount; i++) {
+ mWidgetItems.add(new WidgetItem(i + "!"));
+ }
+ ...
+ }
+ ...
+
+ // Given the position (index) of a WidgetItem in the array, use the item's text value in
+ // combination with the app widget item XML file to construct a RemoteViews object.
+ public RemoteViews getViewAt(int position) {
+ // position will always range from 0 to getCount() - 1.
+
+ // Construct a RemoteViews item based on the app widget item XML file, and set the
+ // text based on the position.
+ RemoteViews rv = new RemoteViews(mContext.getPackageName(), R.layout.widget_item);
+ rv.setTextViewText(R.id.widget_item, mWidgetItems.get(position).text);
+
+ // Next, set a fill-intent, which will be used to fill in the pending intent template
+ // that is set on the collection view in StackWidgetProvider.
+ Bundle extras = new Bundle();
+ extras.putInt(StackWidgetProvider.EXTRA_ITEM, position);
+ Intent fillInIntent = new Intent();
+ fillInIntent.putExtras(extras);
+ // Make it possible to distinguish the individual on-click
+ // action of a given item
+ rv.setOnClickFillInIntent(R.id.widget_item, fillInIntent);
+
+ ...
+
+ // Return the RemoteViews object.
+ return rv;
+ }
+ ...
+ }</pre>
+
+<h3 id="fresh">Keeping Collection Data Fresh</h3>
+
+<p>The following figure illustrates the flow that occurs in an App Widget that
+uses
+collections when updates occur. It shows how the App Widget code interacts with
+the {@link android.widget.RemoteViewsService.RemoteViewsFactory
+RemoteViewsFactory}, and how you can trigger updates:</p>
+
+<img src="{@docRoot}images/appwidget_collections.png" alt="" />
+
+<p>One feature of App Widgets that use collections is the ability to provide
+users with up-to-date content. For example, consider the Android 3.0 Gmail
+app widget, which provides users with a snapshot of their inbox. To make this
+possible, you need to be able to trigger your {@link
+android.widget.RemoteViewsService.RemoteViewsFactory RemoteViewsFactory} and
+collection view to fetch and display new data. You achieve this with the {@link
+android.appwidget.AppWidgetManager} call {@link
+android.appwidget.AppWidgetManager#notifyAppWidgetViewDataChanged(int, int)
+notifyAppWidgetViewDataChanged()}. This call results in a callback to your
+<code>RemoteViewsFactory</code>’s {@link
+android.widget.RemoteViewsService.RemoteViewsFactory#onDataSetChanged()
+onDataSetChanged()} method, which gives you the opportunity to fetch any new
+data. Note that you can perform
+processing-intensive operations synchronously within the {@link
+android.widget.RemoteViewsService.RemoteViewsFactory#onDataSetChanged()
+onDataSetChanged()} callback. You are guaranteed that this call will be
+completed before the metadata or view data is fetched from the {@link
+android.widget.RemoteViewsService.RemoteViewsFactory RemoteViewsFactory}. In
+addition, you can perform processing-intensive operations within the {@link
+android.widget.RemoteViewsService.RemoteViewsFactory#getViewAt(int) getViewAt()}
+method. If this call takes a long time, the loading view (specified by the
+<code>RemoteViewsFactory</code>’s {@link
+android.widget.RemoteViewsService.RemoteViewsFactory#getLoadingView()} method)
+will be displayed in the corresponding position of the collection view until it
+returns.</p>
diff --git a/docs/html/guide/topics/graphics/opengl.jd b/docs/html/guide/topics/graphics/opengl.jd
index 1f51c2d..9f88954 100644
--- a/docs/html/guide/topics/graphics/opengl.jd
+++ b/docs/html/guide/topics/graphics/opengl.jd
@@ -5,13 +5,15 @@
<p>Android includes support for high performance 3D graphics
-via the OpenGL API — specifically, the OpenGL ES API.</p>
+via the OpenGL API—specifically, the OpenGL ES API.</p>
-<p>OpenGL ES is a flavor of the OpenGL specification intended for embedded
-devices. Versions of <a href="http://www.khronos.org/opengles/">OpenGL ES</a> are loosely peered to versions of the primary
-OpenGL standard. Android currently supports OpenGL ES 1.0, which corresponds
-to OpenGL 1.3. So, if the application you have in mind is possible with OpenGL
-1.3 on a desktop system, it should be possible on Android.</p>
+<p>OpenGL ES is a flavor of the OpenGL specification intended for embedded devices. Versions of <a
+href="http://www.khronos.org/opengles/">OpenGL ES</a> are loosely peered to versions of the primary
+OpenGL standard. Beginning with Android 2.2, the platform supports OpenGL ES 2.0 (with
+backward compatibility support for OpenGL ES 1.1). For information about the relative number of
+Android-powered devices that support a given version of OpenGL ES, see the <a
+href="http://developer.android.com/resources/dashboard/opengl.html">OpenGL ES Versions</a>
+dashboard.</p>
<p>The specific API provided by Android is similar to the J2ME JSR239 OpenGL
ES API. However, it may not be identical, so watch out for deviations.</p>
@@ -21,17 +23,18 @@
<p>Here's how to use the API at an extremely high level:</p>
<ol>
-<li>Write a custom View subclass.</li>
+<li>Write a custom {@link android.view.View} subclass.</li>
<li>Obtain a handle to an OpenGLContext, which provides access to the OpenGL functionality.</li>
-<li>In your View's onDraw() method, get a handle to a GL object, and use its methods to perform GL operations.</li>
+<li>In your View's {@link android.view.View#onDraw onDraw()} method, get a handle to a GL object,
+and use its methods to perform GL operations.</li>
</ol>
-<p>For an example of this usage model (based on the classic GL ColorCube), showing how to use
-it with threads can be found in
-<a href="{@docRoot}resources/samples/ApiDemos/src/com/example/android/apis/graphics/GLSurfaceViewActivity.html">com.android.samples.graphics.GLSurfaceViewActivity.java</a>.
+<p>Several samples using OpenGL ES are available in the <a
+href="{@docRoot}resources/samples/ApiDemos/src/com/example/android/apis/graphics/index.html">API
+Demos</a> sample application.
</p>
-<p>Writing a summary of how to actually write 3D applications using OpenGL is
+<p>A summary of how to actually write 3D applications using OpenGL is
beyond the scope of this text and is left as an exercise for the reader.</p>
<h2>Links to Additional Information</h2>
@@ -45,9 +48,6 @@
at <a title="http://www.khronos.org/opengles/1_X/"
href="http://www.khronos.org/opengles/1_X/">http://www.khronos.org/opengles/1_X/</a>.</p>
-<p>The documentation for the Android {@link javax.microedition.khronos.opengles
-OpenGL ES implementations} are also available.</p>
+<p>The documentation for the Android OpenGL ES implementations are available in {@link
+android.opengl} and {@link javax.microedition.khronos.opengles}.</p>
-<p>Finally, note that though Android does include some basic support for
-OpenGL ES 1.1, the support is <strong>not complete</strong>, and should not be relied
-upon at this time.</p>
diff --git a/docs/html/guide/topics/manifest/manifest-element.jd b/docs/html/guide/topics/manifest/manifest-element.jd
index a8125b3..598e88f 100644
--- a/docs/html/guide/topics/manifest/manifest-element.jd
+++ b/docs/html/guide/topics/manifest/manifest-element.jd
@@ -141,9 +141,14 @@
</tr>
</table>
+<p class="caution"><strong>Caution:</strong> If your application uses the Android Market's Copy
+ Protection feature, it cannot be installed to a device's SD card. However, if you use Android
+ Market's <a href="{@docRoot}guide/publishing/licensing.html">Application Licensing</a> instead,
+ your application <em>can</em> be installed to internal or external storage, including SD cards.</p>
+
<p class="note"><strong>Note:</strong> By default, your application will be installed on the
-internal storage and cannot be installed on the external storage unless you define this attribute
-to be either "{@code auto}" or "{@code preferExternal}".</p>
+ internal storage and cannot be installed on the external storage unless you define this attribute
+ to be either "{@code auto}" or "{@code preferExternal}".</p>
<p>When an application is installed on the external storage:</p>
<ul>
diff --git a/docs/html/images/appwidget.png b/docs/html/images/appwidget.png
index b72b80b..ab6e3de 100644
--- a/docs/html/images/appwidget.png
+++ b/docs/html/images/appwidget.png
Binary files differ
diff --git a/docs/html/images/appwidget_collections.png b/docs/html/images/appwidget_collections.png
new file mode 100644
index 0000000..4bce4a7
--- /dev/null
+++ b/docs/html/images/appwidget_collections.png
Binary files differ
diff --git a/graphics/java/android/renderscript/RenderScript.java b/graphics/java/android/renderscript/RenderScript.java
index 41a29e6..d51c202 100644
--- a/graphics/java/android/renderscript/RenderScript.java
+++ b/graphics/java/android/renderscript/RenderScript.java
@@ -68,9 +68,9 @@
native int nDeviceCreate();
native void nDeviceDestroy(int dev);
native void nDeviceSetConfig(int dev, int param, int value);
- native void nContextGetUserMessage(int con, int[] data);
+ native int nContextGetUserMessage(int con, int[] data);
native String nContextGetErrorMessage(int con);
- native int nContextPeekMessage(int con, int[] subID, boolean wait);
+ native int nContextPeekMessage(int con, int[] subID);
native void nContextInitToClient(int con);
native void nContextDeinitToClient(int con);
@@ -736,7 +736,7 @@
mRS.nContextInitToClient(mRS.mContext);
while(mRun) {
rbuf[0] = 0;
- int msg = mRS.nContextPeekMessage(mRS.mContext, mAuxData, true);
+ int msg = mRS.nContextPeekMessage(mRS.mContext, mAuxData);
int size = mAuxData[1];
int subID = mAuxData[0];
@@ -744,7 +744,10 @@
if ((size>>2) >= rbuf.length) {
rbuf = new int[(size + 3) >> 2];
}
- mRS.nContextGetUserMessage(mRS.mContext, rbuf);
+ if (mRS.nContextGetUserMessage(mRS.mContext, rbuf) !=
+ RS_MESSAGE_TO_CLIENT_USER) {
+ throw new RSDriverException("Error processing message from Renderscript.");
+ }
if(mRS.mMessageCallback != null) {
mRS.mMessageCallback.mData = rbuf;
diff --git a/graphics/jni/android_renderscript_RenderScript.cpp b/graphics/jni/android_renderscript_RenderScript.cpp
index 26a6287..60b39b0 100644
--- a/graphics/jni/android_renderscript_RenderScript.cpp
+++ b/graphics/jni/android_renderscript_RenderScript.cpp
@@ -190,14 +190,14 @@
{
LOG_API("nContextSetSurface, con(%p), width(%i), height(%i), surface(%p)", con, width, height, (Surface *)wnd);
- Surface * window = NULL;
+ ANativeWindow * window = NULL;
if (wnd == NULL) {
} else {
- window = (Surface*) android_Surface_getNativeWindow(_env, wnd).get();
+ window = android_Surface_getNativeWindow(_env, wnd).get();
}
- rsContextSetSurface(con, width, height, window, 1);
+ rsContextSetSurface(con, width, height, window);
}
static void
@@ -240,15 +240,14 @@
int id = rsContextGetMessage(con,
buf, sizeof(buf),
&receiveLen, sizeof(receiveLen),
- &subID, sizeof(subID),
- true);
+ &subID, sizeof(subID));
if (!id && receiveLen) {
LOGV("message receive buffer too small. %i", receiveLen);
}
return _env->NewStringUTF(buf);
}
-static void
+static jint
nContextGetUserMessage(JNIEnv *_env, jobject _this, RsContext con, jintArray data)
{
jint len = _env->GetArrayLength(data);
@@ -259,23 +258,23 @@
int id = rsContextGetMessage(con,
ptr, len * 4,
&receiveLen, sizeof(receiveLen),
- &subID, sizeof(subID),
- true);
+ &subID, sizeof(subID));
if (!id && receiveLen) {
LOGV("message receive buffer too small. %i", receiveLen);
}
_env->ReleaseIntArrayElements(data, ptr, 0);
+ return id;
}
static jint
-nContextPeekMessage(JNIEnv *_env, jobject _this, RsContext con, jintArray auxData, jboolean wait)
+nContextPeekMessage(JNIEnv *_env, jobject _this, RsContext con, jintArray auxData)
{
LOG_API("nContextPeekMessage, con(%p)", con);
jint *auxDataPtr = _env->GetIntArrayElements(auxData, NULL);
size_t receiveLen;
uint32_t subID;
int id = rsContextPeekMessage(con, &receiveLen, sizeof(receiveLen),
- &subID, sizeof(subID), wait);
+ &subID, sizeof(subID));
auxDataPtr[0] = (jint)subID;
auxDataPtr[1] = (jint)receiveLen;
_env->ReleaseIntArrayElements(auxData, auxDataPtr, 0);
@@ -1160,9 +1159,9 @@
{"nDeviceCreate", "()I", (void*)nDeviceCreate },
{"nDeviceDestroy", "(I)V", (void*)nDeviceDestroy },
{"nDeviceSetConfig", "(III)V", (void*)nDeviceSetConfig },
-{"nContextGetUserMessage", "(I[I)V", (void*)nContextGetUserMessage },
+{"nContextGetUserMessage", "(I[I)I", (void*)nContextGetUserMessage },
{"nContextGetErrorMessage", "(I)Ljava/lang/String;", (void*)nContextGetErrorMessage },
-{"nContextPeekMessage", "(I[IZ)I", (void*)nContextPeekMessage },
+{"nContextPeekMessage", "(I[I)I", (void*)nContextPeekMessage },
{"nContextInitToClient", "(I)V", (void*)nContextInitToClient },
{"nContextDeinitToClient", "(I)V", (void*)nContextDeinitToClient },
diff --git a/include/camera/CameraParameters.h b/include/camera/CameraParameters.h
index 513239f..dc5fc84 100644
--- a/include/camera/CameraParameters.h
+++ b/include/camera/CameraParameters.h
@@ -309,25 +309,54 @@
// 0.3333, EV is -2.
// Example value: "0.333333333" or "0.5". Read only.
static const char KEY_EXPOSURE_COMPENSATION_STEP[];
- // The state of the auto-exposure lock. "true" means that auto-exposure is
- // locked to its current value and will not change. "false" means the
- // auto-exposure routine is free to change exposure settings. Changing
- // exposure compensation settings will still affect the exposure settings
- // while auto-exposure is locked. Stopping preview or taking a still image
- // will release the lock. However, the lock can be re-enabled prior to
- // preview being re-started, to keep the exposure values from the previous
- // lock. In conjunction with exposure compensation, this allows for
- // capturing multi-exposure brackets with known relative exposure
- // values. Locking auto-exposure after open but before the first cal to
- // startPreview may result in severly over- or under-exposed images. The
- // driver may independently enable the AE lock after auto-focus
- // completes. If it does so, this key must have its value updated to reflect
- // the lock's existence. Applications are free to release such a lock, to
- // re-enable AE without restarting preview.
+ // The state of the auto-exposure lock. "true" means that
+ // auto-exposure is locked to its current value and will not
+ // change. "false" means the auto-exposure routine is free to
+ // change exposure values. If auto-exposure is already locked,
+ // setting this to true again has no effect (the driver will not
+ // recalculate exposure values). Changing exposure compensation
+ // settings will still affect the exposure settings while
+ // auto-exposure is locked. Stopping preview or taking a still
+ // image will release the lock. However, the lock can be
+ // re-enabled prior to preview being re-started, to keep the
+ // exposure values from the previous lock. In conjunction with
+ // exposure compensation, this allows for capturing multi-exposure
+ // brackets with known relative exposure values. Locking
+ // auto-exposure after open but before the first call to
+ // startPreview may result in severely over- or under-exposed
+ // images. The driver may independently enable the AE lock after
+ // auto-focus completes. If it does so, this key must have its
+ // value updated to reflect the lock's existence. Applications are
+ // free to release such a lock, to re-enable AE without restarting
+ // preview.
static const char KEY_AUTO_EXPOSURE_LOCK[];
// Whether locking the auto-exposure is supported. "true" means it is, and
// "false" or this key not existing means it is not supported.
static const char KEY_AUTO_EXPOSURE_LOCK_SUPPORTED[];
+ // The state of the auto-white balance lock. "true" means that
+ // auto-white balance is locked to its current value and will not
+ // change. "false" means the auto-white balance routine is free to
+ // change white balance values. If auto-white balance is already
+ // locked, setting this to true again has no effect (the driver
+ // will not recalculate white balance values). Stopping preview or
+ // taking a still image will release the lock. However, the lock
+ // can be re-enabled prior to preview being re-started, to keep
+ // the white balance values from the previous lock. In conjunction
+ // with exposure compensation, this allows for capturing
+ // multi-exposure brackets with fixed white balance. Locking
+ // auto-white balance after open but before the first call to
+ // startPreview may result in severely incorrect color. The
+ // driver may independently enable the AWB lock after auto-focus
+ // completes. If it does so, this key must have its value updated
+ // to reflect the lock's existence. Applications are free to
+ // release such a lock, to re-enable AWB without restarting
+ // preview.
+ static const char KEY_AUTO_WHITEBALANCE_LOCK[];
+ // Whether locking the auto-white balance is supported. "true"
+ // means it is, and "false" or this key not existing means it is
+ // not supported.
+ static const char KEY_AUTO_WHITEBALANCE_LOCK_SUPPORTED[];
+
// The maximum number of metering areas supported. This is the maximum
// length of KEY_METERING_AREAS.
// Example value: "0" or "2". Read only.
diff --git a/include/media/mediarecorder.h b/include/media/mediarecorder.h
index 59093c9..36bf34e 100644
--- a/include/media/mediarecorder.h
+++ b/include/media/mediarecorder.h
@@ -179,6 +179,9 @@
// The time used to compensate for initial A/V sync.
MEDIA_RECORDER_TRACK_INFO_START_OFFSET_MS = 1008,
+ // Total number of bytes of the media data.
+ MEDIA_RECORDER_TRACK_INFO_DATA_KBYTES = 1009,
+
MEDIA_RECORDER_TRACK_INFO_LIST_END = 2000,
};
diff --git a/include/media/stagefright/MPEG4Writer.h b/include/media/stagefright/MPEG4Writer.h
index 1764306..904ce2a 100644
--- a/include/media/stagefright/MPEG4Writer.h
+++ b/include/media/stagefright/MPEG4Writer.h
@@ -176,7 +176,7 @@
void writeCompositionMatrix(int32_t degrees);
void writeMvhdBox(int64_t durationUs);
void writeMoovBox(int64_t durationUs);
- void writeFtypBox(const MetaData *param);
+ void writeFtypBox(MetaData *param);
void writeUdtaBox();
void writeGeoDataBox();
void writeLatitude(int degreex10000);
diff --git a/include/media/stagefright/MetaData.h b/include/media/stagefright/MetaData.h
index a300f0e..4044c5d 100644
--- a/include/media/stagefright/MetaData.h
+++ b/include/media/stagefright/MetaData.h
@@ -154,16 +154,16 @@
int32_t left, int32_t top,
int32_t right, int32_t bottom);
- bool findCString(uint32_t key, const char **value) const;
- bool findInt32(uint32_t key, int32_t *value) const;
- bool findInt64(uint32_t key, int64_t *value) const;
- bool findFloat(uint32_t key, float *value) const;
- bool findPointer(uint32_t key, void **value) const;
+ bool findCString(uint32_t key, const char **value);
+ bool findInt32(uint32_t key, int32_t *value);
+ bool findInt64(uint32_t key, int64_t *value);
+ bool findFloat(uint32_t key, float *value);
+ bool findPointer(uint32_t key, void **value);
bool findRect(
uint32_t key,
int32_t *left, int32_t *top,
- int32_t *right, int32_t *bottom) const;
+ int32_t *right, int32_t *bottom);
bool setData(uint32_t key, uint32_t type, const void *data, size_t size);
diff --git a/keystore/java/android/security/IKeyChainService.aidl b/keystore/java/android/security/IKeyChainService.aidl
index 64f5a48..be59f23 100644
--- a/keystore/java/android/security/IKeyChainService.aidl
+++ b/keystore/java/android/security/IKeyChainService.aidl
@@ -24,8 +24,13 @@
* @hide
*/
interface IKeyChainService {
- byte[] getPrivate(String alias, String authToken);
+ // APIs used by KeyChain
+ byte[] getPrivateKey(String alias, String authToken);
byte[] getCertificate(String alias, String authToken);
- byte[] getCaCertificate(String alias, String authToken);
- String findIssuer(in Bundle cert);
+
+ // APIs used by CertInstaller
+ void installCaCertificate(in byte[] caCertificate);
+
+ // APIs used by Settings
+ boolean reset();
}
diff --git a/keystore/java/android/security/KeyChain.java b/keystore/java/android/security/KeyChain.java
index 69847bf..08e05ef 100644
--- a/keystore/java/android/security/KeyChain.java
+++ b/keystore/java/android/security/KeyChain.java
@@ -28,24 +28,20 @@
import android.os.IBinder;
import android.os.Looper;
import android.os.RemoteException;
-import android.util.Log;
-import dalvik.system.CloseGuard;
import java.io.ByteArrayInputStream;
+import java.io.Closeable;
import java.io.IOException;
import java.security.KeyFactory;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
-import java.security.cert.CertPathValidatorException;
import java.security.cert.Certificate;
-import java.security.cert.CertificateEncodingException;
import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;
-import java.security.cert.TrustAnchor;
import java.security.cert.X509Certificate;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.PKCS8EncodedKeySpec;
-import org.apache.harmony.xnet.provider.jsse.IndexedPKIXParameters;
-import org.apache.harmony.xnet.provider.jsse.SSLParametersImpl;
+import java.util.concurrent.BlockingQueue;
+import java.util.concurrent.LinkedBlockingQueue;
/**
* @hide
@@ -60,30 +56,6 @@
public static final String ACCOUNT_TYPE = "com.android.keychain";
/**
- * @hide Also used by KeyChainService implementation
- */
- // TODO This non-localized CA string to be removed when CAs moved out of keystore
- public static final String CA_SUFFIX = " CA";
-
- public static final String KEY_INTENT = "intent";
-
- /**
- * Intentionally not public to leave open the future possibility
- * of hardware based keys. Callers should use {@link #toPrivateKey
- * toPrivateKey} in order to convert a bundle to a {@code
- * PrivateKey}
- */
- private static final String KEY_PKCS8 = "pkcs8";
-
- /**
- * Intentionally not public to leave open the future possibility
- * of hardware based certs. Callers should use {@link
- * #toCertificate toCertificate} in order to convert a bundle to a
- * {@code PrivateKey}
- */
- private static final String KEY_X509 = "x509";
-
- /**
* Returns an {@code Intent} for use with {@link
* android.app.Activity#startActivityForResult
* startActivityForResult}. The result will be returned via {@link
@@ -97,160 +69,59 @@
}
/**
- * Returns a new {@code KeyChain} instance. When the caller is
- * done using the {@code KeyChain}, it must be closed with {@link
- * #close()} or resource leaks will occur.
+ * Returns a new {@code KeyChainResult} instance.
*/
- public static KeyChain getInstance(Context context) throws InterruptedException {
- return new KeyChain(context);
- }
-
- private final AccountManager mAccountManager;
-
- private final Object mServiceLock = new Object();
- private IKeyChainService mService;
- private boolean mIsBound;
-
- private Account mAccount;
-
- private ServiceConnection mServiceConnection = new ServiceConnection() {
- @Override public void onServiceConnected(ComponentName name, IBinder service) {
- synchronized (mServiceLock) {
- mService = IKeyChainService.Stub.asInterface(service);
- mServiceLock.notifyAll();
-
- // Account is created if necessary during binding of the IKeyChainService
- mAccount = mAccountManager.getAccountsByType(ACCOUNT_TYPE)[0];
- }
- }
-
- @Override public void onServiceDisconnected(ComponentName name) {
- synchronized (mServiceLock) {
- mService = null;
- }
- }
- };
-
- private final Context mContext;
-
- private final CloseGuard mGuard = CloseGuard.get();
-
- private KeyChain(Context context) throws InterruptedException {
- if (context == null) {
- throw new NullPointerException("context == null");
- }
- mContext = context;
- ensureNotOnMainThread();
- mAccountManager = AccountManager.get(mContext);
- mIsBound = mContext.bindService(new Intent(IKeyChainService.class.getName()),
- mServiceConnection,
- Context.BIND_AUTO_CREATE);
- if (!mIsBound) {
- throw new AssertionError();
- }
- synchronized (mServiceLock) {
- // there is a race between binding on this thread and the
- // callback on the main thread. wait until binding is done
- // to be sure we have the mAccount initialized.
- if (mService == null) {
- mServiceLock.wait();
- }
- }
- mGuard.open("close");
- }
-
- /**
- * {@code Bundle} will contain {@link #KEY_INTENT} if user needs
- * to confirm application access to requested key. In the alias
- * does not exist or there is an error, null is
- * returned. Otherwise the {@code Bundle} contains information
- * representing the private key which can be interpreted with
- * {@link #toPrivateKey toPrivateKey}.
- *
- * non-null alias
- */
- public Bundle getPrivate(String alias) {
- return get(alias, Credentials.USER_PRIVATE_KEY);
- }
-
- public Bundle getCertificate(String alias) {
- return get(alias, Credentials.USER_CERTIFICATE);
- }
-
- public Bundle getCaCertificate(String alias) {
- return get(alias, Credentials.CA_CERTIFICATE);
- }
-
- private Bundle get(String alias, String type) {
+ public static KeyChainResult get(Context context, String alias)
+ throws InterruptedException, RemoteException {
if (alias == null) {
throw new NullPointerException("alias == null");
}
- ensureNotOnMainThread();
-
- String authAlias = (type.equals(Credentials.CA_CERTIFICATE)) ? (alias + CA_SUFFIX) : alias;
- AccountManagerFuture<Bundle> future = mAccountManager.getAuthToken(mAccount,
- authAlias,
- false,
- null,
- null);
- Bundle bundle;
+ KeyChainConnection keyChainConnection = bind(context);
try {
- bundle = future.getResult();
- } catch (OperationCanceledException e) {
- throw new AssertionError(e);
- } catch (IOException e) {
- throw new AssertionError(e);
- } catch (AuthenticatorException e) {
- throw new AssertionError(e);
- }
- Intent intent = bundle.getParcelable(AccountManager.KEY_INTENT);
- if (intent != null) {
- Bundle result = new Bundle();
- // we don't want this Eclair compatability flag,
- // it will prevent onActivityResult from being called
- intent.setFlags(intent.getFlags() & ~Intent.FLAG_ACTIVITY_NEW_TASK);
- result.putParcelable(KEY_INTENT, intent);
- return result;
- }
- String authToken = bundle.getString(AccountManager.KEY_AUTHTOKEN);
- if (authToken == null) {
- throw new AssertionError("Invalid authtoken");
- }
-
- byte[] bytes;
- try {
- if (type.equals(Credentials.USER_PRIVATE_KEY)) {
- bytes = mService.getPrivate(alias, authToken);
- } else if (type.equals(Credentials.USER_CERTIFICATE)) {
- bytes = mService.getCertificate(alias, authToken);
- } else if (type.equals(Credentials.CA_CERTIFICATE)) {
- bytes = mService.getCaCertificate(alias, authToken);
- } else {
- throw new AssertionError();
+ // Account is created if necessary during binding of the IKeyChainService
+ AccountManager accountManager = AccountManager.get(context);
+ Account account = accountManager.getAccountsByType(ACCOUNT_TYPE)[0];
+ AccountManagerFuture<Bundle> future = accountManager.getAuthToken(account,
+ alias,
+ false,
+ null,
+ null);
+ Bundle bundle;
+ try {
+ bundle = future.getResult();
+ } catch (OperationCanceledException e) {
+ throw new AssertionError(e);
+ } catch (IOException e) {
+ throw new AssertionError(e);
+ } catch (AuthenticatorException e) {
+ throw new AssertionError(e);
}
- } catch (RemoteException e) {
- throw new AssertionError(e);
+ Intent intent = bundle.getParcelable(AccountManager.KEY_INTENT);
+ if (intent != null) {
+ Bundle result = new Bundle();
+ // we don't want this Eclair compatability flag,
+ // it will prevent onActivityResult from being called
+ intent.setFlags(intent.getFlags() & ~Intent.FLAG_ACTIVITY_NEW_TASK);
+ return new KeyChainResult(intent);
+ }
+
+ String authToken = bundle.getString(AccountManager.KEY_AUTHTOKEN);
+ if (authToken == null) {
+ throw new AssertionError("Invalid authtoken");
+ }
+ IKeyChainService keyChainService = keyChainConnection.getService();
+ byte[] privateKeyBytes = keyChainService.getPrivateKey(alias, authToken);
+ byte[] certificateBytes = keyChainService.getCertificate(alias, authToken);
+ return new KeyChainResult(toPrivateKey(privateKeyBytes),
+ toCertificate(certificateBytes));
+ } finally {
+ keyChainConnection.close();
}
- if (bytes == null) {
- throw new AssertionError();
- }
- Bundle result = new Bundle();
- if (type.equals(Credentials.USER_PRIVATE_KEY)) {
- result.putByteArray(KEY_PKCS8, bytes);
- } else if (type.equals(Credentials.USER_CERTIFICATE)) {
- result.putByteArray(KEY_X509, bytes);
- } else if (type.equals(Credentials.CA_CERTIFICATE)) {
- result.putByteArray(KEY_X509, bytes);
- } else {
- throw new AssertionError();
- }
- return result;
}
- public static PrivateKey toPrivateKey(Bundle bundle) {
- byte[] bytes = bundle.getByteArray(KEY_PKCS8);
+ private static PrivateKey toPrivateKey(byte[] bytes) {
if (bytes == null) {
- throw new IllegalArgumentException("not a private key bundle");
+ throw new IllegalArgumentException("bytes == null");
}
try {
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
@@ -262,20 +133,9 @@
}
}
- public static Bundle fromPrivateKey(PrivateKey privateKey) {
- Bundle bundle = new Bundle();
- String format = privateKey.getFormat();
- if (!format.equals("PKCS#8")) {
- throw new IllegalArgumentException("Unsupported private key format " + format);
- }
- bundle.putByteArray(KEY_PKCS8, privateKey.getEncoded());
- return bundle;
- }
-
- public static X509Certificate toCertificate(Bundle bundle) {
- byte[] bytes = bundle.getByteArray(KEY_X509);
+ private static X509Certificate toCertificate(byte[] bytes) {
if (bytes == null) {
- throw new IllegalArgumentException("not a certificate bundle");
+ throw new IllegalArgumentException("bytes == null");
}
try {
CertificateFactory certFactory = CertificateFactory.getInstance("X.509");
@@ -286,87 +146,64 @@
}
}
- public static Bundle fromCertificate(Certificate cert) {
- Bundle bundle = new Bundle();
- String type = cert.getType();
- if (!type.equals("X.509")) {
- throw new IllegalArgumentException("Unsupported certificate type " + type);
+ /**
+ * @hide for reuse by CertInstaller and Settings.
+ * @see KeyChain#bind
+ */
+ public final static class KeyChainConnection implements Closeable {
+ private final Context context;
+ private final ServiceConnection serviceConnection;
+ private final IKeyChainService service;
+ private KeyChainConnection(Context context,
+ ServiceConnection serviceConnection,
+ IKeyChainService service) {
+ this.context = context;
+ this.serviceConnection = serviceConnection;
+ this.service = service;
}
- try {
- bundle.putByteArray(KEY_X509, cert.getEncoded());
- } catch (CertificateEncodingException e) {
- throw new AssertionError(e);
+ @Override public void close() {
+ context.unbindService(serviceConnection);
}
- return bundle;
+ public IKeyChainService getService() {
+ return service;
+ }
}
- private void ensureNotOnMainThread() {
+ /**
+ * @hide for reuse by CertInstaller and Settings.
+ *
+ * Caller should call unbindService on the result when finished.
+ */
+ public static KeyChainConnection bind(Context context) throws InterruptedException {
+ if (context == null) {
+ throw new NullPointerException("context == null");
+ }
+ ensureNotOnMainThread(context);
+ final BlockingQueue<IKeyChainService> q = new LinkedBlockingQueue<IKeyChainService>(1);
+ ServiceConnection keyChainServiceConnection = new ServiceConnection() {
+ @Override public void onServiceConnected(ComponentName name, IBinder service) {
+ try {
+ q.put(IKeyChainService.Stub.asInterface(service));
+ } catch (InterruptedException e) {
+ throw new AssertionError(e);
+ }
+ }
+ @Override public void onServiceDisconnected(ComponentName name) {}
+ };
+ boolean isBound = context.bindService(new Intent(IKeyChainService.class.getName()),
+ keyChainServiceConnection,
+ Context.BIND_AUTO_CREATE);
+ if (!isBound) {
+ throw new AssertionError("could not bind to KeyChainService");
+ }
+ return new KeyChainConnection(context, keyChainServiceConnection, q.take());
+ }
+
+ private static void ensureNotOnMainThread(Context context) {
Looper looper = Looper.myLooper();
- if (looper != null && looper == mContext.getMainLooper()) {
+ if (looper != null && looper == context.getMainLooper()) {
throw new IllegalStateException(
"calling this from your main thread can lead to deadlock");
}
}
-
- public Bundle findIssuer(X509Certificate cert) {
- if (cert == null) {
- throw new NullPointerException("cert == null");
- }
- ensureNotOnMainThread();
-
- // check and see if the issuer is already known to the default IndexedPKIXParameters
- IndexedPKIXParameters index = SSLParametersImpl.getDefaultIndexedPKIXParameters();
- try {
- TrustAnchor anchor = index.findTrustAnchor(cert);
- if (anchor != null && anchor.getTrustedCert() != null) {
- X509Certificate ca = anchor.getTrustedCert();
- return fromCertificate(ca);
- }
- } catch (CertPathValidatorException ignored) {
- }
-
- // otherwise, it might be a user installed CA in the keystore
- String alias;
- try {
- alias = mService.findIssuer(fromCertificate(cert));
- } catch (RemoteException e) {
- throw new AssertionError(e);
- }
- if (alias == null) {
- Log.w(TAG, "Lookup failed for issuer");
- return null;
- }
-
- Bundle bundle = get(alias, Credentials.CA_CERTIFICATE);
- Intent intent = bundle.getParcelable(KEY_INTENT);
- if (intent != null) {
- // permission still required
- return bundle;
- }
- // add the found CA to the index for next time
- X509Certificate ca = toCertificate(bundle);
- index.index(new TrustAnchor(ca, null));
- return bundle;
- }
-
- public void close() {
- if (mIsBound) {
- mContext.unbindService(mServiceConnection);
- mIsBound = false;
- mGuard.close();
- }
- }
-
- protected void finalize() throws Throwable {
- // note we don't close, we just warn.
- // shouldn't be doing I/O in a finalizer,
- // which the unbind would cause.
- try {
- if (mGuard != null) {
- mGuard.warnIfOpen();
- }
- } finally {
- super.finalize();
- }
- }
}
diff --git a/keystore/java/android/security/KeyChainResult.java b/keystore/java/android/security/KeyChainResult.java
new file mode 100644
index 0000000..85a2921
--- /dev/null
+++ b/keystore/java/android/security/KeyChainResult.java
@@ -0,0 +1,72 @@
+/*
+ * 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 android.security;
+
+import android.content.Intent;
+import java.security.PrivateKey;
+import java.security.cert.X509Certificate;
+
+/**
+ * The KeyChainResult is the complex result value from {@link
+ * KeyChain#get}. The caller should first inspect {@link #getIntent}
+ * to determine if the user needs to grant the application access to
+ * the protected contents. If {@code getIntent} returns null, access
+ * has been granted and the methods {@link #getPrivateKey} and {@link
+ * #getCertificate} can be used to access the credentials.
+ *
+ * @hide
+ */
+public final class KeyChainResult {
+
+ private final Intent intent;
+ private final PrivateKey privateKey;
+ private final X509Certificate certificate;
+
+ KeyChainResult(Intent intent) {
+ this(intent, null, null);
+ }
+
+ KeyChainResult(PrivateKey privateKey, X509Certificate certificate) {
+ this(null, privateKey, certificate);
+ }
+
+ private KeyChainResult(Intent intent, PrivateKey privateKey, X509Certificate certificate) {
+ this.intent = intent;
+ this.privateKey = privateKey;
+ this.certificate = certificate;
+ }
+
+ public Intent getIntent() {
+ return intent;
+ }
+
+ public PrivateKey getPrivateKey() {
+ checkIntent();
+ return privateKey;
+ }
+
+ public X509Certificate getCertificate() {
+ checkIntent();
+ return certificate;
+ }
+
+ private void checkIntent() {
+ if (intent != null) {
+ throw new IllegalStateException("non-null Intent, check getIntent()");
+ }
+ }
+
+}
diff --git a/libs/camera/CameraParameters.cpp b/libs/camera/CameraParameters.cpp
index 4f3da40..c295315 100644
--- a/libs/camera/CameraParameters.cpp
+++ b/libs/camera/CameraParameters.cpp
@@ -70,6 +70,8 @@
const char CameraParameters::KEY_EXPOSURE_COMPENSATION_STEP[] = "exposure-compensation-step";
const char CameraParameters::KEY_AUTO_EXPOSURE_LOCK[] = "auto-exposure-lock";
const char CameraParameters::KEY_AUTO_EXPOSURE_LOCK_SUPPORTED[] = "auto-exposure-lock-supported";
+const char CameraParameters::KEY_AUTO_WHITEBALANCE_LOCK[] = "auto-whitebalance-lock";
+const char CameraParameters::KEY_AUTO_WHITEBALANCE_LOCK_SUPPORTED[] = "auto-whitebalance-lock-supported";
const char CameraParameters::KEY_MAX_NUM_METERING_AREAS[] = "max-num-metering-areas";
const char CameraParameters::KEY_METERING_AREAS[] = "metering-areas";
const char CameraParameters::KEY_ZOOM[] = "zoom";
diff --git a/libs/gui/SurfaceTexture.cpp b/libs/gui/SurfaceTexture.cpp
index d7c449c..b08a5a8 100644
--- a/libs/gui/SurfaceTexture.cpp
+++ b/libs/gui/SurfaceTexture.cpp
@@ -292,7 +292,8 @@
LOGE("dequeueBuffer: MIN_UNDEQUEUED_BUFFERS=%d exceeded (dequeued=%d)",
MIN_UNDEQUEUED_BUFFERS-int(mSynchronousMode),
dequeuedCount);
- return -EBUSY;
+ // TODO: Enable this error report after we fix issue 4435022
+ // return -EBUSY;
}
// we're in synchronous mode and didn't find a buffer, we need to wait
diff --git a/libs/hwui/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp
index 3232f6f..560c1f9 100644
--- a/libs/hwui/OpenGLRenderer.cpp
+++ b/libs/hwui/OpenGLRenderer.cpp
@@ -2434,12 +2434,11 @@
}
SkXfermode::Mode OpenGLRenderer::getXfermode(SkXfermode* mode) {
- // In the future we should look at unifying the Porter-Duff modes and
- // SkXferModes so that we can use SkXfermode::IsMode(xfer, &mode).
- if (mode == NULL) {
- return SkXfermode::kSrcOver_Mode;
+ SkXfermode::Mode resultMode;
+ if (!SkXfermode::AsMode(mode, &resultMode)) {
+ resultMode = SkXfermode::kSrcOver_Mode;
}
- return mode->fMode;
+ return resultMode;
}
void OpenGLRenderer::setTextureWrapModes(Texture* texture, GLenum wrapS, GLenum wrapT) {
diff --git a/libs/rs/Android.mk b/libs/rs/Android.mk
index ef00b30..29c1447 100644
--- a/libs/rs/Android.mk
+++ b/libs/rs/Android.mk
@@ -117,6 +117,7 @@
rsType.cpp \
driver/rsdBcc.cpp \
driver/rsdCore.cpp \
+ driver/rsdFrameBuffer.cpp \
driver/rsdGL.cpp \
driver/rsdMesh.cpp \
driver/rsdMeshObj.cpp \
diff --git a/libs/rs/RenderScript.h b/libs/rs/RenderScript.h
index f4e3f57..3f2d67a 100644
--- a/libs/rs/RenderScript.h
+++ b/libs/rs/RenderScript.h
@@ -49,6 +49,12 @@
void rsaElementGetNativeData(RsContext, RsElement, uint32_t *elemData, uint32_t elemDataSize);
void rsaElementGetSubElements(RsContext, RsElement, uint32_t *ids, const char **names, uint32_t dataSize);
+RsDevice rsDeviceCreate();
+void rsDeviceDestroy(RsDevice dev);
+void rsDeviceSetConfig(RsDevice dev, RsDeviceParam p, int32_t value);
+RsContext rsContextCreate(RsDevice dev, uint32_t version);
+RsContext rsContextCreateGL(RsDevice dev, uint32_t version, RsSurfaceConfig sc, uint32_t dpi);
+
#ifdef ANDROID_RS_SERIALIZE
diff --git a/libs/rs/RenderScriptDefines.h b/libs/rs/RenderScriptDefines.h
index 308437d..ee9645c 100644
--- a/libs/rs/RenderScriptDefines.h
+++ b/libs/rs/RenderScriptDefines.h
@@ -50,6 +50,8 @@
typedef void * RsProgramStore;
typedef void * RsProgramRaster;
+typedef void * RsNativeWindow;
+
typedef void (* RsBitmapCallback_t)(void *);
typedef struct {
diff --git a/libs/rs/driver/rsdCore.cpp b/libs/rs/driver/rsdCore.cpp
index 0a5f2ec..7ef9c30 100644
--- a/libs/rs/driver/rsdCore.cpp
+++ b/libs/rs/driver/rsdCore.cpp
@@ -23,6 +23,7 @@
#include "rsdProgramFragment.h"
#include "rsdMesh.h"
#include "rsdSampler.h"
+#include "rsdFrameBuffer.h"
#include <malloc.h>
#include "rsContext.h"
@@ -98,6 +99,12 @@
rsdSamplerDestroy
},
+ {
+ rsdFrameBufferInit,
+ rsdFrameBufferSetActive,
+ rsdFrameBufferDestroy
+ },
+
};
pthread_key_t rsdgThreadTLSKey = 0;
diff --git a/libs/rs/driver/rsdFrameBuffer.cpp b/libs/rs/driver/rsdFrameBuffer.cpp
new file mode 100644
index 0000000..6a7dac4
--- /dev/null
+++ b/libs/rs/driver/rsdFrameBuffer.cpp
@@ -0,0 +1,162 @@
+/*
+ * 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 "rsdCore.h"
+#include "rsdFrameBuffer.h"
+
+#include "rsContext.h"
+#include "rsFBOCache.h"
+
+#include <GLES2/gl2.h>
+#include <GLES2/gl2ext.h>
+
+using namespace android;
+using namespace android::renderscript;
+
+struct DrvFrameBuffer {
+ GLuint mFBOId;
+};
+
+void checkError(const Context *rsc) {
+ GLenum status;
+ status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
+ switch (status) {
+ case GL_FRAMEBUFFER_COMPLETE:
+ break;
+ case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT:
+ rsc->setError(RS_ERROR_BAD_VALUE,
+ "Unable to set up render Target: RFRAMEBUFFER_INCOMPLETE_ATTACHMENT");
+ break;
+ case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT:
+ rsc->setError(RS_ERROR_BAD_VALUE,
+ "Unable to set up render Target: GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT");
+ break;
+ case GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS:
+ rsc->setError(RS_ERROR_BAD_VALUE,
+ "Unable to set up render Target: GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS");
+ break;
+ case GL_FRAMEBUFFER_UNSUPPORTED:
+ rsc->setError(RS_ERROR_BAD_VALUE,
+ "Unable to set up render Target: GL_FRAMEBUFFER_UNSUPPORTED");
+ break;
+ }
+}
+
+
+void setDepthAttachment(const Context *rsc, const FBOCache *fb) {
+ if (fb->mHal.state.depthTarget.get() != NULL) {
+ if (fb->mHal.state.depthTarget->getIsTexture()) {
+ uint32_t texID = fb->mHal.state.depthTarget->getTextureID();
+ glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,
+ GL_TEXTURE_2D, texID, 0);
+ } else {
+ uint32_t texID = fb->mHal.state.depthTarget->getRenderTargetID();
+ glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,
+ GL_RENDERBUFFER, texID);
+ }
+ } else {
+ // Reset last attachment
+ glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,
+ GL_RENDERBUFFER, 0);
+ glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,
+ GL_TEXTURE_2D, 0, 0);
+ }
+}
+
+void setColorAttachment(const Context *rsc, const FBOCache *fb) {
+ // Now attach color targets
+ for (uint32_t i = 0; i < fb->mHal.state.colorTargetsCount; i ++) {
+ uint32_t texID = 0;
+ if (fb->mHal.state.colorTargets[i].get() != NULL) {
+ if (fb->mHal.state.colorTargets[i]->getIsTexture()) {
+ uint32_t texID = fb->mHal.state.colorTargets[i]->getTextureID();
+ glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + i,
+ GL_TEXTURE_2D, texID, 0);
+ } else {
+ uint32_t texID = fb->mHal.state.depthTarget->getRenderTargetID();
+ glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + i,
+ GL_RENDERBUFFER, texID);
+ }
+ } else {
+ // Reset last attachment
+ glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + i,
+ GL_RENDERBUFFER, 0);
+ glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + i,
+ GL_TEXTURE_2D, 0, 0);
+ }
+ }
+}
+
+bool renderToFramebuffer(const FBOCache *fb) {
+ if (fb->mHal.state.depthTarget.get() != NULL) {
+ return false;
+ }
+
+ for (uint32_t i = 0; i < fb->mHal.state.colorTargetsCount; i ++) {
+ if (fb->mHal.state.colorTargets[i].get() != NULL) {
+ return false;
+ }
+ }
+ return true;
+}
+
+
+bool rsdFrameBufferInit(const Context *rsc, const FBOCache *fb) {
+ DrvFrameBuffer *drv = (DrvFrameBuffer *)calloc(1, sizeof(DrvFrameBuffer));
+ if (drv == NULL) {
+ return false;
+ }
+ fb->mHal.drv = drv;
+ drv->mFBOId = 0;
+
+ return true;
+}
+
+void rsdFrameBufferSetActive(const Context *rsc, const FBOCache *fb) {
+ DrvFrameBuffer *drv = (DrvFrameBuffer *)fb->mHal.drv;
+
+ bool framebuffer = renderToFramebuffer(fb);
+ if (!framebuffer) {
+ if(drv->mFBOId == 0) {
+ glGenFramebuffers(1, &drv->mFBOId);
+ }
+ glBindFramebuffer(GL_FRAMEBUFFER, drv->mFBOId);
+
+ setDepthAttachment(rsc, fb);
+ setColorAttachment(rsc, fb);
+
+ glViewport(0, 0, fb->mHal.state.colorTargets[0]->getType()->getDimX(),
+ fb->mHal.state.colorTargets[0]->getType()->getDimY());
+
+ checkError(rsc);
+ } else {
+ glBindFramebuffer(GL_FRAMEBUFFER, 0);
+ glViewport(0, 0, rsc->getWidth(), rsc->getHeight());
+ }
+}
+
+void rsdFrameBufferDestroy(const Context *rsc, const FBOCache *fb) {
+ DrvFrameBuffer *drv = (DrvFrameBuffer *)fb->mHal.drv;
+ if(drv->mFBOId != 0) {
+ glDeleteFramebuffers(1, &drv->mFBOId);
+ }
+
+ free(fb->mHal.drv);
+ fb->mHal.drv = NULL;
+}
+
+
diff --git a/libs/rs/driver/rsdFrameBuffer.h b/libs/rs/driver/rsdFrameBuffer.h
new file mode 100644
index 0000000..dec59fc
--- /dev/null
+++ b/libs/rs/driver/rsdFrameBuffer.h
@@ -0,0 +1,30 @@
+/*
+ * 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 RSD_FRAME_BUFFER_H
+#define RSD_FRAME_BUFFER_H
+
+#include <rs_hal.h>
+
+bool rsdFrameBufferInit(const android::renderscript::Context *rsc,
+ const android::renderscript::FBOCache *fb);
+void rsdFrameBufferSetActive(const android::renderscript::Context *rsc,
+ const android::renderscript::FBOCache *fb);
+void rsdFrameBufferDestroy(const android::renderscript::Context *rsc,
+ const android::renderscript::FBOCache *fb);
+
+
+#endif // RSD_FRAME_BUFFER_H
diff --git a/libs/rs/driver/rsdGL.cpp b/libs/rs/driver/rsdGL.cpp
index de9fb51..a70589b 100644
--- a/libs/rs/driver/rsdGL.cpp
+++ b/libs/rs/driver/rsdGL.cpp
@@ -300,7 +300,7 @@
}
-bool rsdGLSetSurface(const Context *rsc, uint32_t w, uint32_t h, ANativeWindow *sur) {
+bool rsdGLSetSurface(const Context *rsc, uint32_t w, uint32_t h, RsNativeWindow sur) {
RsdHal *dc = (RsdHal *)rsc->mHal.drv;
EGLBoolean ret;
@@ -319,7 +319,7 @@
dc->gl.height = 1;
}
- dc->gl.wndSurface = sur;
+ dc->gl.wndSurface = (ANativeWindow *)sur;
if (dc->gl.wndSurface != NULL) {
dc->gl.width = w;
dc->gl.height = h;
diff --git a/libs/rs/driver/rsdGL.h b/libs/rs/driver/rsdGL.h
index 90cbe04..01c8438 100644
--- a/libs/rs/driver/rsdGL.h
+++ b/libs/rs/driver/rsdGL.h
@@ -18,6 +18,7 @@
#define RSD_GL_H
#include <rs_hal.h>
+#include <EGL/egl.h>
class RsdShaderCache;
class RsdVertexArrayState;
@@ -74,7 +75,7 @@
bool rsdGLInit(const android::renderscript::Context *rsc);
void rsdGLShutdown(const android::renderscript::Context *rsc);
bool rsdGLSetSurface(const android::renderscript::Context *rsc,
- uint32_t w, uint32_t h, ANativeWindow *sur);
+ uint32_t w, uint32_t h, RsNativeWindow sur);
void rsdGLSwap(const android::renderscript::Context *rsc);
void rsdGLCheckError(const android::renderscript::Context *rsc,
const char *msg, bool isFatal = false);
diff --git a/libs/rs/rs.spec b/libs/rs/rs.spec
index 1da00a5..87d764d 100644
--- a/libs/rs/rs.spec
+++ b/libs/rs/rs.spec
@@ -1,42 +1,4 @@
-DeviceCreate {
- direct
- nocontext
- ret RsDevice
-}
-
-DeviceDestroy {
- direct
- nocontext
- param RsDevice dev
-}
-
-DeviceSetConfig {
- direct
- nocontext
- param RsDevice dev
- param RsDeviceParam p
- param int32_t value
-}
-
-ContextCreate {
- direct
- nocontext
- param RsDevice dev
- param uint32_t version
- ret RsContext
-}
-
-ContextCreateGL {
- direct
- nocontext
- param RsDevice dev
- param uint32_t version
- param RsSurfaceConfig sc
- param uint32_t dpi
- ret RsContext
-}
-
ContextDestroy {
direct
}
@@ -45,16 +7,14 @@
direct
param void *data
param size_t *receiveLen
- param uint32_t *subID
- param bool wait
+ param uint32_t *usrID
ret RsMessageToClientType
}
ContextPeekMessage {
direct
param size_t *receiveLen
- param uint32_t *subID
- param bool wait
+ param uint32_t *usrID
ret RsMessageToClientType
}
@@ -106,7 +66,7 @@
ContextFinish {
- handcodeApi
+ sync
}
ContextBindRootScript {
@@ -142,7 +102,7 @@
ContextSetSurface {
param uint32_t width
param uint32_t height
- param ANativeWindow *sur
+ param RsNativeWindow sur
}
ContextDump {
diff --git a/libs/rs/rsContext.cpp b/libs/rs/rsContext.cpp
index 98adabc..bab5c58 100644
--- a/libs/rs/rsContext.cpp
+++ b/libs/rs/rsContext.cpp
@@ -18,8 +18,6 @@
#include "rsContext.h"
#include "rsThreadIO.h"
#include <ui/FramebufferNativeWindow.h>
-#include <ui/PixelFormat.h>
-#include <ui/egl/android_natives.h>
#include <sys/types.h>
#include <sys/resource.h>
@@ -238,6 +236,7 @@
rsc->setProgramStore(NULL);
rsc->mStateFont.init(rsc);
rsc->setFont(NULL);
+ rsc->mFBOCache.init(rsc);
}
rsc->mRunning = true;
@@ -245,7 +244,7 @@
while (!rsc->mExit) {
mDraw |= rsc->mIO.playCoreCommands(rsc, !mDraw);
mDraw &= (rsc->mRootScript.get() != NULL);
- mDraw &= (rsc->mWndSurface != NULL);
+ mDraw &= rsc->mHasSurface;
uint32_t targetTime = 0;
if (mDraw && rsc->mIsGraphicsContext) {
@@ -298,6 +297,7 @@
mStateFragment.deinit(this);
mStateFragmentStore.deinit(this);
mStateFont.deinit(this);
+ mFBOCache.deinit(this);
}
//LOGV("destroyWorkerThreadResources 2");
mExit = true;
@@ -344,6 +344,8 @@
bool Context::initContext(Device *dev, const RsSurfaceConfig *sc) {
pthread_mutex_lock(&gInitMutex);
+ mIO.init();
+
dev->addContext(this);
mDev = dev;
if (sc) {
@@ -367,7 +369,7 @@
return false;
}
- mWndSurface = NULL;
+ mHasSurface = false;
timerInit();
timerSet(RS_TIMER_INTERNAL);
@@ -393,7 +395,7 @@
Context::~Context() {
LOGV("Context::~Context");
- mIO.mToCore.flush();
+ mIO.coreFlush();
rsAssert(mExit);
mExit = true;
mPaused = false;
@@ -402,7 +404,6 @@
mIO.shutdown();
int status = pthread_join(mThreadId, &res);
-
if (mHal.funcs.shutdownDriver) {
mHal.funcs.shutdownDriver(this);
}
@@ -417,11 +418,11 @@
LOGV("Context::~Context done");
}
-void Context::setSurface(uint32_t w, uint32_t h, ANativeWindow *sur) {
+void Context::setSurface(uint32_t w, uint32_t h, RsNativeWindow sur) {
rsAssert(mIsGraphicsContext);
mHal.funcs.setSurface(this, w, h, sur);
- mWndSurface = sur;
+ mHasSurface = sur != NULL;
mWidth = w;
mHeight = h;
@@ -505,69 +506,18 @@
}
}
-RsMessageToClientType Context::peekMessageToClient(size_t *receiveLen, uint32_t *subID, bool wait) {
- *receiveLen = 0;
- if (!wait && mIO.mToClient.isEmpty()) {
- return RS_MESSAGE_TO_CLIENT_NONE;
- }
-
- uint32_t bytesData = 0;
- uint32_t commandID = 0;
- const uint32_t *d = (const uint32_t *)mIO.mToClient.get(&commandID, &bytesData);
- *receiveLen = bytesData - sizeof(uint32_t);
- if (bytesData) {
- *subID = d[0];
- }
- return (RsMessageToClientType)commandID;
+RsMessageToClientType Context::peekMessageToClient(size_t *receiveLen, uint32_t *subID) {
+ return (RsMessageToClientType)mIO.getClientHeader(receiveLen, subID);
}
-RsMessageToClientType Context::getMessageToClient(void *data, size_t *receiveLen, uint32_t *subID, size_t bufferLen, bool wait) {
- //LOGE("getMessageToClient %i %i", bufferLen, wait);
- *receiveLen = 0;
- if (!wait && mIO.mToClient.isEmpty()) {
- return RS_MESSAGE_TO_CLIENT_NONE;
- }
-
- //LOGE("getMessageToClient 2 con=%p", this);
- uint32_t bytesData = 0;
- uint32_t commandID = 0;
- const uint32_t *d = (const uint32_t *)mIO.mToClient.get(&commandID, &bytesData);
- //LOGE("getMessageToClient 3 %i %i", commandID, bytesData);
-
- *receiveLen = bytesData - sizeof(uint32_t);
- *subID = d[0];
-
- //LOGE("getMessageToClient %i %i", commandID, *subID);
- if (bufferLen >= (*receiveLen)) {
- memcpy(data, d+1, *receiveLen);
- mIO.mToClient.next();
- return (RsMessageToClientType)commandID;
- }
- return RS_MESSAGE_TO_CLIENT_RESIZE;
+RsMessageToClientType Context::getMessageToClient(void *data, size_t *receiveLen, uint32_t *subID, size_t bufferLen) {
+ return (RsMessageToClientType)mIO.getClientPayload(data, receiveLen, subID, bufferLen);
}
bool Context::sendMessageToClient(const void *data, RsMessageToClientType cmdID,
uint32_t subID, size_t len, bool waitForSpace) const {
- //LOGE("sendMessageToClient %i %i %i %i", cmdID, subID, len, waitForSpace);
- if (cmdID == 0) {
- LOGE("Attempting to send invalid command 0 to client.");
- return false;
- }
- if (!waitForSpace) {
- if (!mIO.mToClient.makeSpaceNonBlocking(len + 12)) {
- // Not enough room, and not waiting.
- return false;
- }
- }
- //LOGE("sendMessageToClient 2");
- uint32_t *p = (uint32_t *)mIO.mToClient.reserve(len + sizeof(subID));
- p[0] = subID;
- if (len > 0) {
- memcpy(p+1, data, len);
- }
- mIO.mToClient.commit(cmdID, len + sizeof(subID));
- //LOGE("sendMessageToClient 3");
- return true;
+
+ return mIO.sendToClient(cmdID, subID, data, len, waitForSpace);
}
void Context::initToClient() {
@@ -577,7 +527,7 @@
}
void Context::deinitToClient() {
- mIO.mToClient.shutdown();
+ mIO.clientShutdown();
}
void Context::setError(RsError e, const char *msg) const {
@@ -664,7 +614,7 @@
rsc->resume();
}
-void rsi_ContextSetSurface(Context *rsc, uint32_t w, uint32_t h, ANativeWindow *sur, size_t sur_length) {
+void rsi_ContextSetSurface(Context *rsc, uint32_t w, uint32_t h, RsNativeWindow sur) {
rsc->setSurface(w, h, sur);
}
@@ -687,35 +637,19 @@
LOGV("rsContextDestroy 2 %p", rsc);
}
-RsContext rsi_ContextCreate(RsDevice vdev, uint32_t version) {
- LOGV("rsContextCreate %p", vdev);
- Device * dev = static_cast<Device *>(vdev);
- Context *rsc = Context::createContext(dev, NULL);
- return rsc;
-}
-
-RsContext rsi_ContextCreateGL(RsDevice vdev, uint32_t version,
- RsSurfaceConfig sc, uint32_t dpi) {
- LOGV("rsContextCreateGL %p", vdev);
- Device * dev = static_cast<Device *>(vdev);
- Context *rsc = Context::createContext(dev, &sc);
- rsc->setDPI(dpi);
- LOGV("rsContextCreateGL ret %p ", rsc);
- return rsc;
-}
RsMessageToClientType rsi_ContextPeekMessage(Context *rsc,
size_t * receiveLen, size_t receiveLen_length,
- uint32_t * subID, size_t subID_length, bool wait) {
- return rsc->peekMessageToClient(receiveLen, subID, wait);
+ uint32_t * subID, size_t subID_length) {
+ return rsc->peekMessageToClient(receiveLen, subID);
}
RsMessageToClientType rsi_ContextGetMessage(Context *rsc, void * data, size_t data_length,
size_t * receiveLen, size_t receiveLen_length,
- uint32_t * subID, size_t subID_length, bool wait) {
+ uint32_t * subID, size_t subID_length) {
rsAssert(subID_length == sizeof(uint32_t));
rsAssert(receiveLen_length == sizeof(size_t));
- return rsc->getMessageToClient(data, receiveLen, subID, data_length, wait);
+ return rsc->getMessageToClient(data, receiveLen, subID, data_length);
}
void rsi_ContextInitToClient(Context *rsc) {
@@ -729,6 +663,23 @@
}
}
+RsContext rsContextCreate(RsDevice vdev, uint32_t version) {
+ LOGV("rsContextCreate %p", vdev);
+ Device * dev = static_cast<Device *>(vdev);
+ Context *rsc = Context::createContext(dev, NULL);
+ return rsc;
+}
+
+RsContext rsContextCreateGL(RsDevice vdev, uint32_t version,
+ RsSurfaceConfig sc, uint32_t dpi) {
+ LOGV("rsContextCreateGL %p", vdev);
+ Device * dev = static_cast<Device *>(vdev);
+ Context *rsc = Context::createContext(dev, &sc);
+ rsc->setDPI(dpi);
+ LOGV("rsContextCreateGL ret %p ", rsc);
+ return rsc;
+}
+
// Only to be called at a3d load time, before object is visible to user
// not thread safe
void rsaGetName(RsContext con, void * obj, const char **name) {
diff --git a/libs/rs/rsContext.h b/libs/rs/rsContext.h
index 1407b7e..be615a3 100644
--- a/libs/rs/rsContext.h
+++ b/libs/rs/rsContext.h
@@ -44,8 +44,6 @@
#endif // ANDROID_RS_SERIALIZE
-class ANativeWindow;
-
// ---------------------------------------------------------------------------
namespace android {
@@ -136,15 +134,15 @@
void pause();
void resume();
- void setSurface(uint32_t w, uint32_t h, ANativeWindow *sur);
+ void setSurface(uint32_t w, uint32_t h, RsNativeWindow sur);
void setPriority(int32_t p);
void destroyWorkerThreadResources();
void assignName(ObjectBase *obj, const char *name, uint32_t len);
void removeName(ObjectBase *obj);
- RsMessageToClientType peekMessageToClient(size_t *receiveLen, uint32_t *subID, bool wait);
- RsMessageToClientType getMessageToClient(void *data, size_t *receiveLen, uint32_t *subID, size_t bufferLen, bool wait);
+ RsMessageToClientType peekMessageToClient(size_t *receiveLen, uint32_t *subID);
+ RsMessageToClientType getMessageToClient(void *data, size_t *receiveLen, uint32_t *subID, size_t bufferLen);
bool sendMessageToClient(const void *data, RsMessageToClientType cmdID, uint32_t subID, size_t len, bool waitForSpace) const;
uint32_t runScript(Script *s);
@@ -244,7 +242,7 @@
static void * threadProc(void *);
static void * helperThreadProc(void *);
- ANativeWindow *mWndSurface;
+ bool mHasSurface;
Vector<ObjectBase *> mNames;
diff --git a/libs/rs/rsDevice.cpp b/libs/rs/rsDevice.cpp
index 849fd98..d7d03f6 100644
--- a/libs/rs/rsDevice.cpp
+++ b/libs/rs/rsDevice.cpp
@@ -40,20 +40,17 @@
}
}
-namespace android {
-namespace renderscript {
-
-RsDevice rsi_DeviceCreate() {
+RsDevice rsDeviceCreate() {
Device * d = new Device();
return d;
}
-void rsi_DeviceDestroy(RsDevice dev) {
+void rsDeviceDestroy(RsDevice dev) {
Device * d = static_cast<Device *>(dev);
delete d;
}
-void rsi_DeviceSetConfig(RsDevice dev, RsDeviceParam p, int32_t value) {
+void rsDeviceSetConfig(RsDevice dev, RsDeviceParam p, int32_t value) {
Device * d = static_cast<Device *>(dev);
if (p == RS_DEVICE_PARAM_FORCE_SOFTWARE_GL) {
d->mForceSW = value != 0;
@@ -62,5 +59,3 @@
rsAssert(0);
}
-}
-}
diff --git a/libs/rs/rsFBOCache.cpp b/libs/rs/rsFBOCache.cpp
index 0f33f67..31a51b7 100644
--- a/libs/rs/rsFBOCache.cpp
+++ b/libs/rs/rsFBOCache.cpp
@@ -19,33 +19,30 @@
#include "rsContext.h"
#include "rsAllocation.h"
-#ifndef ANDROID_RS_SERIALIZE
-#include <GLES/gl.h>
-#include <GLES2/gl2.h>
-#endif //ANDROID_RS_SERIALIZE
-
using namespace android;
using namespace android::renderscript;
FBOCache::FBOCache() {
- mFBOId = 0;
mDirty = true;
- mMaxTargets = 1;
- mColorTargets = new ObjectBaseRef<Allocation>[mMaxTargets];
+ mHal.state.colorTargetsCount = 1;
+ mHal.state.colorTargets = new ObjectBaseRef<Allocation>[mHal.state.colorTargetsCount];
}
FBOCache::~FBOCache() {
- delete[] mColorTargets;
-#ifndef ANDROID_RS_SERIALIZE
- if(mFBOId != 0) {
- glDeleteFramebuffers(1, &mFBOId);
- }
-#endif //ANDROID_RS_SERIALIZE
+ delete[] mHal.state.colorTargets;
+}
+
+void FBOCache::init(Context *rsc) {
+ rsc->mHal.funcs.framebuffer.init(rsc, this);
+}
+
+void FBOCache::deinit(Context *rsc) {
+ rsc->mHal.funcs.framebuffer.destroy(rsc, this);
}
void FBOCache::bindColorTarget(Context *rsc, Allocation *a, uint32_t slot) {
- if (slot >= mMaxTargets) {
+ if (slot >= mHal.state.colorTargetsCount) {
LOGE("Invalid render target index");
return;
}
@@ -62,7 +59,7 @@
a->deferredAllocateRenderTarget(rsc);
}
}
- mColorTargets[slot].set(a);
+ mHal.state.colorTargets[slot].set(a);
mDirty = true;
}
@@ -80,131 +77,34 @@
a->deferredAllocateRenderTarget(rsc);
}
}
- mDepthTarget.set(a);
+ mHal.state.depthTarget.set(a);
mDirty = true;
}
void FBOCache::resetAll(Context *) {
- for (uint32_t i = 0; i < mMaxTargets; i ++) {
- mColorTargets[i].set(NULL);
+ for (uint32_t i = 0; i < mHal.state.colorTargetsCount; i ++) {
+ mHal.state.colorTargets[i].set(NULL);
}
- mDepthTarget.set(NULL);
+ mHal.state.depthTarget.set(NULL);
mDirty = true;
}
-bool FBOCache::renderToFramebuffer() {
- if (mDepthTarget.get() != NULL) {
- return false;
- }
-
- for (uint32_t i = 0; i < mMaxTargets; i ++) {
- if (mColorTargets[i].get() != NULL) {
- return false;
- }
- }
- return true;
-}
-
-void FBOCache::checkError(Context *rsc) {
- GLenum status;
- status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
- switch (status) {
- case GL_FRAMEBUFFER_COMPLETE:
- break;
- case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT:
- rsc->setError(RS_ERROR_BAD_VALUE,
- "Unable to set up render Target: RFRAMEBUFFER_INCOMPLETE_ATTACHMENT");
- break;
- case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT:
- rsc->setError(RS_ERROR_BAD_VALUE,
- "Unable to set up render Target: GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT");
- break;
- case GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS:
- rsc->setError(RS_ERROR_BAD_VALUE,
- "Unable to set up render Target: GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS");
- break;
- case GL_FRAMEBUFFER_UNSUPPORTED:
- rsc->setError(RS_ERROR_BAD_VALUE,
- "Unable to set up render Target: GL_FRAMEBUFFER_UNSUPPORTED");
- break;
- }
-}
-
-void FBOCache::setDepthAttachment(Context *rsc) {
-#ifndef ANDROID_RS_SERIALIZE
- if (mDepthTarget.get() != NULL) {
- mDepthTarget->uploadCheck(rsc);
- if (mDepthTarget->getIsTexture()) {
- uint32_t texID = mDepthTarget->getTextureID();
- glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,
- GL_TEXTURE_2D, texID, 0);
- } else {
- uint32_t texID = mDepthTarget->getRenderTargetID();
- glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,
- GL_RENDERBUFFER, texID);
- }
- } else {
- // Reset last attachment
- glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,
- GL_RENDERBUFFER, 0);
- glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,
- GL_TEXTURE_2D, 0, 0);
- }
-#endif //ANDROID_RS_SERIALIZE
-}
-
-void FBOCache::setColorAttachment(Context *rsc) {
-#ifndef ANDROID_RS_SERIALIZE
- // Now attach color targets
- for (uint32_t i = 0; i < mMaxTargets; i ++) {
- uint32_t texID = 0;
- if (mColorTargets[i].get() != NULL) {
- mColorTargets[i]->uploadCheck(rsc);
- if (mColorTargets[i]->getIsTexture()) {
- uint32_t texID = mColorTargets[i]->getTextureID();
- glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + i,
- GL_TEXTURE_2D, texID, 0);
- } else {
- uint32_t texID = mDepthTarget->getRenderTargetID();
- glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + i,
- GL_RENDERBUFFER, texID);
- }
- } else {
- // Reset last attachment
- glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + i,
- GL_RENDERBUFFER, 0);
- glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + i,
- GL_TEXTURE_2D, 0, 0);
- }
- }
-#endif //ANDROID_RS_SERIALIZE
-}
-
void FBOCache::setup(Context *rsc) {
-#ifndef ANDROID_RS_SERIALIZE
if (!mDirty) {
return;
}
- bool framebuffer = renderToFramebuffer();
-
- if (!framebuffer) {
- if(mFBOId == 0) {
- glGenFramebuffers(1, &mFBOId);
- }
- glBindFramebuffer(GL_FRAMEBUFFER, mFBOId);
-
- setDepthAttachment(rsc);
- setColorAttachment(rsc);
-
- glViewport(0, 0, mColorTargets[0]->getType()->getDimX(),
- mColorTargets[0]->getType()->getDimY());
-
- checkError(rsc);
- } else {
- glBindFramebuffer(GL_FRAMEBUFFER, 0);
- glViewport(0, 0, rsc->getWidth(), rsc->getHeight());
+ if (mHal.state.depthTarget.get() != NULL) {
+ mHal.state.depthTarget->uploadCheck(rsc);
}
+
+ for (uint32_t i = 0; i < mHal.state.colorTargetsCount; i ++) {
+ if (mHal.state.colorTargets[i].get() != NULL) {
+ mHal.state.colorTargets[i]->uploadCheck(rsc);
+ }
+ }
+
+ rsc->mHal.funcs.framebuffer.setActive(rsc, this);
+
mDirty = false;
-#endif //ANDROID_RS_SERIALIZE
}
diff --git a/libs/rs/rsFBOCache.h b/libs/rs/rsFBOCache.h
index c9ae1dc..f42e1f3 100644
--- a/libs/rs/rsFBOCache.h
+++ b/libs/rs/rsFBOCache.h
@@ -30,24 +30,33 @@
FBOCache();
~FBOCache();
+ void init(Context *rsc);
+ void deinit(Context *rsc);
+
void bindColorTarget(Context *rsc, Allocation *a, uint32_t slot);
void bindDepthTarget(Context *, Allocation *a);
void resetAll(Context *);
void setup(Context *);
-protected:
+ struct Hal {
+ mutable void *drv;
+ struct State {
+ ObjectBaseRef<Allocation> *colorTargets;
+ uint32_t colorTargetsCount;
+ ObjectBaseRef<Allocation> depthTarget;
+ };
+ State state;
+ };
+ Hal mHal;
+
+protected:
bool mDirty;
- uint32_t mMaxTargets;
void checkError(Context *);
void setColorAttachment(Context *rsc);
void setDepthAttachment(Context *rsc);
bool renderToFramebuffer();
- ObjectBaseRef<Allocation> *mColorTargets;
- ObjectBaseRef<Allocation> mDepthTarget;
-
- uint32_t mFBOId;
};
diff --git a/libs/rs/rsFifoSocket.cpp b/libs/rs/rsFifoSocket.cpp
index 1ce57b9..848bba5 100644
--- a/libs/rs/rsFifoSocket.cpp
+++ b/libs/rs/rsFifoSocket.cpp
@@ -45,23 +45,34 @@
}
void FifoSocket::writeAsync(const void *data, size_t bytes) {
- size_t ret = ::write(sv[0], data, bytes);
+ if (bytes == 0) {
+ return;
+ }
+ //LOGE("writeAsync %p %i", data, bytes);
+ size_t ret = ::send(sv[0], data, bytes, 0);
+ //LOGE("writeAsync ret %i", ret);
rsAssert(ret == bytes);
}
void FifoSocket::writeWaitReturn(void *retData, size_t retBytes) {
- size_t ret = ::read(sv[1], retData, retBytes);
+ //LOGE("writeWaitReturn %p %i", retData, retBytes);
+ size_t ret = ::recv(sv[0], retData, retBytes, 0);
+ //LOGE("writeWaitReturn %i", ret);
rsAssert(ret == retBytes);
}
size_t FifoSocket::read(void *data, size_t bytes) {
- size_t ret = ::read(sv[0], data, bytes);
+ //LOGE("read %p %i", data, bytes);
+ size_t ret = ::recv(sv[1], data, bytes, 0);
rsAssert(ret == bytes);
+ //LOGE("read ret %i", ret);
return ret;
}
void FifoSocket::readReturn(const void *data, size_t bytes) {
- size_t ret = ::write(sv[1], data, bytes);
+ LOGE("readReturn %p %i", data, bytes);
+ size_t ret = ::send(sv[1], data, bytes, 0);
+ LOGE("readReturn %i", ret);
rsAssert(ret == bytes);
}
diff --git a/libs/rs/rsHandcode.h b/libs/rs/rsHandcode.h
deleted file mode 100644
index e6b722c..0000000
--- a/libs/rs/rsHandcode.h
+++ /dev/null
@@ -1,9 +0,0 @@
-
-#define DATA_SYNC_SIZE 1024
-
-static inline void rsHCAPI_ContextFinish (RsContext rsc) {
- ThreadIO *io = &((Context *)rsc)->mIO;
- uint32_t size = sizeof(RS_CMD_ContextFinish);
- io->mToCore.commitSync(RS_CMD_ID_ContextFinish, size);
-}
-
diff --git a/libs/rs/rsThreadIO.cpp b/libs/rs/rsThreadIO.cpp
index 6e959a7..4429556 100644
--- a/libs/rs/rsThreadIO.cpp
+++ b/libs/rs/rsThreadIO.cpp
@@ -23,16 +23,96 @@
ThreadIO::ThreadIO() {
mToCore.init(16 * 1024);
- mToClient.init(1024);
}
ThreadIO::~ThreadIO() {
}
-void ThreadIO::shutdown() {
- mToCore.shutdown();
+void ThreadIO::init(bool useSocket) {
+ mUsingSocket = useSocket;
+
+ if (mUsingSocket) {
+ mToClientSocket.init();
+ mToCoreSocket.init();
+ } else {
+ mToClient.init(1024);
+ }
}
+void ThreadIO::shutdown() {
+ //LOGE("shutdown 1");
+ mToCore.shutdown();
+ //LOGE("shutdown 2");
+}
+
+void ThreadIO::coreFlush() {
+ //LOGE("coreFlush 1");
+ if (mUsingSocket) {
+ } else {
+ mToCore.flush();
+ }
+ //LOGE("coreFlush 2");
+}
+
+void * ThreadIO::coreHeader(uint32_t cmdID, size_t dataLen) {
+ //LOGE("coreHeader %i %i", cmdID, dataLen);
+ if (mUsingSocket) {
+ CoreCmdHeader hdr;
+ hdr.bytes = dataLen;
+ hdr.cmdID = cmdID;
+ mToCoreSocket.writeAsync(&hdr, sizeof(hdr));
+ } else {
+ mCoreCommandSize = dataLen;
+ mCoreCommandID = cmdID;
+ mCoreDataPtr = (uint8_t *)mToCore.reserve(dataLen);
+ mCoreDataBasePtr = mCoreDataPtr;
+ }
+ //LOGE("coreHeader ret %p", mCoreDataPtr);
+ return mCoreDataPtr;
+}
+
+void ThreadIO::coreData(const void *data, size_t dataLen) {
+ //LOGE("coreData %p %i", data, dataLen);
+ mToCoreSocket.writeAsync(data, dataLen);
+ //LOGE("coreData ret %p", mCoreDataPtr);
+}
+
+void ThreadIO::coreCommit() {
+ //LOGE("coreCommit %p %p %i", mCoreDataPtr, mCoreDataBasePtr, mCoreCommandSize);
+ if (mUsingSocket) {
+ } else {
+ rsAssert((size_t)(mCoreDataPtr - mCoreDataBasePtr) <= mCoreCommandSize);
+ mToCore.commit(mCoreCommandID, mCoreCommandSize);
+ }
+ //LOGE("coreCommit ret");
+}
+
+void ThreadIO::coreCommitSync() {
+ //LOGE("coreCommitSync %p %p %i", mCoreDataPtr, mCoreDataBasePtr, mCoreCommandSize);
+ if (mUsingSocket) {
+ } else {
+ rsAssert((size_t)(mCoreDataPtr - mCoreDataBasePtr) <= mCoreCommandSize);
+ mToCore.commitSync(mCoreCommandID, mCoreCommandSize);
+ }
+ //LOGE("coreCommitSync ret");
+}
+
+void ThreadIO::clientShutdown() {
+ //LOGE("coreShutdown 1");
+ mToClient.shutdown();
+ //LOGE("coreShutdown 2");
+}
+
+void ThreadIO::coreSetReturn(const void *data, size_t dataLen) {
+ rsAssert(dataLen <= sizeof(mToCoreRet));
+ memcpy(&mToCoreRet, data, dataLen);
+}
+
+void ThreadIO::coreGetReturn(void *data, size_t dataLen) {
+ memcpy(data, &mToCoreRet, dataLen);
+}
+
+
bool ThreadIO::playCoreCommands(Context *con, bool waitForCommand) {
bool ret = false;
while (!mToCore.isEmpty() || waitForCommand) {
@@ -64,4 +144,82 @@
return ret;
}
+RsMessageToClientType ThreadIO::getClientHeader(size_t *receiveLen, uint32_t *usrID) {
+ if (mUsingSocket) {
+ mToClientSocket.read(&mLastClientHeader, sizeof(mLastClientHeader));
+ } else {
+ size_t bytesData = 0;
+ const uint32_t *d = (const uint32_t *)mToClient.get(&mLastClientHeader.cmdID, &bytesData);
+ if (bytesData >= sizeof(uint32_t)) {
+ mLastClientHeader.userID = d[0];
+ mLastClientHeader.bytes = bytesData - sizeof(uint32_t);
+ } else {
+ mLastClientHeader.userID = 0;
+ mLastClientHeader.bytes = 0;
+ }
+ }
+ receiveLen[0] = mLastClientHeader.bytes;
+ usrID[0] = mLastClientHeader.userID;
+ return (RsMessageToClientType)mLastClientHeader.cmdID;
+}
+
+RsMessageToClientType ThreadIO::getClientPayload(void *data, size_t *receiveLen,
+ uint32_t *usrID, size_t bufferLen) {
+ receiveLen[0] = mLastClientHeader.bytes;
+ usrID[0] = mLastClientHeader.userID;
+ if (bufferLen < mLastClientHeader.bytes) {
+ return RS_MESSAGE_TO_CLIENT_RESIZE;
+ }
+ if (mUsingSocket) {
+ if (receiveLen[0]) {
+ mToClientSocket.read(data, receiveLen[0]);
+ }
+ return (RsMessageToClientType)mLastClientHeader.cmdID;
+ } else {
+ uint32_t bytesData = 0;
+ uint32_t commandID = 0;
+ const uint32_t *d = (const uint32_t *)mToClient.get(&commandID, &bytesData);
+ //LOGE("getMessageToClient 3 %i %i", commandID, bytesData);
+ //LOGE("getMessageToClient %i %i", commandID, *subID);
+ if (bufferLen >= receiveLen[0]) {
+ memcpy(data, d+1, receiveLen[0]);
+ mToClient.next();
+ return (RsMessageToClientType)commandID;
+ }
+ }
+ return RS_MESSAGE_TO_CLIENT_RESIZE;
+}
+
+bool ThreadIO::sendToClient(RsMessageToClientType cmdID, uint32_t usrID, const void *data,
+ size_t dataLen, bool waitForSpace) {
+ ClientCmdHeader hdr;
+ hdr.bytes = dataLen;
+ hdr.cmdID = cmdID;
+ hdr.userID = usrID;
+ if (mUsingSocket) {
+ mToClientSocket.writeAsync(&hdr, sizeof(hdr));
+ if (dataLen) {
+ mToClientSocket.writeAsync(data, dataLen);
+ }
+ return true;
+ } else {
+ if (!waitForSpace) {
+ if (!mToClient.makeSpaceNonBlocking(dataLen + sizeof(hdr))) {
+ // Not enough room, and not waiting.
+ return false;
+ }
+ }
+
+ //LOGE("sendMessageToClient 2");
+ uint32_t *p = (uint32_t *)mToClient.reserve(dataLen + sizeof(usrID));
+ p[0] = usrID;
+ if (dataLen > 0) {
+ memcpy(p+1, data, dataLen);
+ }
+ mToClient.commit(cmdID, dataLen + sizeof(usrID));
+ //LOGE("sendMessageToClient 3");
+ return true;
+ }
+ return false;
+}
diff --git a/libs/rs/rsThreadIO.h b/libs/rs/rsThreadIO.h
index f9d0de7..cad7318 100644
--- a/libs/rs/rsThreadIO.h
+++ b/libs/rs/rsThreadIO.h
@@ -19,6 +19,7 @@
#include "rsUtils.h"
#include "rsLocklessFifo.h"
+#include "rsFifoSocket.h"
// ---------------------------------------------------------------------------
namespace android {
@@ -31,17 +32,58 @@
ThreadIO();
~ThreadIO();
+ void init(bool useSocket = false);
void shutdown();
// Plays back commands from the client.
// Returns true if any commands were processed.
bool playCoreCommands(Context *con, bool waitForCommand);
+ //LocklessCommandFifo mToCore;
- LocklessCommandFifo mToCore;
+
+
+ void coreFlush();
+ void * coreHeader(uint32_t, size_t dataLen);
+ void coreData(const void *data, size_t dataLen);
+ void coreCommit();
+ void coreCommitSync();
+ void coreSetReturn(const void *data, size_t dataLen);
+ void coreGetReturn(void *data, size_t dataLen);
+
+
+ RsMessageToClientType getClientHeader(size_t *receiveLen, uint32_t *usrID);
+ RsMessageToClientType getClientPayload(void *data, size_t *receiveLen, uint32_t *subID, size_t bufferLen);
+ bool sendToClient(RsMessageToClientType cmdID, uint32_t usrID, const void *data, size_t dataLen, bool waitForSpace);
+ void clientShutdown();
+
+
+protected:
+ typedef struct CoreCmdHeaderRec {
+ uint32_t cmdID;
+ uint32_t bytes;
+ } CoreCmdHeader;
+ typedef struct ClientCmdHeaderRec {
+ uint32_t cmdID;
+ uint32_t bytes;
+ uint32_t userID;
+ } ClientCmdHeader;
+ ClientCmdHeader mLastClientHeader;
+
+ size_t mCoreCommandSize;
+ uint32_t mCoreCommandID;
+ uint8_t * mCoreDataPtr;
+ uint8_t * mCoreDataBasePtr;
+
+ bool mUsingSocket;
LocklessCommandFifo mToClient;
+ LocklessCommandFifo mToCore;
+
+ FifoSocket mToClientSocket;
+ FifoSocket mToCoreSocket;
intptr_t mToCoreRet;
+
};
diff --git a/libs/rs/rsUtils.h b/libs/rs/rsUtils.h
index 3b60af5..3a6c85a 100644
--- a/libs/rs/rsUtils.h
+++ b/libs/rs/rsUtils.h
@@ -32,10 +32,6 @@
#include <time.h>
#include <cutils/atomic.h>
-#ifndef ANDROID_RS_SERIALIZE
-#include <EGL/egl.h>
-#endif
-
#include <math.h>
#include "RenderScript.h"
diff --git a/libs/rs/rs_hal.h b/libs/rs/rs_hal.h
index 4cc2abf..9d8c906 100644
--- a/libs/rs/rs_hal.h
+++ b/libs/rs/rs_hal.h
@@ -37,6 +37,7 @@
class ProgramFragment;
class Mesh;
class Sampler;
+class FBOCache;
typedef void *(*RsHalSymbolLookupFunc)(void *usrptr, char const *symbolName);
@@ -46,7 +47,7 @@
typedef struct {
bool (*initGraphics)(const Context *);
void (*shutdownGraphics)(const Context *);
- bool (*setSurface)(const Context *, uint32_t w, uint32_t h, ANativeWindow *);
+ bool (*setSurface)(const Context *, uint32_t w, uint32_t h, RsNativeWindow);
void (*swap)(const Context *);
void (*shutdownDriver)(Context *);
@@ -128,6 +129,12 @@
void (*destroy)(const Context *rsc, const Sampler *m);
} sampler;
+ struct {
+ bool (*init)(const Context *rsc, const FBOCache *fb);
+ void (*setActive)(const Context *rsc, const FBOCache *fb);
+ void (*destroy)(const Context *rsc, const FBOCache *fb);
+ } framebuffer;
+
} RsdHalFunctions;
diff --git a/libs/rs/rsg_generator.c b/libs/rs/rsg_generator.c
index d550712..b3f6c55 100644
--- a/libs/rs/rsg_generator.c
+++ b/libs/rs/rsg_generator.c
@@ -193,7 +193,6 @@
fprintf(f, "\n");
fprintf(f, "using namespace android;\n");
fprintf(f, "using namespace android::renderscript;\n");
- fprintf(f, "#include \"rsHandcode.h\"\n");
fprintf(f, "\n");
printFuncPointers(f, 0);
@@ -206,18 +205,14 @@
fprintf(f, "static ");
printFuncDecl(f, api, "LF_", 0, 0);
fprintf(f, "\n{\n");
- if (api->handcodeApi || api->direct) {
- if (api->handcodeApi) {
- fprintf(f, " rsHCAPI_%s(rsc", api->name);
- } else {
- fprintf(f, " ");
- if (api->ret.typeName[0]) {
- fprintf(f, "return ");
- }
- fprintf(f, "rsi_%s(", api->name);
- if (!api->nocontext) {
- fprintf(f, "(Context *)rsc");
- }
+ if (api->direct) {
+ fprintf(f, " ");
+ if (api->ret.typeName[0]) {
+ fprintf(f, "return ");
+ }
+ fprintf(f, "rsi_%s(", api->name);
+ if (!api->nocontext) {
+ fprintf(f, "(Context *)rsc");
}
for (ct2=0; ct2 < api->paramCount; ct2++) {
const VarType *vt = &api->params[ct2];
@@ -244,13 +239,13 @@
if (hasInlineDataPointers(api)) {
fprintf(f, " RS_CMD_%s *cmd = NULL;\n", api->name);
fprintf(f, " if (dataSize < 1024) {;\n");
- fprintf(f, " cmd = static_cast<RS_CMD_%s *>(io->mToCore.reserve(dataSize + size));\n", api->name);
+ fprintf(f, " cmd = static_cast<RS_CMD_%s *>(io->coreHeader(RS_CMD_ID_%s, dataSize + size));\n", api->name, api->name);
fprintf(f, " } else {\n");
- fprintf(f, " cmd = static_cast<RS_CMD_%s *>(io->mToCore.reserve(size));\n", api->name);
+ fprintf(f, " cmd = static_cast<RS_CMD_%s *>(io->coreHeader(RS_CMD_ID_%s, size));\n", api->name, api->name);
fprintf(f, " }\n");
fprintf(f, " uint8_t *payload = (uint8_t *)&cmd[1];\n");
} else {
- fprintf(f, " RS_CMD_%s *cmd = static_cast<RS_CMD_%s *>(io->mToCore.reserve(size));\n", api->name, api->name);
+ fprintf(f, " RS_CMD_%s *cmd = static_cast<RS_CMD_%s *>(io->coreHeader(RS_CMD_ID_%s, size));\n", api->name, api->name, api->name);
}
for (ct2=0; ct2 < api->paramCount; ct2++) {
@@ -271,28 +266,30 @@
fprintf(f, " cmd->%s = %s;\n", vt->name, vt->name);
}
}
- if (api->ret.typeName[0]) {
+ if (api->ret.typeName[0] || api->sync) {
needFlush = 1;
}
if (hasInlineDataPointers(api)) {
fprintf(f, " if (dataSize < 1024) {\n");
- fprintf(f, " io->mToCore.commit(RS_CMD_ID_%s, size + dataSize);\n", api->name);
+ fprintf(f, " io->coreCommit();\n");
fprintf(f, " } else {\n");
- fprintf(f, " io->mToCore.commitSync(RS_CMD_ID_%s, size);\n", api->name);
+ fprintf(f, " io->coreCommitSync();\n");
fprintf(f, " }\n");
} else {
- fprintf(f, " io->mToCore.commit");
+ fprintf(f, " io->coreCommit");
if (needFlush) {
fprintf(f, "Sync");
}
- fprintf(f, "(RS_CMD_ID_%s, size);\n", api->name);
+ fprintf(f, "();\n");
}
if (api->ret.typeName[0]) {
- fprintf(f, " return reinterpret_cast<");
+ fprintf(f, "\n ");
printVarType(f, &api->ret);
- fprintf(f, ">(io->mToCoreRet);\n");
+ fprintf(f, " ret;\n");
+ fprintf(f, " io->coreGetReturn(&ret, sizeof(ret));\n");
+ fprintf(f, " return ret;\n");
}
}
fprintf(f, "};\n\n");
@@ -306,86 +303,73 @@
fprintf(f, " const uint32_t cmdSize = sizeof(cmd);\n");
fprintf(f, " const uint32_t cmdID = RS_CMD_ID_%s;\n", api->name);
fprintf(f, " f->writeAsync(&cmdID, sizeof(cmdID));\n");
-
- if (api->handcodeApi) {
- fprintf(f, " rsHCAPI_%s(rsc", api->name);
- for (ct2=0; ct2 < api->paramCount; ct2++) {
- const VarType *vt = &api->params[ct2];
- if (ct2 > 0 || !api->nocontext) {
- fprintf(f, ", ");
- }
- fprintf(f, "%s", vt->name);
- }
- fprintf(f, ");\n");
- } else {
- fprintf(f, " intptr_t offset = cmdSize;\n");
- fprintf(f, " uint32_t dataSize = 0;\n");
- for (ct2=0; ct2 < api->paramCount; ct2++) {
- const VarType *vt = &api->params[ct2];
- if (vt->isConst && vt->ptrLevel) {
- switch(vt->ptrLevel) {
- case 1:
- fprintf(f, " dataSize += %s_length;\n", vt->name);
- break;
- case 2:
- fprintf(f, " for (size_t ct = 0; ct < (%s_length_length / sizeof(%s_length)); ct++) {\n", vt->name, vt->name);
- fprintf(f, " dataSize += %s_length[ct];\n", vt->name);
- fprintf(f, " }\n");
- break;
- default:
- printf("pointer level not handled!!");
- }
- }
- }
- fprintf(f, "\n");
-
- for (ct2=0; ct2 < api->paramCount; ct2++) {
- const VarType *vt = &api->params[ct2];
+ fprintf(f, " intptr_t offset = cmdSize;\n");
+ fprintf(f, " uint32_t dataSize = 0;\n");
+ for (ct2=0; ct2 < api->paramCount; ct2++) {
+ const VarType *vt = &api->params[ct2];
+ if (vt->isConst && vt->ptrLevel) {
switch(vt->ptrLevel) {
- case 0:
- fprintf(f, " cmd.%s = %s;\n", vt->name, vt->name);
- break;
case 1:
- fprintf(f, " cmd.%s = (", vt->name);
- printVarType(f, vt);
- fprintf(f, ")offset;\n");
- fprintf(f, " offset += %s_length;\n", vt->name);
+ fprintf(f, " dataSize += %s_length;\n", vt->name);
break;
case 2:
- fprintf(f, " cmd.%s = (", vt->name);
- printVarType(f, vt);
- fprintf(f, ")offset;\n");
fprintf(f, " for (size_t ct = 0; ct < (%s_length_length / sizeof(%s_length)); ct++) {\n", vt->name, vt->name);
- fprintf(f, " offset += %s_length[ct];\n", vt->name);
+ fprintf(f, " dataSize += %s_length[ct];\n", vt->name);
fprintf(f, " }\n");
break;
default:
printf("pointer level not handled!!");
}
}
- fprintf(f, "\n");
+ }
+ fprintf(f, "\n");
- fprintf(f, " f->writeAsync(&cmd, cmdSize);\n");
- for (ct2=0; ct2 < api->paramCount; ct2++) {
- const VarType *vt = &api->params[ct2];
- if (vt->ptrLevel == 1) {
- fprintf(f, " f->writeAsync(%s, %s_length);\n", vt->name, vt->name);
- }
- if (vt->ptrLevel == 2) {
- fprintf(f, " for (size_t ct = 0; ct < (%s_length_length / sizeof(%s_length)); ct++) {\n", vt->name, vt->name);
- fprintf(f, " f->writeAsync(%s, %s_length[ct]);\n", vt->name, vt->name);
- fprintf(f, " offset += %s_length[ct];\n", vt->name);
- fprintf(f, " }\n");
- }
+ for (ct2=0; ct2 < api->paramCount; ct2++) {
+ const VarType *vt = &api->params[ct2];
+ switch(vt->ptrLevel) {
+ case 0:
+ fprintf(f, " cmd.%s = %s;\n", vt->name, vt->name);
+ break;
+ case 1:
+ fprintf(f, " cmd.%s = (", vt->name);
+ printVarType(f, vt);
+ fprintf(f, ")offset;\n");
+ fprintf(f, " offset += %s_length;\n", vt->name);
+ break;
+ case 2:
+ fprintf(f, " cmd.%s = (", vt->name);
+ printVarType(f, vt);
+ fprintf(f, ")offset;\n");
+ fprintf(f, " for (size_t ct = 0; ct < (%s_length_length / sizeof(%s_length)); ct++) {\n", vt->name, vt->name);
+ fprintf(f, " offset += %s_length[ct];\n", vt->name);
+ fprintf(f, " }\n");
+ break;
+ default:
+ fprintf(stderr, "pointer level not handled!!");
}
+ }
+ fprintf(f, "\n");
- if (api->ret.typeName[0]) {
- fprintf(f, " ");
- printVarType(f, &api->ret);
- fprintf(f, " retValue;\n");
- fprintf(f, " f->writeWaitReturn(&retValue, sizeof(retValue));\n");
- fprintf(f, " return retValue;\n");
+ fprintf(f, " f->writeAsync(&cmd, cmdSize);\n");
+ for (ct2=0; ct2 < api->paramCount; ct2++) {
+ const VarType *vt = &api->params[ct2];
+ if (vt->ptrLevel == 1) {
+ fprintf(f, " f->writeAsync(%s, %s_length);\n", vt->name, vt->name);
}
+ if (vt->ptrLevel == 2) {
+ fprintf(f, " for (size_t ct = 0; ct < (%s_length_length / sizeof(%s_length)); ct++) {\n", vt->name, vt->name);
+ fprintf(f, " f->writeAsync(%s, %s_length[ct]);\n", vt->name, vt->name);
+ fprintf(f, " offset += %s_length[ct];\n", vt->name);
+ fprintf(f, " }\n");
+ }
+ }
+
+ if (api->ret.typeName[0]) {
+ fprintf(f, " ");
+ printVarType(f, &api->ret);
+ fprintf(f, " retValue;\n");
+ fprintf(f, " f->writeWaitReturn(&retValue, sizeof(retValue));\n");
+ fprintf(f, " return retValue;\n");
}
fprintf(f, "}\n\n");
}
@@ -446,7 +430,6 @@
fprintf(f, "\n");
fprintf(f, "namespace android {\n");
fprintf(f, "namespace renderscript {\n");
- fprintf(f, "#include \"rsHandcode.h\"\n");
fprintf(f, "\n");
for (ct=0; ct < apiCount; ct++) {
@@ -463,7 +446,9 @@
fprintf(f, " ");
if (api->ret.typeName[0]) {
- fprintf(f, "con->mIO.mToCoreRet = (intptr_t)");
+ fprintf(f, "\n ");
+ printVarType(f, &api->ret);
+ fprintf(f, " ret = ");
}
fprintf(f, "rsi_%s(con", api->name);
for (ct2=0; ct2 < api->paramCount; ct2++) {
@@ -472,6 +457,10 @@
}
fprintf(f, ");\n");
+ if (api->ret.typeName[0]) {
+ fprintf(f, " con->mIO.coreSetReturn(&ret, sizeof(ret));\n");
+ }
+
fprintf(f, "};\n\n");
}
diff --git a/media/java/android/media/MediaFile.java b/media/java/android/media/MediaFile.java
index 352579a..a54cf28 100644
--- a/media/java/android/media/MediaFile.java
+++ b/media/java/android/media/MediaFile.java
@@ -176,6 +176,7 @@
addFileType("OGG", FILE_TYPE_OGG, "application/ogg", MtpConstants.FORMAT_OGG);
addFileType("OGA", FILE_TYPE_OGG, "application/ogg", MtpConstants.FORMAT_OGG);
addFileType("AAC", FILE_TYPE_AAC, "audio/aac", MtpConstants.FORMAT_AAC);
+ addFileType("AAC", FILE_TYPE_AAC, "audio/aac-adts", MtpConstants.FORMAT_AAC);
addFileType("MKA", FILE_TYPE_MKA, "audio/x-matroska");
addFileType("MID", FILE_TYPE_MID, "audio/midi");
diff --git a/media/java/android/media/MediaRecorder.java b/media/java/android/media/MediaRecorder.java
index 961ee1e..38202f2 100644
--- a/media/java/android/media/MediaRecorder.java
+++ b/media/java/android/media/MediaRecorder.java
@@ -347,7 +347,7 @@
}
/**
- * Store the geodata (latitude and longitude) in the output file.
+ * Set and store the geodata (latitude and longitude) in the output file.
* This method should be called before prepare(). The geodata is
* stored in udta box if the output format is OutputFormat.THREE_GPP
* or OutputFormat.MPEG_4, and is ignored for other output formats.
@@ -361,18 +361,17 @@
* @throws IllegalArgumentException if the given latitude or
* longitude is out of range.
*
- * {@hide}
*/
- public void setGeoData(float latitude, float longitude) {
+ public void setLocation(float latitude, float longitude) {
int latitudex10000 = (int) (latitude * 10000 + 0.5);
int longitudex10000 = (int) (longitude * 10000 + 0.5);
if (latitudex10000 > 900000 || latitudex10000 < -900000) {
- String msg = "Unsupported latitude: " + latitude;
+ String msg = "Latitude: " + latitude + " out of range.";
throw new IllegalArgumentException(msg);
}
if (longitudex10000 > 1800000 || longitudex10000 < -1800000) {
- String msg = "Unsupported longitude: " + longitude;
+ String msg = "Longitude: " + longitude + " out of range";
throw new IllegalArgumentException(msg);
}
@@ -860,6 +859,10 @@
* {@hide}
*/
public static final int MEDIA_RECORDER_TRACK_INFO_START_OFFSET_MS = 1008;
+ /** Provide the total number of data (in kilo-bytes) encoded.
+ * {@hide}
+ */
+ public static final int MEDIA_RECORDER_TRACK_INFO_DATA_KBYTES = 1009;
/**
* {@hide}
*/
diff --git a/media/java/android/mtp/MtpStorage.java b/media/java/android/mtp/MtpStorage.java
index 21a18ca..7932d34 100644
--- a/media/java/android/mtp/MtpStorage.java
+++ b/media/java/android/mtp/MtpStorage.java
@@ -16,6 +16,8 @@
package android.mtp;
+import android.os.storage.StorageVolume;
+
/**
* This class represents a storage unit on an MTP device.
* Used only for MTP support in USB responder mode.
@@ -31,13 +33,12 @@
private final long mReserveSpace;
private final boolean mRemovable;
- public MtpStorage(int id, String path, String description,
- long reserveSpace, boolean removable) {
- mStorageId = id;
- mPath = path;
- mDescription = description;
- mReserveSpace = reserveSpace;
- mRemovable = removable;
+ public MtpStorage(StorageVolume volume) {
+ mStorageId = volume.getStorageId();
+ mPath = volume.getPath();
+ mDescription = volume.getDescription();
+ mReserveSpace = volume.getMtpReserveSpace();
+ mRemovable = volume.isRemovable();
}
/**
diff --git a/media/libstagefright/AwesomePlayer.cpp b/media/libstagefright/AwesomePlayer.cpp
index b45e5d3..fb7a871 100644
--- a/media/libstagefright/AwesomePlayer.cpp
+++ b/media/libstagefright/AwesomePlayer.cpp
@@ -24,11 +24,13 @@
#include "include/ARTSPController.h"
#include "include/AwesomePlayer.h"
+#include "include/DRMExtractor.h"
#include "include/SoftwareRenderer.h"
#include "include/NuCachedSource2.h"
#include "include/ThrottledSource.h"
#include "include/MPEG2TSExtractor.h"
#include "include/TimedTextPlayer.h"
+#include "include/WVMExtractor.h"
#include <binder/IPCThreadState.h>
#include <binder/IServiceManager.h>
@@ -447,6 +449,7 @@
cancelPlayerEvents();
+ mWVMExtractor.clear();
mCachedSource.clear();
mAudioTrack.clear();
mVideoTrack.clear();
@@ -545,6 +548,11 @@
*durationUs = cachedDataRemaining * 8000000ll / bitrate;
*eos = (finalStatus != OK);
return true;
+ } else if (mWVMExtractor != NULL) {
+ status_t finalStatus;
+ *durationUs = mWVMExtractor->getCachedDurationUs(&finalStatus);
+ *eos = (finalStatus != OK);
+ return true;
}
return false;
@@ -637,6 +645,30 @@
}
}
}
+ } else if (mWVMExtractor != NULL) {
+ status_t finalStatus;
+
+ int64_t cachedDurationUs
+ = mWVMExtractor->getCachedDurationUs(&finalStatus);
+
+ bool eos = (finalStatus != OK);
+
+ if (eos) {
+ if (finalStatus == ERROR_END_OF_STREAM) {
+ notifyListener_l(MEDIA_BUFFERING_UPDATE, 100);
+ }
+ if (mFlags & PREPARING) {
+ LOGV("cache has reached EOS, prepare is done.");
+ finishAsyncPrepare_l();
+ }
+ } else {
+ int percentage = 100.0 * (double)cachedDurationUs / mDurationUs;
+ if (percentage > 100) {
+ percentage = 100;
+ }
+
+ notifyListener_l(MEDIA_BUFFERING_UPDATE, percentage);
+ }
}
int64_t cachedDurationUs;
@@ -1425,7 +1457,7 @@
mVideoBuffer = NULL;
}
- if (mSeeking == SEEK && mCachedSource != NULL && mAudioSource != NULL
+ if (mSeeking == SEEK && isStreamingHTTP() && mAudioSource != NULL
&& !(mFlags & SEEK_PREVIEW)) {
// We're going to seek the video source first, followed by
// the audio source.
@@ -1760,8 +1792,19 @@
status_t AwesomePlayer::finishSetDataSource_l() {
sp<DataSource> dataSource;
+ bool isWidevineStreaming = false;
+ if (!strncasecmp("widevine://", mUri.string(), 11)) {
+ isWidevineStreaming = true;
+
+ String8 newURI = String8("http://");
+ newURI.append(mUri.string() + 11);
+
+ mUri = newURI;
+ }
+
if (!strncasecmp("http://", mUri.string(), 7)
- || !strncasecmp("https://", mUri.string(), 8)) {
+ || !strncasecmp("https://", mUri.string(), 8)
+ || isWidevineStreaming) {
mConnectingDataSource = HTTPBase::Create(
(mFlags & INCOGNITO)
? HTTPBase::kFlagIncognito
@@ -1778,16 +1821,24 @@
return err;
}
+ if (!isWidevineStreaming) {
+ // The widevine extractor does its own caching.
+
#if 0
- mCachedSource = new NuCachedSource2(
- new ThrottledSource(
- mConnectingDataSource, 50 * 1024 /* bytes/sec */));
+ mCachedSource = new NuCachedSource2(
+ new ThrottledSource(
+ mConnectingDataSource, 50 * 1024 /* bytes/sec */));
#else
- mCachedSource = new NuCachedSource2(mConnectingDataSource);
+ mCachedSource = new NuCachedSource2(mConnectingDataSource);
#endif
+
+ dataSource = mCachedSource;
+ } else {
+ dataSource = mConnectingDataSource;
+ }
+
mConnectingDataSource.clear();
- dataSource = mCachedSource;
String8 contentType = dataSource->getMIMEType();
@@ -1801,28 +1852,35 @@
// could block on the datasource for a significant amount of time.
// During that time we'd be unable to abort the preparation phase
// without this prefill.
+ if (mCachedSource != NULL) {
+ // We're going to prefill the cache before trying to instantiate
+ // the extractor below, as the latter is an operation that otherwise
+ // could block on the datasource for a significant amount of time.
+ // During that time we'd be unable to abort the preparation phase
+ // without this prefill.
- mLock.unlock();
+ mLock.unlock();
- for (;;) {
- status_t finalStatus;
- size_t cachedDataRemaining =
- mCachedSource->approxDataRemaining(&finalStatus);
+ for (;;) {
+ status_t finalStatus;
+ size_t cachedDataRemaining =
+ mCachedSource->approxDataRemaining(&finalStatus);
- if (finalStatus != OK || cachedDataRemaining >= kHighWaterMarkBytes
- || (mFlags & PREPARE_CANCELLED)) {
- break;
+ if (finalStatus != OK || cachedDataRemaining >= kHighWaterMarkBytes
+ || (mFlags & PREPARE_CANCELLED)) {
+ break;
+ }
+
+ usleep(200000);
}
- usleep(200000);
+ mLock.lock();
}
- mLock.lock();
- }
-
- if (mFlags & PREPARE_CANCELLED) {
- LOGI("Prepare cancelled while waiting for initial cache fill.");
- return UNKNOWN_ERROR;
+ if (mFlags & PREPARE_CANCELLED) {
+ LOGI("Prepare cancelled while waiting for initial cache fill.");
+ return UNKNOWN_ERROR;
+ }
}
} else if (!strncasecmp("rtsp://", mUri.string(), 7)) {
if (mLooper == NULL) {
@@ -1856,10 +1914,29 @@
return UNKNOWN_ERROR;
}
- sp<MediaExtractor> extractor = MediaExtractor::Create(dataSource);
+ sp<MediaExtractor> extractor;
- if (extractor == NULL) {
- return UNKNOWN_ERROR;
+ if (isWidevineStreaming) {
+ String8 mimeType;
+ float confidence;
+ sp<AMessage> dummy;
+ bool success = SniffDRM(dataSource, &mimeType, &confidence, &dummy);
+
+ if (!success
+ || strcasecmp(
+ mimeType.string(), MEDIA_MIMETYPE_CONTAINER_WVM)) {
+ return ERROR_UNSUPPORTED;
+ }
+
+ mWVMExtractor = new WVMExtractor(dataSource);
+ mWVMExtractor->setAdaptiveStreamingMode(true);
+ extractor = mWVMExtractor;
+ } else {
+ extractor = MediaExtractor::Create(dataSource);
+
+ if (extractor == NULL) {
+ return UNKNOWN_ERROR;
+ }
}
dataSource->getDrmInfo(mDecryptHandle, &mDrmManagerClient);
@@ -1871,7 +1948,15 @@
}
}
- return setDataSource_l(extractor);
+ status_t err = setDataSource_l(extractor);
+
+ if (err != OK) {
+ mWVMExtractor.clear();
+
+ return err;
+ }
+
+ return OK;
}
void AwesomePlayer::abortPrepare(status_t err) {
@@ -1932,7 +2017,7 @@
mFlags |= PREPARING_CONNECTED;
- if (mCachedSource != NULL || mRTSPController != NULL) {
+ if (isStreamingHTTP() || mRTSPController != NULL) {
postBufferingEvent_l();
} else {
finishAsyncPrepare_l();
@@ -1985,4 +2070,9 @@
status_t AwesomePlayer::getParameter(int key, Parcel *reply) {
return OK;
}
+
+bool AwesomePlayer::isStreamingHTTP() const {
+ return mCachedSource != NULL || mWVMExtractor != NULL;
+}
+
} // namespace android
diff --git a/media/libstagefright/MPEG4Extractor.cpp b/media/libstagefright/MPEG4Extractor.cpp
index c79d02e..6692809 100644
--- a/media/libstagefright/MPEG4Extractor.cpp
+++ b/media/libstagefright/MPEG4Extractor.cpp
@@ -2171,6 +2171,9 @@
// Just give these file types a chance.
FOURCC('q', 't', ' ', ' '), // Apple's QuickTime
FOURCC('M', 'S', 'N', 'V'), // Sony's PSP
+
+ FOURCC('3', 'g', '2', 'a'), // 3GPP2
+ FOURCC('3', 'g', '2', 'b'),
};
for (size_t i = 0;
diff --git a/media/libstagefright/MPEG4Writer.cpp b/media/libstagefright/MPEG4Writer.cpp
index 9dc83a6..f6a8b17 100644
--- a/media/libstagefright/MPEG4Writer.cpp
+++ b/media/libstagefright/MPEG4Writer.cpp
@@ -33,6 +33,7 @@
#include <media/stagefright/MediaSource.h>
#include <media/stagefright/Utils.h>
#include <media/mediarecorder.h>
+#include <cutils/properties.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
@@ -743,7 +744,7 @@
endBox(); // moov
}
-void MPEG4Writer::writeFtypBox(const MetaData *param) {
+void MPEG4Writer::writeFtypBox(MetaData *param) {
beginBox("ftyp");
int32_t fileType;
@@ -760,7 +761,27 @@
endBox();
}
+static bool isTestModeEnabled() {
+#if (PROPERTY_VALUE_MAX < 5)
+#error "PROPERTY_VALUE_MAX must be at least 5"
+#endif
+
+ // Test mode is enabled only if rw.media.record.test system
+ // property is enabled.
+ char value[PROPERTY_VALUE_MAX];
+ if (property_get("rw.media.record.test", value, NULL) &&
+ (!strcasecmp(value, "true") || !strcasecmp(value, "1"))) {
+ return true;
+ }
+ return false;
+}
+
void MPEG4Writer::sendSessionSummary() {
+ // Send session summary only if test mode is enabled
+ if (!isTestModeEnabled()) {
+ return;
+ }
+
for (List<ChunkInfo>::iterator it = mChunkInfos.begin();
it != mChunkInfos.end(); ++it) {
int trackNum = it->mTrack->getTrackId() << 28;
@@ -2227,6 +2248,12 @@
}
void MPEG4Writer::Track::sendTrackSummary(bool hasMultipleTracks) {
+
+ // Send track summary only if test mode is enabled.
+ if (!isTestModeEnabled()) {
+ return;
+ }
+
int trackNum = (mTrackId << 28);
mOwner->notify(MEDIA_RECORDER_TRACK_EVENT_INFO,
@@ -2256,6 +2283,10 @@
(initialDelayUs) / 1000);
}
+ mOwner->notify(MEDIA_RECORDER_TRACK_EVENT_INFO,
+ trackNum | MEDIA_RECORDER_TRACK_INFO_DATA_KBYTES,
+ mMdatSizeBytes / 1024);
+
if (hasMultipleTracks) {
mOwner->notify(MEDIA_RECORDER_TRACK_EVENT_INFO,
trackNum | MEDIA_RECORDER_TRACK_INFO_MAX_CHUNK_DUR_MS,
diff --git a/media/libstagefright/MetaData.cpp b/media/libstagefright/MetaData.cpp
index aac94a6..884f3b4 100644
--- a/media/libstagefright/MetaData.cpp
+++ b/media/libstagefright/MetaData.cpp
@@ -83,7 +83,7 @@
return setData(key, TYPE_RECT, &r, sizeof(r));
}
-bool MetaData::findCString(uint32_t key, const char **value) const {
+bool MetaData::findCString(uint32_t key, const char **value) {
uint32_t type;
const void *data;
size_t size;
@@ -96,7 +96,7 @@
return true;
}
-bool MetaData::findInt32(uint32_t key, int32_t *value) const {
+bool MetaData::findInt32(uint32_t key, int32_t *value) {
uint32_t type;
const void *data;
size_t size;
@@ -111,7 +111,7 @@
return true;
}
-bool MetaData::findInt64(uint32_t key, int64_t *value) const {
+bool MetaData::findInt64(uint32_t key, int64_t *value) {
uint32_t type;
const void *data;
size_t size;
@@ -126,7 +126,7 @@
return true;
}
-bool MetaData::findFloat(uint32_t key, float *value) const {
+bool MetaData::findFloat(uint32_t key, float *value) {
uint32_t type;
const void *data;
size_t size;
@@ -141,7 +141,7 @@
return true;
}
-bool MetaData::findPointer(uint32_t key, void **value) const {
+bool MetaData::findPointer(uint32_t key, void **value) {
uint32_t type;
const void *data;
size_t size;
@@ -159,7 +159,7 @@
bool MetaData::findRect(
uint32_t key,
int32_t *left, int32_t *top,
- int32_t *right, int32_t *bottom) const {
+ int32_t *right, int32_t *bottom) {
uint32_t type;
const void *data;
size_t size;
diff --git a/media/libstagefright/OMXCodec.cpp b/media/libstagefright/OMXCodec.cpp
index cd5bdfb..0f0ffd4 100644
--- a/media/libstagefright/OMXCodec.cpp
+++ b/media/libstagefright/OMXCodec.cpp
@@ -4077,10 +4077,10 @@
numChannels, params.nChannels);
}
- if (sampleRate != params.nSamplingRate) {
+ if (sampleRate != (int32_t)params.nSamplingRate) {
LOGW("Codec outputs at different sampling rate than "
"what the input stream contains (contains data at "
- "%d Hz, codec outputs %d Hz)",
+ "%d Hz, codec outputs %lu Hz)",
sampleRate, params.nSamplingRate);
}
@@ -4203,6 +4203,14 @@
break;
}
}
+
+ // If the input format contains rotation information, flag the output
+ // format accordingly.
+
+ int32_t rotationDegrees;
+ if (mSource->getFormat()->findInt32(kKeyRotation, &rotationDegrees)) {
+ mOutputFormat->setInt32(kKeyRotation, rotationDegrees);
+ }
}
status_t OMXCodec::pause() {
diff --git a/media/libstagefright/WVMExtractor.cpp b/media/libstagefright/WVMExtractor.cpp
index 7c72852..83a1eaa 100644
--- a/media/libstagefright/WVMExtractor.cpp
+++ b/media/libstagefright/WVMExtractor.cpp
@@ -45,7 +45,8 @@
static Mutex gWVMutex;
WVMExtractor::WVMExtractor(const sp<DataSource> &source)
- : mDataSource(source) {
+ : mDataSource(source),
+ mUseAdaptiveStreaming(false) {
{
Mutex::Autolock autoLock(gWVMutex);
if (gVendorLibHandle == NULL) {
@@ -100,5 +101,21 @@
return mImpl->getMetaData();
}
+int64_t WVMExtractor::getCachedDurationUs(status_t *finalStatus) {
+ // TODO: Fill this with life.
+
+ *finalStatus = OK;
+
+ return 0;
+}
+
+void WVMExtractor::setAdaptiveStreamingMode(bool adaptive) {
+ mUseAdaptiveStreaming = adaptive;
+}
+
+bool WVMExtractor::getAdaptiveStreamingMode() const {
+ return mUseAdaptiveStreaming;
+}
+
} //namespace android
diff --git a/media/libstagefright/colorconversion/Android.mk b/media/libstagefright/colorconversion/Android.mk
index 62ba40f..702a7b4 100644
--- a/media/libstagefright/colorconversion/Android.mk
+++ b/media/libstagefright/colorconversion/Android.mk
@@ -9,6 +9,10 @@
$(TOP)/frameworks/base/include/media/stagefright/openmax \
$(TOP)/hardware/msm7k
+ifneq ($(filter crespo crespo4g,$(TARGET_DEVICE)),)
+LOCAL_CFLAGS += -DTHIS_IS_CRESPO=1
+endif
+
LOCAL_MODULE:= libstagefright_color_conversion
include $(BUILD_STATIC_LIBRARY)
diff --git a/media/libstagefright/colorconversion/SoftwareRenderer.cpp b/media/libstagefright/colorconversion/SoftwareRenderer.cpp
index a4e8ee4..1828ac8 100644
--- a/media/libstagefright/colorconversion/SoftwareRenderer.cpp
+++ b/media/libstagefright/colorconversion/SoftwareRenderer.cpp
@@ -59,6 +59,7 @@
size_t bufWidth, bufHeight;
switch (mColorFormat) {
+#ifndef THIS_IS_CRESPO
case OMX_COLOR_FormatYUV420Planar:
{
halFormat = HAL_PIXEL_FORMAT_YV12;
@@ -66,6 +67,7 @@
bufHeight = (mHeight + 1) & ~1;
break;
}
+#endif
default:
halFormat = HAL_PIXEL_FORMAT_RGB_565;
@@ -87,7 +89,11 @@
native_window_set_usage(
mNativeWindow.get(),
GRALLOC_USAGE_SW_READ_NEVER | GRALLOC_USAGE_SW_WRITE_OFTEN
- | GRALLOC_USAGE_HW_TEXTURE | GRALLOC_USAGE_EXTERNAL_DISP));
+ | GRALLOC_USAGE_HW_TEXTURE
+#ifndef THIS_IS_CRESPO
+ | GRALLOC_USAGE_EXTERNAL_DISP
+#endif
+ ));
// Width must be multiple of 32???
CHECK_EQ(0, native_window_set_buffers_geometry(
diff --git a/media/libstagefright/include/AwesomePlayer.h b/media/libstagefright/include/AwesomePlayer.h
index 835d2bb..3c9a121 100644
--- a/media/libstagefright/include/AwesomePlayer.h
+++ b/media/libstagefright/include/AwesomePlayer.h
@@ -45,6 +45,7 @@
class DecryptHandle;
class TimedTextPlayer;
+struct WVMExtractor;
struct AwesomeRenderer : public RefBase {
AwesomeRenderer() {}
@@ -231,6 +232,8 @@
int64_t mLastVideoTimeUs;
TimedTextPlayer *mTextPlayer;
+ sp<WVMExtractor> mWVMExtractor;
+
status_t setDataSource_l(
const char *uri,
const KeyedVector<String8, String8> *headers = NULL);
@@ -286,6 +289,8 @@
void shutdownVideoDecoder_l();
void setNativeWindow_l(const sp<ANativeWindow> &native);
+ bool isStreamingHTTP() const;
+
AwesomePlayer(const AwesomePlayer &);
AwesomePlayer &operator=(const AwesomePlayer &);
};
diff --git a/media/libstagefright/include/WVMExtractor.h b/media/libstagefright/include/WVMExtractor.h
index 0da45a8..62e5aa5 100644
--- a/media/libstagefright/include/WVMExtractor.h
+++ b/media/libstagefright/include/WVMExtractor.h
@@ -19,6 +19,7 @@
#define WVM_EXTRACTOR_H_
#include <media/stagefright/MediaExtractor.h>
+#include <utils/Errors.h>
namespace android {
@@ -33,12 +34,31 @@
virtual sp<MetaData> getTrackMetaData(size_t index, uint32_t flags);
virtual sp<MetaData> getMetaData();
+ // Return the amount of data cached from the current
+ // playback positiion (in us).
+ // While more data is still being fetched *finalStatus == OK,
+ // Once fetching is completed (no more data available), *finalStatus != OK
+ // If fetching completed normally (i.e. reached EOS instead of IO error)
+ // *finalStatus == ERROR_END_OF_STREAM
+ int64_t getCachedDurationUs(status_t *finalStatus);
+
+ // Set to use adaptive streaming mode by the WV component.
+ // If adaptive == true, adaptive streaming mode will be used.
+ // Default mode is non-adaptive streaming mode.
+ // Should set to use adaptive streaming mode only if widevine:// protocol
+ // is used.
+ void setAdaptiveStreamingMode(bool adaptive);
+
+ // Retrieve the adaptive streaming mode used by the WV component.
+ bool getAdaptiveStreamingMode() const;
+
protected:
virtual ~WVMExtractor();
private:
sp<DataSource> mDataSource;
sp<MediaExtractor> mImpl;
+ bool mUseAdaptiveStreaming;
WVMExtractor(const WVMExtractor &);
WVMExtractor &operator=(const WVMExtractor &);
diff --git a/opengl/libs/Android.mk b/opengl/libs/Android.mk
index 0747efb..afefee6 100644
--- a/opengl/libs/Android.mk
+++ b/opengl/libs/Android.mk
@@ -7,7 +7,11 @@
include $(CLEAR_VARS)
LOCAL_SRC_FILES:= \
+ EGL/egl_tls.cpp \
+ EGL/egl_display.cpp \
+ EGL/egl_object.cpp \
EGL/egl.cpp \
+ EGL/eglApi.cpp \
EGL/trace.cpp \
EGL/getProcAddress.cpp.arm \
EGL/hooks.cpp \
diff --git a/opengl/libs/EGL/egl.cpp b/opengl/libs/EGL/egl.cpp
index aabba28..31fe306 100644
--- a/opengl/libs/EGL/egl.cpp
+++ b/opengl/libs/EGL/egl.cpp
@@ -17,14 +17,9 @@
#include <ctype.h>
#include <stdlib.h>
#include <string.h>
-#include <errno.h>
-#include <dlfcn.h>
-#include <sys/ioctl.h>
-
-#ifdef HAVE_ANDROID_OS
-#include <linux/android_pmem.h>
-#endif
+#include <hardware/gralloc.h>
+#include <system/window.h>
#include <EGL/egl.h>
#include <EGL/eglext.h>
@@ -36,266 +31,41 @@
#include <cutils/properties.h>
#include <cutils/memory.h>
-#include <utils/SortedVector.h>
-#include <utils/KeyedVector.h>
#include <utils/String8.h>
-#include <ui/egl/android_natives.h>
-
-#include "hooks.h"
#include "egl_impl.h"
-#include "Loader.h"
-#include "glesv2dbg.h"
#include "egl_tls.h"
+#include "glesv2dbg.h"
+#include "hooks.h"
+#include "Loader.h"
-#define setError(_e, _r) setErrorEtc(__FUNCTION__, __LINE__, _e, _r)
+#include "egl_display.h"
+#include "egl_object.h"
// ----------------------------------------------------------------------------
namespace android {
// ----------------------------------------------------------------------------
-#define VERSION_MAJOR 1
-#define VERSION_MINOR 4
-static char const * const gVendorString = "Android";
-static char const * const gVersionString = "1.4 Android META-EGL";
-static char const * const gClientApiString = "OpenGL ES";
-static char const * const gExtensionString =
- "EGL_KHR_image "
- "EGL_KHR_image_base "
- "EGL_KHR_image_pixmap "
- "EGL_KHR_gl_texture_2D_image "
- "EGL_KHR_gl_texture_cubemap_image "
- "EGL_KHR_gl_renderbuffer_image "
- "EGL_KHR_fence_sync "
- "EGL_ANDROID_image_native_buffer "
- "EGL_ANDROID_swap_rectangle "
- ;
+egl_connection_t gEGLImpl[IMPL_NUM_IMPLEMENTATIONS];
+gl_hooks_t gHooks[2][IMPL_NUM_IMPLEMENTATIONS];
+gl_hooks_t gHooksNoContext;
+pthread_key_t gGLWrapperKey = -1;
// ----------------------------------------------------------------------------
-class egl_object_t;
-struct egl_display_t;
-static egl_display_t* get_display(EGLDisplay dpy);
-
-struct egl_config_t {
- egl_config_t() {}
- egl_config_t(int impl, EGLConfig config)
- : impl(impl), config(config), configId(0), implConfigId(0) { }
- int impl; // the implementation this config is for
- EGLConfig config; // the implementation's EGLConfig
- EGLint configId; // our CONFIG_ID
- EGLint implConfigId; // the implementation's CONFIG_ID
- inline bool operator < (const egl_config_t& rhs) const {
- if (impl < rhs.impl) return true;
- if (impl > rhs.impl) return false;
- return config < rhs.config;
- }
-};
-
-struct egl_display_t {
- enum { NOT_INITIALIZED, INITIALIZED, TERMINATED };
-
- struct strings_t {
- char const * vendor;
- char const * version;
- char const * clientApi;
- char const * extensions;
- };
-
- struct DisplayImpl {
- DisplayImpl() : dpy(EGL_NO_DISPLAY), config(0),
- state(NOT_INITIALIZED), numConfigs(0) { }
- EGLDisplay dpy;
- EGLConfig* config;
- EGLint state;
- EGLint numConfigs;
- strings_t queryString;
- };
-
- uint32_t magic;
- DisplayImpl disp[IMPL_NUM_IMPLEMENTATIONS];
- EGLint numTotalConfigs;
- egl_config_t* configs;
- uint32_t refs;
- Mutex lock;
-
- SortedVector<egl_object_t*> objects;
-
- egl_display_t() : magic('_dpy'), numTotalConfigs(0), configs(0), refs(0) { }
- ~egl_display_t() { magic = 0; }
- inline bool isReady() const { return (refs > 0); }
- inline bool isValid() const { return magic == '_dpy'; }
- inline bool isAlive() const { return isValid(); }
-};
-
-class egl_object_t {
- egl_display_t *display;
- volatile int32_t terminated;
- mutable volatile int32_t count;
-
-public:
- egl_object_t(EGLDisplay dpy) : display(get_display(dpy)), terminated(0), count(1) {
- Mutex::Autolock _l(display->lock);
- display->objects.add(this);
- }
-
- inline bool isAlive() const { return !terminated; }
-
-private:
- bool get() {
- Mutex::Autolock _l(display->lock);
- if (display->objects.indexOf(this) >= 0) {
- android_atomic_inc(&count);
- return true;
- }
- return false;
- }
-
- bool put() {
- Mutex::Autolock _l(display->lock);
- if (android_atomic_dec(&count) == 1) {
- display->objects.remove(this);
- return true;
- }
- return false;
- }
-
-public:
- template <typename N, typename T>
- struct LocalRef {
- N* ref;
- LocalRef(T o) : ref(0) {
- N* native = reinterpret_cast<N*>(o);
- if (o && native->get()) {
- ref = native;
- }
- }
- ~LocalRef() {
- if (ref && ref->put()) {
- delete ref;
- }
- }
- inline N* get() {
- return ref;
- }
- void acquire() const {
- if (ref) {
- android_atomic_inc(&ref->count);
- }
- }
- void release() const {
- if (ref) {
- int32_t c = android_atomic_dec(&ref->count);
- // ref->count cannot be 1 prior atomic_dec because we have
- // a reference, and if we have one, it means there was
- // already one before us.
- LOGE_IF(c==1, "refcount is now 0 in release()");
- }
- }
- void terminate() {
- if (ref) {
- ref->terminated = 1;
- release();
- }
- }
- };
-};
-
-struct egl_surface_t : public egl_object_t
-{
- typedef egl_object_t::LocalRef<egl_surface_t, EGLSurface> Ref;
-
- egl_surface_t(EGLDisplay dpy, EGLConfig config, EGLNativeWindowType win,
- EGLSurface surface, int impl, egl_connection_t const* cnx)
- : egl_object_t(dpy), dpy(dpy), surface(surface), config(config), win(win), impl(impl), cnx(cnx) {
- }
- ~egl_surface_t() {
- }
- EGLDisplay dpy;
- EGLSurface surface;
- EGLConfig config;
- sp<ANativeWindow> win;
- int impl;
- egl_connection_t const* cnx;
-};
-
-struct egl_context_t : public egl_object_t
-{
- 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(dpy), dpy(dpy), context(context), config(config), read(0), draw(0),
- impl(impl), cnx(cnx), version(version)
- {
- }
- ~egl_context_t()
- {
- }
- EGLDisplay dpy;
- EGLContext context;
- EGLConfig config;
- EGLSurface read;
- EGLSurface draw;
- int impl;
- egl_connection_t const* cnx;
- int version;
-};
-
-struct egl_image_t : public egl_object_t
-{
- typedef egl_object_t::LocalRef<egl_image_t, EGLImageKHR> Ref;
-
- egl_image_t(EGLDisplay dpy, EGLContext context)
- : egl_object_t(dpy), dpy(dpy), context(context)
- {
- memset(images, 0, sizeof(images));
- }
- EGLDisplay dpy;
- EGLContext context;
- EGLImageKHR images[IMPL_NUM_IMPLEMENTATIONS];
-};
-
-struct egl_sync_t : public egl_object_t
-{
- typedef egl_object_t::LocalRef<egl_sync_t, EGLSyncKHR> Ref;
-
- egl_sync_t(EGLDisplay dpy, EGLContext context, EGLSyncKHR sync)
- : egl_object_t(dpy), dpy(dpy), context(context), sync(sync)
- {
- }
- EGLDisplay dpy;
- EGLContext context;
- EGLSyncKHR sync;
-};
-
-typedef egl_surface_t::Ref SurfaceRef;
-typedef egl_context_t::Ref ContextRef;
-typedef egl_image_t::Ref ImageRef;
-typedef egl_sync_t::Ref SyncRef;
-
-// ----------------------------------------------------------------------------
-
-static egl_connection_t gEGLImpl[IMPL_NUM_IMPLEMENTATIONS];
-static egl_display_t gDisplay[NUM_DISPLAYS];
-static pthread_mutex_t gThreadLocalStorageKeyMutex = PTHREAD_MUTEX_INITIALIZER;
-static pthread_key_t gEGLThreadLocalStorageKey = -1;
-
-// ----------------------------------------------------------------------------
-
-EGLAPI gl_hooks_t gHooks[2][IMPL_NUM_IMPLEMENTATIONS];
-EGLAPI gl_hooks_t gHooksNoContext;
-EGLAPI pthread_key_t gGLWrapperKey = -1;
-
#if EGL_TRACE
EGLAPI pthread_key_t gGLTraceKey = -1;
// ----------------------------------------------------------------------------
-static int gEGLTraceLevel, gEGLDebugLevel;
-static int gEGLApplicationTraceLevel;
-extern EGLAPI gl_hooks_t gHooksTrace, gHooksDebug;
+int gEGLDebugLevel;
+
+static int sEGLTraceLevel;
+static int sEGLApplicationTraceLevel;
+
+extern gl_hooks_t gHooksTrace;
+extern gl_hooks_t gHooksDebug;
static inline void setGlTraceThreadSpecific(gl_hooks_t const *value) {
pthread_setspecific(gGLTraceKey, value);
@@ -305,12 +75,12 @@
return static_cast<gl_hooks_t*>(pthread_getspecific(gGLTraceKey));
}
-static void initEglTraceLevel() {
+void initEglTraceLevel() {
char value[PROPERTY_VALUE_MAX];
property_get("debug.egl.trace", value, "0");
int propertyLevel = atoi(value);
- int applicationLevel = gEGLApplicationTraceLevel;
- gEGLTraceLevel = propertyLevel > applicationLevel ? propertyLevel : applicationLevel;
+ int applicationLevel = sEGLApplicationTraceLevel;
+ sEGLTraceLevel = propertyLevel > applicationLevel ? propertyLevel : applicationLevel;
property_get("debug.egl.debug_proc", value, "");
long pid = getpid();
@@ -323,12 +93,12 @@
if (fgets(cmdline, sizeof(cmdline) - 1, file))
{
if (!strcmp(value, cmdline))
- gEGLDebugLevel = 1;
+ sEGLTraceLevel = 1;
}
fclose(file);
}
- if (gEGLDebugLevel > 0)
+ if (sEGLTraceLevel > 0)
{
property_get("debug.egl.debug_port", value, "5039");
const unsigned short port = (unsigned short)atoi(value);
@@ -341,11 +111,11 @@
}
}
-static void setGLHooksThreadSpecific(gl_hooks_t const *value) {
- if (gEGLTraceLevel > 0) {
+void setGLHooksThreadSpecific(gl_hooks_t const *value) {
+ if (sEGLTraceLevel > 0) {
setGlTraceThreadSpecific(value);
setGlThreadSpecific(&gHooksTrace);
- } else if (gEGLDebugLevel > 0 && value != &gHooksNoContext) {
+ } else if (sEGLTraceLevel > 0 && value != &gHooksNoContext) {
setGlTraceThreadSpecific(value);
setGlThreadSpecific(&gHooksDebug);
} else {
@@ -359,186 +129,21 @@
*/
extern "C"
void setGLTraceLevel(int level) {
- gEGLApplicationTraceLevel = level;
+ sEGLApplicationTraceLevel = level;
}
#else
-static inline void setGLHooksThreadSpecific(gl_hooks_t const *value) {
+void setGLHooksThreadSpecific(gl_hooks_t const *value) {
setGlThreadSpecific(value);
}
#endif
-// ----------------------------------------------------------------------------
-
-static __attribute__((noinline))
-const char *egl_strerror(EGLint err)
-{
- switch (err){
- case EGL_SUCCESS: return "EGL_SUCCESS";
- case EGL_NOT_INITIALIZED: return "EGL_NOT_INITIALIZED";
- case EGL_BAD_ACCESS: return "EGL_BAD_ACCESS";
- case EGL_BAD_ALLOC: return "EGL_BAD_ALLOC";
- case EGL_BAD_ATTRIBUTE: return "EGL_BAD_ATTRIBUTE";
- case EGL_BAD_CONFIG: return "EGL_BAD_CONFIG";
- case EGL_BAD_CONTEXT: return "EGL_BAD_CONTEXT";
- case EGL_BAD_CURRENT_SURFACE: return "EGL_BAD_CURRENT_SURFACE";
- case EGL_BAD_DISPLAY: return "EGL_BAD_DISPLAY";
- case EGL_BAD_MATCH: return "EGL_BAD_MATCH";
- case EGL_BAD_NATIVE_PIXMAP: return "EGL_BAD_NATIVE_PIXMAP";
- case EGL_BAD_NATIVE_WINDOW: return "EGL_BAD_NATIVE_WINDOW";
- case EGL_BAD_PARAMETER: return "EGL_BAD_PARAMETER";
- case EGL_BAD_SURFACE: return "EGL_BAD_SURFACE";
- case EGL_CONTEXT_LOST: return "EGL_CONTEXT_LOST";
- default: return "UNKNOWN";
- }
-}
-
-static __attribute__((noinline))
-void clearTLS() {
- if (gEGLThreadLocalStorageKey != -1) {
- tls_t* tls = (tls_t*)pthread_getspecific(gEGLThreadLocalStorageKey);
- if (tls) {
- delete tls;
- pthread_setspecific(gEGLThreadLocalStorageKey, 0);
- }
- }
-}
-
-static tls_t* getTLS()
-{
- tls_t* tls = (tls_t*)pthread_getspecific(gEGLThreadLocalStorageKey);
- if (tls == 0) {
- tls = new tls_t;
- pthread_setspecific(gEGLThreadLocalStorageKey, tls);
- }
- return tls;
-}
-
-static inline void clearError() {
- // This must clear the error from all the underlying EGL implementations as
- // well as the EGL wrapper layer.
- eglGetError();
-}
-
-template<typename T>
-static __attribute__((noinline))
-T setErrorEtc(const char* caller, int line, EGLint error, T returnValue) {
- if (gEGLThreadLocalStorageKey == -1) {
- pthread_mutex_lock(&gThreadLocalStorageKeyMutex);
- if (gEGLThreadLocalStorageKey == -1)
- pthread_key_create(&gEGLThreadLocalStorageKey, NULL);
- pthread_mutex_unlock(&gThreadLocalStorageKeyMutex);
- }
- tls_t* tls = getTLS();
- if (tls->error != error) {
- LOGE("%s:%d error %x (%s)", caller, line, error, egl_strerror(error));
- tls->error = error;
- }
- return returnValue;
-}
-
-static __attribute__((noinline))
-GLint getError() {
- if (gEGLThreadLocalStorageKey == -1)
- return EGL_SUCCESS;
- tls_t* tls = (tls_t*)pthread_getspecific(gEGLThreadLocalStorageKey);
- if (!tls) return EGL_SUCCESS;
- GLint error = tls->error;
- tls->error = EGL_SUCCESS;
- return error;
-}
-
-static __attribute__((noinline))
-void setContext(EGLContext ctx) {
- if (gEGLThreadLocalStorageKey == -1) {
- pthread_mutex_lock(&gThreadLocalStorageKeyMutex);
- if (gEGLThreadLocalStorageKey == -1)
- pthread_key_create(&gEGLThreadLocalStorageKey, NULL);
- pthread_mutex_unlock(&gThreadLocalStorageKeyMutex);
- }
- tls_t* tls = getTLS();
- tls->ctx = ctx;
-}
-
-static __attribute__((noinline))
-EGLContext getContext() {
- if (gEGLThreadLocalStorageKey == -1)
- return EGL_NO_CONTEXT;
- tls_t* tls = (tls_t*)pthread_getspecific(gEGLThreadLocalStorageKey);
- if (!tls) return EGL_NO_CONTEXT;
- return tls->ctx;
-}
-
/*****************************************************************************/
-template<typename T>
-static __attribute__((noinline))
-int binarySearch(
- T const sortedArray[], int first, int last, T key)
-{
- while (first <= last) {
- int mid = (first + last) / 2;
- if (sortedArray[mid] < key) {
- first = mid + 1;
- } else if (key < sortedArray[mid]) {
- last = mid - 1;
- } else {
- return mid;
- }
- }
- return -1;
-}
-
-static int cmp_configs(const void* a, const void *b)
-{
- const egl_config_t& c0 = *(egl_config_t const *)a;
- const egl_config_t& c1 = *(egl_config_t const *)b;
- return c0<c1 ? -1 : (c1<c0 ? 1 : 0);
-}
-
-struct extention_map_t {
- const char* name;
- __eglMustCastToProperFunctionPointerType address;
-};
-
-static const extention_map_t gExtentionMap[] = {
- { "eglLockSurfaceKHR",
- (__eglMustCastToProperFunctionPointerType)&eglLockSurfaceKHR },
- { "eglUnlockSurfaceKHR",
- (__eglMustCastToProperFunctionPointerType)&eglUnlockSurfaceKHR },
- { "eglCreateImageKHR",
- (__eglMustCastToProperFunctionPointerType)&eglCreateImageKHR },
- { "eglDestroyImageKHR",
- (__eglMustCastToProperFunctionPointerType)&eglDestroyImageKHR },
- { "eglSetSwapRectangleANDROID",
- (__eglMustCastToProperFunctionPointerType)&eglSetSwapRectangleANDROID },
-};
-
-extern const __eglMustCastToProperFunctionPointerType gExtensionForwarders[MAX_NUMBER_OF_GL_EXTENSIONS];
-
-// accesses protected by gInitDriverMutex
-static DefaultKeyedVector<String8, __eglMustCastToProperFunctionPointerType> gGLExtentionMap;
-static int gGLExtentionSlot = 0;
-
-static void(*findProcAddress(const char* name,
- const extention_map_t* map, size_t n))()
-{
- for (uint32_t i=0 ; i<n ; i++) {
- if (!strcmp(name, map[i].name)) {
- return map[i].address;
- }
- }
- return NULL;
-}
-
-// ----------------------------------------------------------------------------
-
static int gl_no_context() {
- tls_t* tls = getTLS();
- if (tls->logCallWithNoContext == EGL_TRUE) {
- tls->logCallWithNoContext = EGL_FALSE;
+ if (egl_tls_t::logNoContextCall()) {
LOGE("call to OpenGL ES API with no current context "
"(logged once per thread)");
}
@@ -566,55 +171,23 @@
static pthread_once_t once_control = PTHREAD_ONCE_INIT;
static int sEarlyInitState = pthread_once(&once_control, &early_egl_init);
+// ----------------------------------------------------------------------------
-static inline
-egl_display_t* get_display(EGLDisplay dpy)
-{
- uintptr_t index = uintptr_t(dpy)-1U;
- return (index >= NUM_DISPLAYS) ? NULL : &gDisplay[index];
-}
-
-template<typename NATIVE, typename EGL>
-static inline NATIVE* egl_to_native_cast(EGL arg) {
- return reinterpret_cast<NATIVE*>(arg);
-}
-
-static inline
-egl_surface_t* get_surface(EGLSurface surface) {
- return egl_to_native_cast<egl_surface_t>(surface);
-}
-
-static inline
-egl_context_t* get_context(EGLContext context) {
- return egl_to_native_cast<egl_context_t>(context);
-}
-
-static inline
-egl_image_t* get_image(EGLImageKHR image) {
- return egl_to_native_cast<egl_image_t>(image);
-}
-
-static inline
-egl_sync_t* get_sync(EGLSyncKHR sync) {
- return egl_to_native_cast<egl_sync_t>(sync);
-}
-
-static inline
-egl_display_t* validate_display(EGLDisplay dpy)
-{
+egl_display_t* validate_display(EGLDisplay dpy) {
egl_display_t * const dp = get_display(dpy);
- if (!dp) return setError(EGL_BAD_DISPLAY, (egl_display_t*)NULL);
- if (!dp->isReady()) return setError(EGL_NOT_INITIALIZED, (egl_display_t*)NULL);
+ if (!dp)
+ return setError(EGL_BAD_DISPLAY, (egl_display_t*)NULL);
+ if (!dp->isReady())
+ return setError(EGL_NOT_INITIALIZED, (egl_display_t*)NULL);
return dp;
}
-static egl_connection_t* validate_display_config(
- EGLDisplay dpy, EGLConfig config,
- egl_display_t const*& dp)
-{
+egl_connection_t* validate_display_config(EGLDisplay dpy, EGLConfig config,
+ egl_display_t const*& dp) {
dp = validate_display(dpy);
- if (!dp) return (egl_connection_t*) NULL;
+ if (!dp)
+ return (egl_connection_t*) NULL;
if (intptr_t(config) >= dp->numTotalConfigs) {
return setError(EGL_BAD_CONFIG, (egl_connection_t*)NULL);
@@ -626,41 +199,26 @@
return cnx;
}
-static EGLBoolean validate_display_context(EGLDisplay dpy, EGLContext ctx)
-{
- egl_display_t const * const dp = validate_display(dpy);
- if (!dp) return EGL_FALSE;
- if (!dp->isAlive())
- return setError(EGL_BAD_DISPLAY, EGL_FALSE);
- if (!get_context(ctx)->isAlive())
- return setError(EGL_BAD_CONTEXT, EGL_FALSE);
- return EGL_TRUE;
-}
-
-static EGLBoolean validate_display_surface(EGLDisplay dpy, EGLSurface surface)
-{
- egl_display_t const * const dp = validate_display(dpy);
- if (!dp) return EGL_FALSE;
- if (!dp->isAlive())
- return setError(EGL_BAD_DISPLAY, EGL_FALSE);
- if (!get_surface(surface)->isAlive())
- return setError(EGL_BAD_SURFACE, EGL_FALSE);
- return EGL_TRUE;
-}
+// ----------------------------------------------------------------------------
EGLImageKHR egl_get_image_for_current_context(EGLImageKHR image)
{
ImageRef _i(image);
- if (!_i.get()) return EGL_NO_IMAGE_KHR;
-
- EGLContext context = getContext();
+ if (!_i.get())
+ return EGL_NO_IMAGE_KHR;
+
+ EGLContext context = egl_tls_t::getContext();
if (context == EGL_NO_CONTEXT || image == EGL_NO_IMAGE_KHR)
return EGL_NO_IMAGE_KHR;
-
+
egl_context_t const * const c = get_context(context);
- if (!c->isAlive())
+ if (c == NULL) // this should never happen
return EGL_NO_IMAGE_KHR;
+ // here we don't validate the context because if it's been marked for
+ // termination, this call should still succeed since it's internal to
+ // EGL.
+
egl_image_t const * const i = get_image(image);
return i->images[c->impl];
}
@@ -671,10 +229,7 @@
// d->disp[]
// egl_init_drivers_locked()
//
-static pthread_mutex_t gInitDriverMutex = PTHREAD_MUTEX_INITIALIZER;
-
-EGLBoolean egl_init_drivers_locked()
-{
+static EGLBoolean egl_init_drivers_locked() {
if (sEarlyInitState) {
// initialized by static ctor. should be set here.
return EGL_FALSE;
@@ -682,28 +237,15 @@
// get our driver loader
Loader& loader(Loader::getInstance());
-
- // dynamically load all our EGL implementations for all displays
- // and retrieve the corresponding EGLDisplay
- // if that fails, don't use this driver.
- // TODO: currently we only deal with EGL_DEFAULT_DISPLAY
+
+ // dynamically load all our EGL implementations
egl_connection_t* cnx;
- egl_display_t* d = &gDisplay[0];
cnx = &gEGLImpl[IMPL_SOFTWARE];
if (cnx->dso == 0) {
cnx->hooks[GLESv1_INDEX] = &gHooks[GLESv1_INDEX][IMPL_SOFTWARE];
cnx->hooks[GLESv2_INDEX] = &gHooks[GLESv2_INDEX][IMPL_SOFTWARE];
cnx->dso = loader.open(EGL_DEFAULT_DISPLAY, 0, cnx);
- if (cnx->dso) {
- EGLDisplay dpy = cnx->egl.eglGetDisplay(EGL_DEFAULT_DISPLAY);
- LOGE_IF(dpy==EGL_NO_DISPLAY, "No EGLDisplay for software EGL!");
- d->disp[IMPL_SOFTWARE].dpy = dpy;
- if (dpy == EGL_NO_DISPLAY) {
- loader.close(cnx->dso);
- cnx->dso = NULL;
- }
- }
}
cnx = &gEGLImpl[IMPL_HARDWARE];
@@ -714,15 +256,6 @@
cnx->hooks[GLESv1_INDEX] = &gHooks[GLESv1_INDEX][IMPL_HARDWARE];
cnx->hooks[GLESv2_INDEX] = &gHooks[GLESv2_INDEX][IMPL_HARDWARE];
cnx->dso = loader.open(EGL_DEFAULT_DISPLAY, 1, cnx);
- if (cnx->dso) {
- EGLDisplay dpy = cnx->egl.eglGetDisplay(EGL_DEFAULT_DISPLAY);
- LOGE_IF(dpy==EGL_NO_DISPLAY, "No EGLDisplay for hardware EGL!");
- d->disp[IMPL_HARDWARE].dpy = dpy;
- if (dpy == EGL_NO_DISPLAY) {
- loader.close(cnx->dso);
- cnx->dso = NULL;
- }
- }
} else {
LOGD("3D hardware acceleration is disabled");
}
@@ -735,12 +268,13 @@
return EGL_TRUE;
}
-EGLBoolean egl_init_drivers()
-{
+static pthread_mutex_t sInitDriverMutex = PTHREAD_MUTEX_INITIALIZER;
+
+EGLBoolean egl_init_drivers() {
EGLBoolean res;
- pthread_mutex_lock(&gInitDriverMutex);
+ pthread_mutex_lock(&sInitDriverMutex);
res = egl_init_drivers_locked();
- pthread_mutex_unlock(&gInitDriverMutex);
+ pthread_mutex_unlock(&sInitDriverMutex);
return res;
}
@@ -748,1486 +282,3 @@
}; // namespace android
// ----------------------------------------------------------------------------
-using namespace android;
-
-EGLDisplay eglGetDisplay(NativeDisplayType display)
-{
- clearError();
-
- uint32_t index = uint32_t(display);
- if (index >= NUM_DISPLAYS) {
- return setError(EGL_BAD_PARAMETER, EGL_NO_DISPLAY);
- }
-
- if (egl_init_drivers() == EGL_FALSE) {
- return setError(EGL_BAD_PARAMETER, EGL_NO_DISPLAY);
- }
-
- EGLDisplay dpy = EGLDisplay(uintptr_t(display) + 1LU);
- return dpy;
-}
-
-// ----------------------------------------------------------------------------
-// Initialization
-// ----------------------------------------------------------------------------
-
-EGLBoolean eglInitialize(EGLDisplay dpy, EGLint *major, EGLint *minor)
-{
- clearError();
-
- egl_display_t * const dp = get_display(dpy);
- if (!dp) return setError(EGL_BAD_DISPLAY, EGL_FALSE);
-
- Mutex::Autolock _l(dp->lock);
-
- if (dp->refs > 0) {
- if (major != NULL) *major = VERSION_MAJOR;
- if (minor != NULL) *minor = VERSION_MINOR;
- dp->refs++;
- return EGL_TRUE;
- }
-
-#if EGL_TRACE
-
- // Called both at early_init time and at this time. (Early_init is pre-zygote, so
- // the information from that call may be stale.)
- initEglTraceLevel();
-
-#endif
-
- setGLHooksThreadSpecific(&gHooksNoContext);
-
- // initialize each EGL and
- // build our own extension string first, based on the extension we know
- // and the extension supported by our client implementation
- for (int i=0 ; i<IMPL_NUM_IMPLEMENTATIONS ; i++) {
- egl_connection_t* const cnx = &gEGLImpl[i];
- cnx->major = -1;
- cnx->minor = -1;
- if (!cnx->dso)
- continue;
-
-#if defined(ADRENO130)
-#warning "Adreno-130 eglInitialize() workaround"
- /*
- * The ADRENO 130 driver returns a different EGLDisplay each time
- * eglGetDisplay() is called, but also makes the EGLDisplay invalid
- * after eglTerminate() has been called, so that eglInitialize()
- * cannot be called again. Therefore, we need to make sure to call
- * eglGetDisplay() before calling eglInitialize();
- */
- if (i == IMPL_HARDWARE) {
- dp->disp[i].dpy =
- cnx->egl.eglGetDisplay(EGL_DEFAULT_DISPLAY);
- }
-#endif
-
-
- EGLDisplay idpy = dp->disp[i].dpy;
- if (cnx->egl.eglInitialize(idpy, &cnx->major, &cnx->minor)) {
- //LOGD("initialized %d dpy=%p, ver=%d.%d, cnx=%p",
- // i, idpy, cnx->major, cnx->minor, cnx);
-
- // display is now initialized
- dp->disp[i].state = egl_display_t::INITIALIZED;
-
- // get the query-strings for this display for each implementation
- dp->disp[i].queryString.vendor =
- cnx->egl.eglQueryString(idpy, EGL_VENDOR);
- dp->disp[i].queryString.version =
- cnx->egl.eglQueryString(idpy, EGL_VERSION);
- dp->disp[i].queryString.extensions =
- cnx->egl.eglQueryString(idpy, EGL_EXTENSIONS);
- dp->disp[i].queryString.clientApi =
- cnx->egl.eglQueryString(idpy, EGL_CLIENT_APIS);
-
- } else {
- LOGW("%d: eglInitialize(%p) failed (%s)", i, idpy,
- egl_strerror(cnx->egl.eglGetError()));
- }
- }
-
- EGLBoolean res = EGL_FALSE;
- for (int i=0 ; i<IMPL_NUM_IMPLEMENTATIONS ; i++) {
- egl_connection_t* const cnx = &gEGLImpl[i];
- if (cnx->dso && cnx->major>=0 && cnx->minor>=0) {
- EGLint n;
- if (cnx->egl.eglGetConfigs(dp->disp[i].dpy, 0, 0, &n)) {
- dp->disp[i].config = (EGLConfig*)malloc(sizeof(EGLConfig)*n);
- if (dp->disp[i].config) {
- if (cnx->egl.eglGetConfigs(
- dp->disp[i].dpy, dp->disp[i].config, n,
- &dp->disp[i].numConfigs))
- {
- dp->numTotalConfigs += n;
- res = EGL_TRUE;
- }
- }
- }
- }
- }
-
- if (res == EGL_TRUE) {
- dp->configs = new egl_config_t[ dp->numTotalConfigs ];
- for (int i=0, k=0 ; i<IMPL_NUM_IMPLEMENTATIONS ; i++) {
- egl_connection_t* const cnx = &gEGLImpl[i];
- if (cnx->dso && cnx->major>=0 && cnx->minor>=0) {
- for (int j=0 ; j<dp->disp[i].numConfigs ; j++) {
- dp->configs[k].impl = i;
- dp->configs[k].config = dp->disp[i].config[j];
- dp->configs[k].configId = k + 1; // CONFIG_ID start at 1
- // store the implementation's CONFIG_ID
- cnx->egl.eglGetConfigAttrib(
- dp->disp[i].dpy,
- dp->disp[i].config[j],
- EGL_CONFIG_ID,
- &dp->configs[k].implConfigId);
- k++;
- }
- }
- }
-
- // sort our configurations so we can do binary-searches
- qsort( dp->configs,
- dp->numTotalConfigs,
- sizeof(egl_config_t), cmp_configs);
-
- dp->refs++;
- if (major != NULL) *major = VERSION_MAJOR;
- if (minor != NULL) *minor = VERSION_MINOR;
- return EGL_TRUE;
- }
- return setError(EGL_NOT_INITIALIZED, EGL_FALSE);
-}
-
-EGLBoolean eglTerminate(EGLDisplay dpy)
-{
- // NOTE: don't unload the drivers b/c some APIs can be called
- // after eglTerminate() has been called. eglTerminate() only
- // terminates an EGLDisplay, not a EGL itself.
-
- clearError();
-
- egl_display_t* const dp = get_display(dpy);
- if (!dp) return setError(EGL_BAD_DISPLAY, EGL_FALSE);
-
- Mutex::Autolock _l(dp->lock);
-
- if (dp->refs == 0) {
- return setError(EGL_NOT_INITIALIZED, EGL_FALSE);
- }
-
- // this is specific to Android, display termination is ref-counted.
- if (dp->refs > 1) {
- dp->refs--;
- return EGL_TRUE;
- }
-
- EGLBoolean res = EGL_FALSE;
- for (int i=0 ; i<IMPL_NUM_IMPLEMENTATIONS ; i++) {
- egl_connection_t* const cnx = &gEGLImpl[i];
- if (cnx->dso && dp->disp[i].state == egl_display_t::INITIALIZED) {
- if (cnx->egl.eglTerminate(dp->disp[i].dpy) == EGL_FALSE) {
- LOGW("%d: eglTerminate(%p) failed (%s)", i, dp->disp[i].dpy,
- egl_strerror(cnx->egl.eglGetError()));
- }
- // REVISIT: it's unclear what to do if eglTerminate() fails
- free(dp->disp[i].config);
-
- dp->disp[i].numConfigs = 0;
- dp->disp[i].config = 0;
- dp->disp[i].state = egl_display_t::TERMINATED;
-
- res = EGL_TRUE;
- }
- }
-
- // TODO: all egl_object_t should be marked for termination
-
- dp->refs--;
- dp->numTotalConfigs = 0;
- delete [] dp->configs;
-
- return res;
-}
-
-// ----------------------------------------------------------------------------
-// configuration
-// ----------------------------------------------------------------------------
-
-EGLBoolean eglGetConfigs( EGLDisplay dpy,
- EGLConfig *configs,
- EGLint config_size, EGLint *num_config)
-{
- clearError();
-
- egl_display_t const * const dp = validate_display(dpy);
- if (!dp) return EGL_FALSE;
-
- GLint numConfigs = dp->numTotalConfigs;
- if (!configs) {
- *num_config = numConfigs;
- return EGL_TRUE;
- }
-
- GLint n = 0;
- for (intptr_t i=0 ; i<dp->numTotalConfigs && config_size ; i++) {
- *configs++ = EGLConfig(i);
- config_size--;
- n++;
- }
-
- *num_config = n;
- return EGL_TRUE;
-}
-
-EGLBoolean eglChooseConfig( EGLDisplay dpy, const EGLint *attrib_list,
- EGLConfig *configs, EGLint config_size,
- EGLint *num_config)
-{
- clearError();
-
- egl_display_t const * const dp = validate_display(dpy);
- if (!dp) return EGL_FALSE;
-
- if (num_config==0) {
- return setError(EGL_BAD_PARAMETER, EGL_FALSE);
- }
-
- EGLint n;
- EGLBoolean res = EGL_FALSE;
- *num_config = 0;
-
-
- // It is unfortunate, but we need to remap the EGL_CONFIG_IDs,
- // to do this, we have to go through the attrib_list array once
- // to figure out both its size and if it contains an EGL_CONFIG_ID
- // key. If so, the full array is copied and patched.
- // NOTE: we assume that there can be only one occurrence
- // of EGL_CONFIG_ID.
-
- EGLint patch_index = -1;
- GLint attr;
- size_t size = 0;
- if (attrib_list) {
- while ((attr=attrib_list[size]) != EGL_NONE) {
- if (attr == EGL_CONFIG_ID)
- patch_index = size;
- size += 2;
- }
- }
- if (patch_index >= 0) {
- size += 2; // we need copy the sentinel as well
- EGLint* new_list = (EGLint*)malloc(size*sizeof(EGLint));
- if (new_list == 0)
- return setError(EGL_BAD_ALLOC, EGL_FALSE);
- memcpy(new_list, attrib_list, size*sizeof(EGLint));
-
- // patch the requested EGL_CONFIG_ID
- bool found = false;
- EGLConfig ourConfig(0);
- EGLint& configId(new_list[patch_index+1]);
- for (intptr_t i=0 ; i<dp->numTotalConfigs ; i++) {
- if (dp->configs[i].configId == configId) {
- ourConfig = EGLConfig(i);
- configId = dp->configs[i].implConfigId;
- found = true;
- break;
- }
- }
-
- egl_connection_t* const cnx = &gEGLImpl[dp->configs[intptr_t(ourConfig)].impl];
- if (found && cnx->dso) {
- // and switch to the new list
- attrib_list = const_cast<const EGLint *>(new_list);
-
- // At this point, the only configuration that can match is
- // dp->configs[i][index], however, we don't know if it would be
- // rejected because of the other attributes, so we do have to call
- // cnx->egl.eglChooseConfig() -- but we don't have to loop
- // through all the EGLimpl[].
- // We also know we can only get a single config back, and we know
- // which one.
-
- res = cnx->egl.eglChooseConfig(
- dp->disp[ dp->configs[intptr_t(ourConfig)].impl ].dpy,
- attrib_list, configs, config_size, &n);
- if (res && n>0) {
- // n has to be 0 or 1, by construction, and we already know
- // which config it will return (since there can be only one).
- if (configs) {
- configs[0] = ourConfig;
- }
- *num_config = 1;
- }
- }
-
- free(const_cast<EGLint *>(attrib_list));
- return res;
- }
-
-
- for (int i=0 ; i<IMPL_NUM_IMPLEMENTATIONS ; i++) {
- egl_connection_t* const cnx = &gEGLImpl[i];
- if (cnx->dso) {
- if (cnx->egl.eglChooseConfig(
- dp->disp[i].dpy, attrib_list, configs, config_size, &n)) {
- if (configs) {
- // now we need to convert these client EGLConfig to our
- // internal EGLConfig format.
- // This is done in O(n Log(n)) time.
- for (int j=0 ; j<n ; j++) {
- egl_config_t key(i, configs[j]);
- intptr_t index = binarySearch<egl_config_t>(
- dp->configs, 0, dp->numTotalConfigs, key);
- if (index >= 0) {
- configs[j] = EGLConfig(index);
- } else {
- return setError(EGL_BAD_CONFIG, EGL_FALSE);
- }
- }
- configs += n;
- config_size -= n;
- }
- *num_config += n;
- res = EGL_TRUE;
- }
- }
- }
- return res;
-}
-
-EGLBoolean eglGetConfigAttrib(EGLDisplay dpy, EGLConfig config,
- EGLint attribute, EGLint *value)
-{
- clearError();
-
- egl_display_t const* dp = 0;
- egl_connection_t* cnx = validate_display_config(dpy, config, dp);
- if (!cnx) return EGL_FALSE;
-
- if (attribute == EGL_CONFIG_ID) {
- *value = dp->configs[intptr_t(config)].configId;
- return EGL_TRUE;
- }
- return cnx->egl.eglGetConfigAttrib(
- dp->disp[ dp->configs[intptr_t(config)].impl ].dpy,
- dp->configs[intptr_t(config)].config, attribute, value);
-}
-
-// ----------------------------------------------------------------------------
-// surfaces
-// ----------------------------------------------------------------------------
-
-EGLSurface eglCreateWindowSurface( EGLDisplay dpy, EGLConfig config,
- NativeWindowType window,
- const EGLint *attrib_list)
-{
- clearError();
-
- egl_display_t const* dp = 0;
- egl_connection_t* cnx = validate_display_config(dpy, config, dp);
- if (cnx) {
- EGLDisplay iDpy = dp->disp[ dp->configs[intptr_t(config)].impl ].dpy;
- EGLConfig iConfig = dp->configs[intptr_t(config)].config;
- EGLint format;
-
- // set the native window's buffers format to match this config
- if (cnx->egl.eglGetConfigAttrib(iDpy,
- iConfig, EGL_NATIVE_VISUAL_ID, &format)) {
- if (format != 0) {
- native_window_set_buffers_geometry(window, 0, 0, format);
- }
- }
-
- EGLSurface surface = cnx->egl.eglCreateWindowSurface(
- iDpy, iConfig, window, attrib_list);
- if (surface != EGL_NO_SURFACE) {
- egl_surface_t* s = new egl_surface_t(dpy, config, window, surface,
- dp->configs[intptr_t(config)].impl, cnx);
- return s;
- }
- }
- return EGL_NO_SURFACE;
-}
-
-EGLSurface eglCreatePixmapSurface( EGLDisplay dpy, EGLConfig config,
- NativePixmapType pixmap,
- const EGLint *attrib_list)
-{
- clearError();
-
- egl_display_t const* dp = 0;
- egl_connection_t* cnx = validate_display_config(dpy, config, dp);
- if (cnx) {
- EGLSurface surface = cnx->egl.eglCreatePixmapSurface(
- dp->disp[ dp->configs[intptr_t(config)].impl ].dpy,
- dp->configs[intptr_t(config)].config, pixmap, attrib_list);
- if (surface != EGL_NO_SURFACE) {
- egl_surface_t* s = new egl_surface_t(dpy, config, NULL, surface,
- dp->configs[intptr_t(config)].impl, cnx);
- return s;
- }
- }
- return EGL_NO_SURFACE;
-}
-
-EGLSurface eglCreatePbufferSurface( EGLDisplay dpy, EGLConfig config,
- const EGLint *attrib_list)
-{
- clearError();
-
- egl_display_t const* dp = 0;
- egl_connection_t* cnx = validate_display_config(dpy, config, dp);
- if (cnx) {
- EGLSurface surface = cnx->egl.eglCreatePbufferSurface(
- dp->disp[ dp->configs[intptr_t(config)].impl ].dpy,
- dp->configs[intptr_t(config)].config, attrib_list);
- if (surface != EGL_NO_SURFACE) {
- egl_surface_t* s = new egl_surface_t(dpy, config, NULL, surface,
- dp->configs[intptr_t(config)].impl, cnx);
- return s;
- }
- }
- return EGL_NO_SURFACE;
-}
-
-EGLBoolean eglDestroySurface(EGLDisplay dpy, EGLSurface surface)
-{
- clearError();
-
- egl_display_t const * const dp = validate_display(dpy);
- if (!dp) return EGL_FALSE;
-
- SurfaceRef _s(surface);
- if (!_s.get()) return setError(EGL_BAD_SURFACE, EGL_FALSE);
-
- if (!validate_display_surface(dpy, surface))
- return EGL_FALSE;
-
- egl_surface_t * const s = get_surface(surface);
- EGLBoolean result = s->cnx->egl.eglDestroySurface(
- dp->disp[s->impl].dpy, s->surface);
- if (result == EGL_TRUE) {
- if (s->win != NULL) {
- native_window_set_buffers_geometry(s->win.get(), 0, 0, 0);
- }
- _s.terminate();
- }
- return result;
-}
-
-EGLBoolean eglQuerySurface( EGLDisplay dpy, EGLSurface surface,
- EGLint attribute, EGLint *value)
-{
- clearError();
-
- egl_display_t const * const dp = validate_display(dpy);
- if (!dp) return EGL_FALSE;
-
- SurfaceRef _s(surface);
- if (!_s.get()) return setError(EGL_BAD_SURFACE, EGL_FALSE);
-
- if (!validate_display_surface(dpy, surface))
- return EGL_FALSE;
- egl_surface_t const * const s = get_surface(surface);
-
- EGLBoolean result(EGL_TRUE);
- if (attribute == EGL_CONFIG_ID) {
- // We need to remap EGL_CONFIG_IDs
- *value = dp->configs[intptr_t(s->config)].configId;
- } else {
- result = s->cnx->egl.eglQuerySurface(
- dp->disp[s->impl].dpy, s->surface, attribute, value);
- }
-
- return result;
-}
-
-// ----------------------------------------------------------------------------
-// Contexts
-// ----------------------------------------------------------------------------
-
-EGLContext eglCreateContext(EGLDisplay dpy, EGLConfig config,
- EGLContext share_list, const EGLint *attrib_list)
-{
- clearError();
-
- egl_display_t const* dp = 0;
- egl_connection_t* cnx = validate_display_config(dpy, config, dp);
- if (cnx) {
- if (share_list != EGL_NO_CONTEXT) {
- egl_context_t* const c = get_context(share_list);
- share_list = c->context;
- }
- EGLContext context = cnx->egl.eglCreateContext(
- dp->disp[ dp->configs[intptr_t(config)].impl ].dpy,
- dp->configs[intptr_t(config)].config,
- share_list, attrib_list);
- if (context != EGL_NO_CONTEXT) {
- // figure out if it's a GLESv1 or GLESv2
- int version = 0;
- if (attrib_list) {
- while (*attrib_list != EGL_NONE) {
- GLint attr = *attrib_list++;
- GLint value = *attrib_list++;
- if (attr == EGL_CONTEXT_CLIENT_VERSION) {
- if (value == 1) {
- version = GLESv1_INDEX;
- } else if (value == 2) {
- version = GLESv2_INDEX;
- }
- }
- };
- }
- egl_context_t* c = new egl_context_t(dpy, context, config,
- dp->configs[intptr_t(config)].impl, cnx, version);
- return c;
- }
- }
- return EGL_NO_CONTEXT;
-}
-
-EGLBoolean eglDestroyContext(EGLDisplay dpy, EGLContext ctx)
-{
- clearError();
-
- egl_display_t const * const dp = validate_display(dpy);
- if (!dp) return EGL_FALSE;
-
- ContextRef _c(ctx);
- if (!_c.get()) return setError(EGL_BAD_CONTEXT, EGL_FALSE);
-
- if (!validate_display_context(dpy, ctx))
- return EGL_FALSE;
- egl_context_t * const c = get_context(ctx);
- EGLBoolean result = c->cnx->egl.eglDestroyContext(
- dp->disp[c->impl].dpy, c->context);
- if (result == EGL_TRUE) {
- _c.terminate();
- }
- 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)
-{
- clearError();
-
- egl_display_t const * const dp = get_display(dpy);
- if (!dp) return setError(EGL_BAD_DISPLAY, EGL_FALSE);
-
- /* If ctx is not EGL_NO_CONTEXT, read is not EGL_NO_SURFACE, or draw is not
- EGL_NO_SURFACE, then an EGL_NOT_INITIALIZED error is generated if dpy is
- a valid but uninitialized display. */
- if ( (ctx != EGL_NO_CONTEXT) || (read != EGL_NO_SURFACE) ||
- (draw != EGL_NO_SURFACE) ) {
- if (!dp->isReady()) return setError(EGL_NOT_INITIALIZED, EGL_FALSE);
- }
-
- // get a reference to the object passed in
- ContextRef _c(ctx);
- SurfaceRef _d(draw);
- SurfaceRef _r(read);
-
- // validate the context (if not EGL_NO_CONTEXT)
- if ((ctx != EGL_NO_CONTEXT) && (!validate_display_context(dpy, ctx))) {
- // EGL_NO_CONTEXT is valid
- return EGL_FALSE;
- }
-
- // these are the underlying implementation's object
- EGLContext impl_ctx = EGL_NO_CONTEXT;
- EGLSurface impl_draw = EGL_NO_SURFACE;
- EGLSurface impl_read = EGL_NO_SURFACE;
-
- // these are our objects structs passed in
- egl_context_t * c = NULL;
- egl_surface_t const * d = NULL;
- egl_surface_t const * r = NULL;
-
- // these are the current objects structs
- egl_context_t * cur_c = get_context(getContext());
-
- if (ctx != EGL_NO_CONTEXT) {
- c = get_context(ctx);
- impl_ctx = c->context;
- } else {
- // no context given, use the implementation of the current context
- if (cur_c == NULL) {
- // no current context
- if (draw != EGL_NO_SURFACE || read != EGL_NO_SURFACE) {
- // calling eglMakeCurrent( ..., !=0, !=0, EGL_NO_CONTEXT);
- return setError(EGL_BAD_MATCH, EGL_FALSE);
- }
- // not an error, there is just no current context.
- return EGL_TRUE;
- }
- }
-
- // retrieve the underlying implementation's draw EGLSurface
- if (draw != EGL_NO_SURFACE) {
- d = get_surface(draw);
- // make sure the EGLContext and EGLSurface passed in are for
- // the same driver
- if (c && d->impl != c->impl)
- return setError(EGL_BAD_MATCH, EGL_FALSE);
- impl_draw = d->surface;
- }
-
- // retrieve the underlying implementation's read EGLSurface
- if (read != EGL_NO_SURFACE) {
- r = get_surface(read);
- // make sure the EGLContext and EGLSurface passed in are for
- // the same driver
- if (c && r->impl != c->impl)
- return setError(EGL_BAD_MATCH, EGL_FALSE);
- 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);
- }
-
- if (result == EGL_TRUE) {
-
- loseCurrent(cur_c);
-
- if (ctx != EGL_NO_CONTEXT) {
- setGLHooksThreadSpecific(c->cnx->hooks[c->version]);
- setContext(ctx);
- tls_t * const tls = getTLS();
- if (!tls->dbg && gEGLDebugLevel > 0)
- tls->dbg = CreateDbgContext(gEGLThreadLocalStorageKey, c->version,
- c->cnx->hooks[c->version]);
- _c.acquire();
- _r.acquire();
- _d.acquire();
- c->read = read;
- c->draw = draw;
- } else {
- setGLHooksThreadSpecific(&gHooksNoContext);
- setContext(EGL_NO_CONTEXT);
- }
- }
- return result;
-}
-
-
-EGLBoolean eglQueryContext( EGLDisplay dpy, EGLContext ctx,
- EGLint attribute, EGLint *value)
-{
- clearError();
-
- egl_display_t const * const dp = validate_display(dpy);
- if (!dp) return EGL_FALSE;
-
- ContextRef _c(ctx);
- if (!_c.get()) return setError(EGL_BAD_CONTEXT, EGL_FALSE);
-
- if (!validate_display_context(dpy, ctx))
- return EGL_FALSE;
-
- egl_context_t * const c = get_context(ctx);
-
- EGLBoolean result(EGL_TRUE);
- if (attribute == EGL_CONFIG_ID) {
- *value = dp->configs[intptr_t(c->config)].configId;
- } else {
- // We need to remap EGL_CONFIG_IDs
- result = c->cnx->egl.eglQueryContext(
- dp->disp[c->impl].dpy, c->context, attribute, value);
- }
-
- return result;
-}
-
-EGLContext eglGetCurrentContext(void)
-{
- // could be called before eglInitialize(), but we wouldn't have a context
- // then, and this function would correctly return EGL_NO_CONTEXT.
-
- clearError();
-
- EGLContext ctx = getContext();
- return ctx;
-}
-
-EGLSurface eglGetCurrentSurface(EGLint readdraw)
-{
- // could be called before eglInitialize(), but we wouldn't have a context
- // then, and this function would correctly return EGL_NO_SURFACE.
-
- clearError();
-
- EGLContext ctx = getContext();
- if (ctx) {
- egl_context_t const * const c = get_context(ctx);
- if (!c) return setError(EGL_BAD_CONTEXT, EGL_NO_SURFACE);
- switch (readdraw) {
- case EGL_READ: return c->read;
- case EGL_DRAW: return c->draw;
- default: return setError(EGL_BAD_PARAMETER, EGL_NO_SURFACE);
- }
- }
- return EGL_NO_SURFACE;
-}
-
-EGLDisplay eglGetCurrentDisplay(void)
-{
- // could be called before eglInitialize(), but we wouldn't have a context
- // then, and this function would correctly return EGL_NO_DISPLAY.
-
- clearError();
-
- EGLContext ctx = getContext();
- if (ctx) {
- egl_context_t const * const c = get_context(ctx);
- if (!c) return setError(EGL_BAD_CONTEXT, EGL_NO_SURFACE);
- return c->dpy;
- }
- return EGL_NO_DISPLAY;
-}
-
-EGLBoolean eglWaitGL(void)
-{
- // could be called before eglInitialize(), but we wouldn't have a context
- // then, and this function would return GL_TRUE, which isn't wrong.
-
- clearError();
-
- EGLBoolean res = EGL_TRUE;
- EGLContext ctx = getContext();
- if (ctx) {
- egl_context_t const * const c = get_context(ctx);
- if (!c) return setError(EGL_BAD_CONTEXT, EGL_FALSE);
- if (uint32_t(c->impl)>=2)
- return setError(EGL_BAD_CONTEXT, EGL_FALSE);
- egl_connection_t* const cnx = &gEGLImpl[c->impl];
- if (!cnx->dso)
- return setError(EGL_BAD_CONTEXT, EGL_FALSE);
- res = cnx->egl.eglWaitGL();
- }
- return res;
-}
-
-EGLBoolean eglWaitNative(EGLint engine)
-{
- // could be called before eglInitialize(), but we wouldn't have a context
- // then, and this function would return GL_TRUE, which isn't wrong.
-
- clearError();
-
- EGLBoolean res = EGL_TRUE;
- EGLContext ctx = getContext();
- if (ctx) {
- egl_context_t const * const c = get_context(ctx);
- if (!c) return setError(EGL_BAD_CONTEXT, EGL_FALSE);
- if (uint32_t(c->impl)>=2)
- return setError(EGL_BAD_CONTEXT, EGL_FALSE);
- egl_connection_t* const cnx = &gEGLImpl[c->impl];
- if (!cnx->dso)
- return setError(EGL_BAD_CONTEXT, EGL_FALSE);
- res = cnx->egl.eglWaitNative(engine);
- }
- return res;
-}
-
-EGLint eglGetError(void)
-{
- EGLint result = EGL_SUCCESS;
- EGLint err;
- for (int i=0 ; i<IMPL_NUM_IMPLEMENTATIONS ; i++) {
- err = EGL_SUCCESS;
- egl_connection_t* const cnx = &gEGLImpl[i];
- if (cnx->dso)
- err = cnx->egl.eglGetError();
- if (err!=EGL_SUCCESS && result==EGL_SUCCESS)
- result = err;
- }
- err = getError();
- if (result == EGL_SUCCESS)
- result = err;
- return result;
-}
-
-// Note: Similar implementations of these functions also exist in
-// gl2.cpp and gl.cpp, and are used by applications that call the
-// exported entry points directly.
-typedef void (GL_APIENTRYP PFNGLEGLIMAGETARGETTEXTURE2DOESPROC) (GLenum target, GLeglImageOES image);
-typedef void (GL_APIENTRYP PFNGLEGLIMAGETARGETRENDERBUFFERSTORAGEOESPROC) (GLenum target, GLeglImageOES image);
-
-static PFNGLEGLIMAGETARGETTEXTURE2DOESPROC glEGLImageTargetTexture2DOES_impl = NULL;
-static PFNGLEGLIMAGETARGETRENDERBUFFERSTORAGEOESPROC glEGLImageTargetRenderbufferStorageOES_impl = NULL;
-
-static void glEGLImageTargetTexture2DOES_wrapper(GLenum target, GLeglImageOES image)
-{
- GLeglImageOES implImage =
- (GLeglImageOES)egl_get_image_for_current_context((EGLImageKHR)image);
- glEGLImageTargetTexture2DOES_impl(target, implImage);
-}
-
-static void glEGLImageTargetRenderbufferStorageOES_wrapper(GLenum target, GLeglImageOES image)
-{
- GLeglImageOES implImage =
- (GLeglImageOES)egl_get_image_for_current_context((EGLImageKHR)image);
- glEGLImageTargetRenderbufferStorageOES_impl(target, implImage);
-}
-
-__eglMustCastToProperFunctionPointerType eglGetProcAddress(const char *procname)
-{
- // eglGetProcAddress() could be the very first function called
- // in which case we must make sure we've initialized ourselves, this
- // happens the first time egl_get_display() is called.
-
- clearError();
-
- if (egl_init_drivers() == EGL_FALSE) {
- setError(EGL_BAD_PARAMETER, NULL);
- return NULL;
- }
-
- __eglMustCastToProperFunctionPointerType addr;
- addr = findProcAddress(procname, gExtentionMap, NELEM(gExtentionMap));
- if (addr) return addr;
-
- // this protects accesses to gGLExtentionMap and gGLExtentionSlot
- pthread_mutex_lock(&gInitDriverMutex);
-
- /*
- * Since eglGetProcAddress() is not associated to anything, it needs
- * to return a function pointer that "works" regardless of what
- * the current context is.
- *
- * For this reason, we return a "forwarder", a small stub that takes
- * care of calling the function associated with the context
- * currently bound.
- *
- * We first look for extensions we've already resolved, if we're seeing
- * this extension for the first time, we go through all our
- * implementations and call eglGetProcAddress() and record the
- * result in the appropriate implementation hooks and return the
- * address of the forwarder corresponding to that hook set.
- *
- */
-
- const String8 name(procname);
- addr = gGLExtentionMap.valueFor(name);
- const int slot = gGLExtentionSlot;
-
- LOGE_IF(slot >= MAX_NUMBER_OF_GL_EXTENSIONS,
- "no more slots for eglGetProcAddress(\"%s\")",
- procname);
-
- if (!addr && (slot < MAX_NUMBER_OF_GL_EXTENSIONS)) {
- bool found = false;
- for (int i=0 ; i<IMPL_NUM_IMPLEMENTATIONS ; i++) {
- egl_connection_t* const cnx = &gEGLImpl[i];
- if (cnx->dso && cnx->egl.eglGetProcAddress) {
- found = true;
- // Extensions are independent of the bound context
- cnx->hooks[GLESv1_INDEX]->ext.extensions[slot] =
- cnx->hooks[GLESv2_INDEX]->ext.extensions[slot] =
-#if EGL_TRACE
- gHooksDebug.ext.extensions[slot] = gHooksTrace.ext.extensions[slot] =
-#endif
- cnx->egl.eglGetProcAddress(procname);
- }
- }
- if (found) {
- addr = gExtensionForwarders[slot];
-
- if (!strcmp(procname, "glEGLImageTargetTexture2DOES")) {
- glEGLImageTargetTexture2DOES_impl = (PFNGLEGLIMAGETARGETTEXTURE2DOESPROC)addr;
- addr = (__eglMustCastToProperFunctionPointerType)glEGLImageTargetTexture2DOES_wrapper;
- }
- if (!strcmp(procname, "glEGLImageTargetRenderbufferStorageOES")) {
- glEGLImageTargetRenderbufferStorageOES_impl = (PFNGLEGLIMAGETARGETRENDERBUFFERSTORAGEOESPROC)addr;
- addr = (__eglMustCastToProperFunctionPointerType)glEGLImageTargetRenderbufferStorageOES_wrapper;
- }
-
- gGLExtentionMap.add(name, addr);
- gGLExtentionSlot++;
- }
- }
-
- pthread_mutex_unlock(&gInitDriverMutex);
- return addr;
-}
-
-EGLBoolean eglSwapBuffers(EGLDisplay dpy, EGLSurface draw)
-{
- EGLBoolean Debug_eglSwapBuffers(EGLDisplay dpy, EGLSurface draw);
- if (gEGLDebugLevel > 0)
- Debug_eglSwapBuffers(dpy, draw);
-
- clearError();
-
- egl_display_t const * const dp = validate_display(dpy);
- if (!dp) return EGL_FALSE;
-
- SurfaceRef _s(draw);
- if (!_s.get()) return setError(EGL_BAD_SURFACE, EGL_FALSE);
-
- if (!validate_display_surface(dpy, draw))
- return EGL_FALSE;
- egl_surface_t const * const s = get_surface(draw);
- return s->cnx->egl.eglSwapBuffers(dp->disp[s->impl].dpy, s->surface);
-}
-
-EGLBoolean eglCopyBuffers( EGLDisplay dpy, EGLSurface surface,
- NativePixmapType target)
-{
- clearError();
-
- egl_display_t const * const dp = validate_display(dpy);
- if (!dp) return EGL_FALSE;
-
- SurfaceRef _s(surface);
- if (!_s.get()) return setError(EGL_BAD_SURFACE, EGL_FALSE);
-
- if (!validate_display_surface(dpy, surface))
- return EGL_FALSE;
- egl_surface_t const * const s = get_surface(surface);
- return s->cnx->egl.eglCopyBuffers(
- dp->disp[s->impl].dpy, s->surface, target);
-}
-
-const char* eglQueryString(EGLDisplay dpy, EGLint name)
-{
- clearError();
-
- egl_display_t const * const dp = validate_display(dpy);
- if (!dp) return (const char *) NULL;
-
- switch (name) {
- case EGL_VENDOR:
- return gVendorString;
- case EGL_VERSION:
- return gVersionString;
- case EGL_EXTENSIONS:
- return gExtensionString;
- case EGL_CLIENT_APIS:
- return gClientApiString;
- }
- return setError(EGL_BAD_PARAMETER, (const char *)0);
-}
-
-
-// ----------------------------------------------------------------------------
-// EGL 1.1
-// ----------------------------------------------------------------------------
-
-EGLBoolean eglSurfaceAttrib(
- EGLDisplay dpy, EGLSurface surface, EGLint attribute, EGLint value)
-{
- clearError();
-
- egl_display_t const * const dp = validate_display(dpy);
- if (!dp) return EGL_FALSE;
-
- SurfaceRef _s(surface);
- if (!_s.get()) return setError(EGL_BAD_SURFACE, EGL_FALSE);
-
- if (!validate_display_surface(dpy, surface))
- return EGL_FALSE;
- egl_surface_t const * const s = get_surface(surface);
- if (s->cnx->egl.eglSurfaceAttrib) {
- return s->cnx->egl.eglSurfaceAttrib(
- dp->disp[s->impl].dpy, s->surface, attribute, value);
- }
- return setError(EGL_BAD_SURFACE, EGL_FALSE);
-}
-
-EGLBoolean eglBindTexImage(
- EGLDisplay dpy, EGLSurface surface, EGLint buffer)
-{
- clearError();
-
- egl_display_t const * const dp = validate_display(dpy);
- if (!dp) return EGL_FALSE;
-
- SurfaceRef _s(surface);
- if (!_s.get()) return setError(EGL_BAD_SURFACE, EGL_FALSE);
-
- if (!validate_display_surface(dpy, surface))
- return EGL_FALSE;
- egl_surface_t const * const s = get_surface(surface);
- if (s->cnx->egl.eglBindTexImage) {
- return s->cnx->egl.eglBindTexImage(
- dp->disp[s->impl].dpy, s->surface, buffer);
- }
- return setError(EGL_BAD_SURFACE, EGL_FALSE);
-}
-
-EGLBoolean eglReleaseTexImage(
- EGLDisplay dpy, EGLSurface surface, EGLint buffer)
-{
- clearError();
-
- egl_display_t const * const dp = validate_display(dpy);
- if (!dp) return EGL_FALSE;
-
- SurfaceRef _s(surface);
- if (!_s.get()) return setError(EGL_BAD_SURFACE, EGL_FALSE);
-
- if (!validate_display_surface(dpy, surface))
- return EGL_FALSE;
- egl_surface_t const * const s = get_surface(surface);
- if (s->cnx->egl.eglReleaseTexImage) {
- return s->cnx->egl.eglReleaseTexImage(
- dp->disp[s->impl].dpy, s->surface, buffer);
- }
- return setError(EGL_BAD_SURFACE, EGL_FALSE);
-}
-
-EGLBoolean eglSwapInterval(EGLDisplay dpy, EGLint interval)
-{
- clearError();
-
- egl_display_t const * const dp = validate_display(dpy);
- if (!dp) return EGL_FALSE;
-
- EGLBoolean res = EGL_TRUE;
- for (int i=0 ; i<IMPL_NUM_IMPLEMENTATIONS ; i++) {
- egl_connection_t* const cnx = &gEGLImpl[i];
- if (cnx->dso) {
- if (cnx->egl.eglSwapInterval) {
- if (cnx->egl.eglSwapInterval(
- dp->disp[i].dpy, interval) == EGL_FALSE) {
- res = EGL_FALSE;
- }
- }
- }
- }
- return res;
-}
-
-
-// ----------------------------------------------------------------------------
-// EGL 1.2
-// ----------------------------------------------------------------------------
-
-EGLBoolean eglWaitClient(void)
-{
- clearError();
-
- // could be called before eglInitialize(), but we wouldn't have a context
- // then, and this function would return GL_TRUE, which isn't wrong.
- EGLBoolean res = EGL_TRUE;
- EGLContext ctx = getContext();
- if (ctx) {
- egl_context_t const * const c = get_context(ctx);
- if (!c) return setError(EGL_BAD_CONTEXT, EGL_FALSE);
- if (uint32_t(c->impl)>=2)
- return setError(EGL_BAD_CONTEXT, EGL_FALSE);
- egl_connection_t* const cnx = &gEGLImpl[c->impl];
- if (!cnx->dso)
- return setError(EGL_BAD_CONTEXT, EGL_FALSE);
- if (cnx->egl.eglWaitClient) {
- res = cnx->egl.eglWaitClient();
- } else {
- res = cnx->egl.eglWaitGL();
- }
- }
- return res;
-}
-
-EGLBoolean eglBindAPI(EGLenum api)
-{
- clearError();
-
- if (egl_init_drivers() == EGL_FALSE) {
- return setError(EGL_BAD_PARAMETER, EGL_FALSE);
- }
-
- // bind this API on all EGLs
- EGLBoolean res = EGL_TRUE;
- for (int i=0 ; i<IMPL_NUM_IMPLEMENTATIONS ; i++) {
- egl_connection_t* const cnx = &gEGLImpl[i];
- if (cnx->dso) {
- if (cnx->egl.eglBindAPI) {
- if (cnx->egl.eglBindAPI(api) == EGL_FALSE) {
- res = EGL_FALSE;
- }
- }
- }
- }
- return res;
-}
-
-EGLenum eglQueryAPI(void)
-{
- clearError();
-
- if (egl_init_drivers() == EGL_FALSE) {
- return setError(EGL_BAD_PARAMETER, EGL_FALSE);
- }
-
- for (int i=0 ; i<IMPL_NUM_IMPLEMENTATIONS ; i++) {
- egl_connection_t* const cnx = &gEGLImpl[i];
- if (cnx->dso) {
- if (cnx->egl.eglQueryAPI) {
- // the first one we find is okay, because they all
- // should be the same
- return cnx->egl.eglQueryAPI();
- }
- }
- }
- // or, it can only be OpenGL ES
- return EGL_OPENGL_ES_API;
-}
-
-EGLBoolean eglReleaseThread(void)
-{
- clearError();
-
- // If there is context bound to the thread, release it
- loseCurrent(get_context(getContext()));
-
- for (int i=0 ; i<IMPL_NUM_IMPLEMENTATIONS ; i++) {
- egl_connection_t* const cnx = &gEGLImpl[i];
- if (cnx->dso) {
- if (cnx->egl.eglReleaseThread) {
- cnx->egl.eglReleaseThread();
- }
- }
- }
- clearTLS();
- return EGL_TRUE;
-}
-
-EGLSurface eglCreatePbufferFromClientBuffer(
- EGLDisplay dpy, EGLenum buftype, EGLClientBuffer buffer,
- EGLConfig config, const EGLint *attrib_list)
-{
- clearError();
-
- egl_display_t const* dp = 0;
- egl_connection_t* cnx = validate_display_config(dpy, config, dp);
- if (!cnx) return EGL_FALSE;
- if (cnx->egl.eglCreatePbufferFromClientBuffer) {
- return cnx->egl.eglCreatePbufferFromClientBuffer(
- dp->disp[ dp->configs[intptr_t(config)].impl ].dpy,
- buftype, buffer,
- dp->configs[intptr_t(config)].config, attrib_list);
- }
- return setError(EGL_BAD_CONFIG, EGL_NO_SURFACE);
-}
-
-// ----------------------------------------------------------------------------
-// EGL_EGLEXT_VERSION 3
-// ----------------------------------------------------------------------------
-
-EGLBoolean eglLockSurfaceKHR(EGLDisplay dpy, EGLSurface surface,
- const EGLint *attrib_list)
-{
- clearError();
-
- egl_display_t const * const dp = validate_display(dpy);
- if (!dp) return EGL_FALSE;
-
- SurfaceRef _s(surface);
- if (!_s.get()) return setError(EGL_BAD_SURFACE, EGL_FALSE);
-
- if (!validate_display_surface(dpy, surface))
- return EGL_FALSE;
-
- egl_surface_t const * const s = get_surface(surface);
-
- if (s->cnx->egl.eglLockSurfaceKHR) {
- return s->cnx->egl.eglLockSurfaceKHR(
- dp->disp[s->impl].dpy, s->surface, attrib_list);
- }
- return setError(EGL_BAD_DISPLAY, EGL_FALSE);
-}
-
-EGLBoolean eglUnlockSurfaceKHR(EGLDisplay dpy, EGLSurface surface)
-{
- clearError();
-
- egl_display_t const * const dp = validate_display(dpy);
- if (!dp) return EGL_FALSE;
-
- SurfaceRef _s(surface);
- if (!_s.get()) return setError(EGL_BAD_SURFACE, EGL_FALSE);
-
- if (!validate_display_surface(dpy, surface))
- return EGL_FALSE;
-
- egl_surface_t const * const s = get_surface(surface);
-
- if (s->cnx->egl.eglUnlockSurfaceKHR) {
- return s->cnx->egl.eglUnlockSurfaceKHR(
- dp->disp[s->impl].dpy, s->surface);
- }
- return setError(EGL_BAD_DISPLAY, EGL_FALSE);
-}
-
-EGLImageKHR eglCreateImageKHR(EGLDisplay dpy, EGLContext ctx, EGLenum target,
- EGLClientBuffer buffer, const EGLint *attrib_list)
-{
- clearError();
-
- egl_display_t const * const dp = validate_display(dpy);
- if (!dp) return EGL_NO_IMAGE_KHR;
-
- if (ctx != EGL_NO_CONTEXT) {
- ContextRef _c(ctx);
- if (!_c.get()) return setError(EGL_BAD_CONTEXT, EGL_NO_IMAGE_KHR);
- if (!validate_display_context(dpy, ctx))
- return EGL_NO_IMAGE_KHR;
- egl_context_t * const c = get_context(ctx);
- // since we have an EGLContext, we know which implementation to use
- EGLImageKHR image = c->cnx->egl.eglCreateImageKHR(
- dp->disp[c->impl].dpy, c->context, target, buffer, attrib_list);
- if (image == EGL_NO_IMAGE_KHR)
- return image;
-
- egl_image_t* result = new egl_image_t(dpy, ctx);
- result->images[c->impl] = image;
- return (EGLImageKHR)result;
- } else {
- // EGL_NO_CONTEXT is a valid parameter
-
- /* Since we don't have a way to know which implementation to call,
- * we're calling all of them. If at least one of the implementation
- * succeeded, this is a success.
- */
-
- EGLint currentError = eglGetError();
-
- EGLImageKHR implImages[IMPL_NUM_IMPLEMENTATIONS];
- bool success = false;
- for (int i=0 ; i<IMPL_NUM_IMPLEMENTATIONS ; i++) {
- egl_connection_t* const cnx = &gEGLImpl[i];
- implImages[i] = EGL_NO_IMAGE_KHR;
- if (cnx->dso) {
- if (cnx->egl.eglCreateImageKHR) {
- implImages[i] = cnx->egl.eglCreateImageKHR(
- dp->disp[i].dpy, ctx, target, buffer, attrib_list);
- if (implImages[i] != EGL_NO_IMAGE_KHR) {
- success = true;
- }
- }
- }
- }
-
- if (!success) {
- // failure, if there was an error when we entered this function,
- // the error flag must not be updated.
- // Otherwise, the error is whatever happened in the implementation
- // that faulted.
- if (currentError != EGL_SUCCESS) {
- setError(currentError, EGL_NO_IMAGE_KHR);
- }
- return EGL_NO_IMAGE_KHR;
- } else {
- // In case of success, we need to clear all error flags
- // (especially those caused by the implementation that didn't
- // succeed). TODO: we could avoid this if we knew this was
- // a "full" success (all implementation succeeded).
- eglGetError();
- }
-
- egl_image_t* result = new egl_image_t(dpy, ctx);
- memcpy(result->images, implImages, sizeof(implImages));
- return (EGLImageKHR)result;
- }
-}
-
-EGLBoolean eglDestroyImageKHR(EGLDisplay dpy, EGLImageKHR img)
-{
- clearError();
-
- egl_display_t const * const dp = validate_display(dpy);
- if (!dp) return EGL_FALSE;
-
- ImageRef _i(img);
- if (!_i.get()) return setError(EGL_BAD_PARAMETER, EGL_FALSE);
-
- egl_image_t* image = get_image(img);
- bool success = false;
- for (int i=0 ; i<IMPL_NUM_IMPLEMENTATIONS ; i++) {
- egl_connection_t* const cnx = &gEGLImpl[i];
- if (image->images[i] != EGL_NO_IMAGE_KHR) {
- if (cnx->dso) {
- if (cnx->egl.eglDestroyImageKHR) {
- if (cnx->egl.eglDestroyImageKHR(
- dp->disp[i].dpy, image->images[i])) {
- success = true;
- }
- }
- }
- }
- }
- if (!success)
- return EGL_FALSE;
-
- _i.terminate();
-
- return EGL_TRUE;
-}
-
-// ----------------------------------------------------------------------------
-// EGL_EGLEXT_VERSION 5
-// ----------------------------------------------------------------------------
-
-
-EGLSyncKHR eglCreateSyncKHR(EGLDisplay dpy, EGLenum type, const EGLint *attrib_list)
-{
- clearError();
-
- egl_display_t const * const dp = validate_display(dpy);
- if (!dp) return EGL_NO_SYNC_KHR;
-
- EGLContext ctx = eglGetCurrentContext();
- ContextRef _c(ctx);
- if (!_c.get()) return setError(EGL_BAD_CONTEXT, EGL_NO_SYNC_KHR);
- if (!validate_display_context(dpy, ctx))
- return EGL_NO_SYNC_KHR;
- egl_context_t * const c = get_context(ctx);
- EGLSyncKHR result = EGL_NO_SYNC_KHR;
- if (c->cnx->egl.eglCreateSyncKHR) {
- EGLSyncKHR sync = c->cnx->egl.eglCreateSyncKHR(
- dp->disp[c->impl].dpy, type, attrib_list);
- if (sync == EGL_NO_SYNC_KHR)
- return sync;
- result = (egl_sync_t*)new egl_sync_t(dpy, ctx, sync);
- }
- return (EGLSyncKHR)result;
-}
-
-EGLBoolean eglDestroySyncKHR(EGLDisplay dpy, EGLSyncKHR sync)
-{
- clearError();
-
- egl_display_t const * const dp = validate_display(dpy);
- if (!dp) return EGL_FALSE;
-
- SyncRef _s(sync);
- if (!_s.get()) return setError(EGL_BAD_PARAMETER, EGL_FALSE);
- egl_sync_t* syncObject = get_sync(sync);
-
- EGLContext ctx = syncObject->context;
- ContextRef _c(ctx);
- if (!_c.get()) return setError(EGL_BAD_CONTEXT, EGL_FALSE);
- if (!validate_display_context(dpy, ctx))
- return EGL_FALSE;
-
- EGLBoolean result = EGL_FALSE;
- egl_context_t * const c = get_context(ctx);
- if (c->cnx->egl.eglDestroySyncKHR) {
- result = c->cnx->egl.eglDestroySyncKHR(
- dp->disp[c->impl].dpy, syncObject->sync);
- if (result)
- _s.terminate();
- }
- return result;
-}
-
-EGLint eglClientWaitSyncKHR(EGLDisplay dpy, EGLSyncKHR sync, EGLint flags, EGLTimeKHR timeout)
-{
- clearError();
-
- egl_display_t const * const dp = validate_display(dpy);
- if (!dp) return EGL_FALSE;
-
- SyncRef _s(sync);
- if (!_s.get()) return setError(EGL_BAD_PARAMETER, EGL_FALSE);
- egl_sync_t* syncObject = get_sync(sync);
-
- EGLContext ctx = syncObject->context;
- ContextRef _c(ctx);
- if (!_c.get()) return setError(EGL_BAD_CONTEXT, EGL_FALSE);
- if (!validate_display_context(dpy, ctx))
- return EGL_FALSE;
-
- egl_context_t * const c = get_context(ctx);
-
- if (c->cnx->egl.eglClientWaitSyncKHR) {
- return c->cnx->egl.eglClientWaitSyncKHR(
- dp->disp[c->impl].dpy, syncObject->sync, flags, timeout);
- }
-
- return EGL_FALSE;
-}
-
-EGLBoolean eglGetSyncAttribKHR(EGLDisplay dpy, EGLSyncKHR sync, EGLint attribute, EGLint *value)
-{
- clearError();
-
- egl_display_t const * const dp = validate_display(dpy);
- if (!dp) return EGL_FALSE;
-
- SyncRef _s(sync);
- if (!_s.get()) return setError(EGL_BAD_PARAMETER, EGL_FALSE);
- egl_sync_t* syncObject = get_sync(sync);
-
- EGLContext ctx = syncObject->context;
- ContextRef _c(ctx);
- if (!_c.get()) return setError(EGL_BAD_CONTEXT, EGL_FALSE);
- if (!validate_display_context(dpy, ctx))
- return EGL_FALSE;
-
- egl_context_t * const c = get_context(ctx);
-
- if (c->cnx->egl.eglGetSyncAttribKHR) {
- return c->cnx->egl.eglGetSyncAttribKHR(
- dp->disp[c->impl].dpy, syncObject->sync, attribute, value);
- }
-
- return EGL_FALSE;
-}
-
-// ----------------------------------------------------------------------------
-// ANDROID extensions
-// ----------------------------------------------------------------------------
-
-EGLBoolean eglSetSwapRectangleANDROID(EGLDisplay dpy, EGLSurface draw,
- EGLint left, EGLint top, EGLint width, EGLint height)
-{
- clearError();
-
- egl_display_t const * const dp = validate_display(dpy);
- if (!dp) return EGL_FALSE;
-
- SurfaceRef _s(draw);
- if (!_s.get()) return setError(EGL_BAD_SURFACE, EGL_FALSE);
-
- if (!validate_display_surface(dpy, draw))
- return EGL_FALSE;
- egl_surface_t const * const s = get_surface(draw);
- if (s->cnx->egl.eglSetSwapRectangleANDROID) {
- return s->cnx->egl.eglSetSwapRectangleANDROID(
- dp->disp[s->impl].dpy, s->surface, left, top, width, height);
- }
- return setError(EGL_BAD_DISPLAY, NULL);
-}
diff --git a/opengl/libs/EGL/eglApi.cpp b/opengl/libs/EGL/eglApi.cpp
new file mode 100644
index 0000000..7d5d010
--- /dev/null
+++ b/opengl/libs/EGL/eglApi.cpp
@@ -0,0 +1,1440 @@
+/*
+ ** Copyright 2007, The Android Open Source Project
+ **
+ ** Licensed under the Apache License, Version 2.0 (the "License");
+ ** you may not use this file except in compliance with the License.
+ ** You may obtain a copy of the License at
+ **
+ ** http://www.apache.org/licenses/LICENSE-2.0
+ **
+ ** Unless required by applicable law or agreed to in writing, software
+ ** distributed under the License is distributed on an "AS IS" BASIS,
+ ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ** See the License for the specific language governing permissions and
+ ** limitations under the License.
+ */
+
+#include <ctype.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <hardware/gralloc.h>
+#include <system/window.h>
+
+#include <EGL/egl.h>
+#include <EGL/eglext.h>
+#include <GLES/gl.h>
+#include <GLES/glext.h>
+
+#include <cutils/log.h>
+#include <cutils/atomic.h>
+#include <cutils/properties.h>
+#include <cutils/memory.h>
+
+#include <utils/KeyedVector.h>
+#include <utils/SortedVector.h>
+#include <utils/String8.h>
+
+#include "egl_impl.h"
+#include "egl_tls.h"
+#include "glesv2dbg.h"
+#include "hooks.h"
+
+#include "egl_display.h"
+#include "egl_impl.h"
+#include "egl_object.h"
+#include "egl_tls.h"
+
+using namespace android;
+
+// ----------------------------------------------------------------------------
+
+static char const * const sVendorString = "Android";
+static char const * const sVersionString = "1.4 Android META-EGL";
+static char const * const sClientApiString = "OpenGL ES";
+static char const * const sExtensionString =
+ "EGL_KHR_image "
+ "EGL_KHR_image_base "
+ "EGL_KHR_image_pixmap "
+ "EGL_KHR_gl_texture_2D_image "
+ "EGL_KHR_gl_texture_cubemap_image "
+ "EGL_KHR_gl_renderbuffer_image "
+ "EGL_KHR_fence_sync "
+ "EGL_ANDROID_image_native_buffer "
+ "EGL_ANDROID_swap_rectangle "
+ ;
+
+struct extention_map_t {
+ const char* name;
+ __eglMustCastToProperFunctionPointerType address;
+};
+
+static const extention_map_t sExtentionMap[] = {
+ { "eglLockSurfaceKHR",
+ (__eglMustCastToProperFunctionPointerType)&eglLockSurfaceKHR },
+ { "eglUnlockSurfaceKHR",
+ (__eglMustCastToProperFunctionPointerType)&eglUnlockSurfaceKHR },
+ { "eglCreateImageKHR",
+ (__eglMustCastToProperFunctionPointerType)&eglCreateImageKHR },
+ { "eglDestroyImageKHR",
+ (__eglMustCastToProperFunctionPointerType)&eglDestroyImageKHR },
+ { "eglSetSwapRectangleANDROID",
+ (__eglMustCastToProperFunctionPointerType)&eglSetSwapRectangleANDROID },
+};
+
+// accesses protected by sExtensionMapMutex
+static DefaultKeyedVector<String8, __eglMustCastToProperFunctionPointerType> sGLExtentionMap;
+static int sGLExtentionSlot = 0;
+static pthread_mutex_t sExtensionMapMutex = PTHREAD_MUTEX_INITIALIZER;
+
+static void(*findProcAddress(const char* name,
+ const extention_map_t* map, size_t n))() {
+ for (uint32_t i=0 ; i<n ; i++) {
+ if (!strcmp(name, map[i].name)) {
+ return map[i].address;
+ }
+ }
+ return NULL;
+}
+
+// ----------------------------------------------------------------------------
+
+template<typename T>
+static __attribute__((noinline))
+int binarySearch(T const sortedArray[], int first, int last, T key) {
+ while (first <= last) {
+ int mid = (first + last) / 2;
+ if (sortedArray[mid] < key) {
+ first = mid + 1;
+ } else if (key < sortedArray[mid]) {
+ last = mid - 1;
+ } else {
+ return mid;
+ }
+ }
+ return -1;
+}
+
+// ----------------------------------------------------------------------------
+
+namespace android {
+extern void setGLHooksThreadSpecific(gl_hooks_t const *value);
+extern EGLBoolean egl_init_drivers();
+extern const __eglMustCastToProperFunctionPointerType gExtensionForwarders[MAX_NUMBER_OF_GL_EXTENSIONS];
+extern int gEGLDebugLevel;
+extern gl_hooks_t gHooksTrace;
+extern gl_hooks_t gHooksDebug;
+} // namespace android;
+
+// ----------------------------------------------------------------------------
+
+static inline void clearError() { egl_tls_t::clearError(); }
+static inline EGLContext getContext() { return egl_tls_t::getContext(); }
+
+// ----------------------------------------------------------------------------
+
+EGLDisplay eglGetDisplay(EGLNativeDisplayType display)
+{
+ clearError();
+
+ uint32_t index = uint32_t(display);
+ if (index >= NUM_DISPLAYS) {
+ return setError(EGL_BAD_PARAMETER, EGL_NO_DISPLAY);
+ }
+
+ if (egl_init_drivers() == EGL_FALSE) {
+ return setError(EGL_BAD_PARAMETER, EGL_NO_DISPLAY);
+ }
+
+ EGLDisplay dpy = egl_display_t::getFromNativeDisplay(display);
+ return dpy;
+}
+
+// ----------------------------------------------------------------------------
+// Initialization
+// ----------------------------------------------------------------------------
+
+EGLBoolean eglInitialize(EGLDisplay dpy, EGLint *major, EGLint *minor)
+{
+ clearError();
+
+ egl_display_t * const dp = get_display(dpy);
+ if (!dp) return setError(EGL_BAD_DISPLAY, EGL_FALSE);
+
+ EGLBoolean res = dp->initialize(major, minor);
+
+ return res;
+}
+
+EGLBoolean eglTerminate(EGLDisplay dpy)
+{
+ // NOTE: don't unload the drivers b/c some APIs can be called
+ // after eglTerminate() has been called. eglTerminate() only
+ // terminates an EGLDisplay, not a EGL itself.
+
+ clearError();
+
+ egl_display_t* const dp = get_display(dpy);
+ if (!dp) return setError(EGL_BAD_DISPLAY, EGL_FALSE);
+
+ EGLBoolean res = dp->terminate();
+
+ return res;
+}
+
+// ----------------------------------------------------------------------------
+// configuration
+// ----------------------------------------------------------------------------
+
+EGLBoolean eglGetConfigs( EGLDisplay dpy,
+ EGLConfig *configs,
+ EGLint config_size, EGLint *num_config)
+{
+ clearError();
+
+ egl_display_t const * const dp = validate_display(dpy);
+ if (!dp) return EGL_FALSE;
+
+ GLint numConfigs = dp->numTotalConfigs;
+ if (!configs) {
+ *num_config = numConfigs;
+ return EGL_TRUE;
+ }
+
+ GLint n = 0;
+ for (intptr_t i=0 ; i<dp->numTotalConfigs && config_size ; i++) {
+ *configs++ = EGLConfig(i);
+ config_size--;
+ n++;
+ }
+
+ *num_config = n;
+ return EGL_TRUE;
+}
+
+EGLBoolean eglChooseConfig( EGLDisplay dpy, const EGLint *attrib_list,
+ EGLConfig *configs, EGLint config_size,
+ EGLint *num_config)
+{
+ clearError();
+
+ egl_display_t const * const dp = validate_display(dpy);
+ if (!dp) return EGL_FALSE;
+
+ if (num_config==0) {
+ return setError(EGL_BAD_PARAMETER, EGL_FALSE);
+ }
+
+ EGLint n;
+ EGLBoolean res = EGL_FALSE;
+ *num_config = 0;
+
+
+ // It is unfortunate, but we need to remap the EGL_CONFIG_IDs,
+ // to do this, we have to go through the attrib_list array once
+ // to figure out both its size and if it contains an EGL_CONFIG_ID
+ // key. If so, the full array is copied and patched.
+ // NOTE: we assume that there can be only one occurrence
+ // of EGL_CONFIG_ID.
+
+ EGLint patch_index = -1;
+ GLint attr;
+ size_t size = 0;
+ if (attrib_list) {
+ while ((attr=attrib_list[size]) != EGL_NONE) {
+ if (attr == EGL_CONFIG_ID)
+ patch_index = size;
+ size += 2;
+ }
+ }
+ if (patch_index >= 0) {
+ size += 2; // we need copy the sentinel as well
+ EGLint* new_list = (EGLint*)malloc(size*sizeof(EGLint));
+ if (new_list == 0)
+ return setError(EGL_BAD_ALLOC, EGL_FALSE);
+ memcpy(new_list, attrib_list, size*sizeof(EGLint));
+
+ // patch the requested EGL_CONFIG_ID
+ bool found = false;
+ EGLConfig ourConfig(0);
+ EGLint& configId(new_list[patch_index+1]);
+ for (intptr_t i=0 ; i<dp->numTotalConfigs ; i++) {
+ if (dp->configs[i].configId == configId) {
+ ourConfig = EGLConfig(i);
+ configId = dp->configs[i].implConfigId;
+ found = true;
+ break;
+ }
+ }
+
+ egl_connection_t* const cnx = &gEGLImpl[dp->configs[intptr_t(ourConfig)].impl];
+ if (found && cnx->dso) {
+ // and switch to the new list
+ attrib_list = const_cast<const EGLint *>(new_list);
+
+ // At this point, the only configuration that can match is
+ // dp->configs[i][index], however, we don't know if it would be
+ // rejected because of the other attributes, so we do have to call
+ // cnx->egl.eglChooseConfig() -- but we don't have to loop
+ // through all the EGLimpl[].
+ // We also know we can only get a single config back, and we know
+ // which one.
+
+ res = cnx->egl.eglChooseConfig(
+ dp->disp[ dp->configs[intptr_t(ourConfig)].impl ].dpy,
+ attrib_list, configs, config_size, &n);
+ if (res && n>0) {
+ // n has to be 0 or 1, by construction, and we already know
+ // which config it will return (since there can be only one).
+ if (configs) {
+ configs[0] = ourConfig;
+ }
+ *num_config = 1;
+ }
+ }
+
+ free(const_cast<EGLint *>(attrib_list));
+ return res;
+ }
+
+
+ for (int i=0 ; i<IMPL_NUM_IMPLEMENTATIONS ; i++) {
+ egl_connection_t* const cnx = &gEGLImpl[i];
+ if (cnx->dso) {
+ if (cnx->egl.eglChooseConfig(
+ dp->disp[i].dpy, attrib_list, configs, config_size, &n)) {
+ if (configs) {
+ // now we need to convert these client EGLConfig to our
+ // internal EGLConfig format.
+ // This is done in O(n Log(n)) time.
+ for (int j=0 ; j<n ; j++) {
+ egl_config_t key(i, configs[j]);
+ intptr_t index = binarySearch<egl_config_t>(
+ dp->configs, 0, dp->numTotalConfigs, key);
+ if (index >= 0) {
+ configs[j] = EGLConfig(index);
+ } else {
+ return setError(EGL_BAD_CONFIG, EGL_FALSE);
+ }
+ }
+ configs += n;
+ config_size -= n;
+ }
+ *num_config += n;
+ res = EGL_TRUE;
+ }
+ }
+ }
+ return res;
+}
+
+EGLBoolean eglGetConfigAttrib(EGLDisplay dpy, EGLConfig config,
+ EGLint attribute, EGLint *value)
+{
+ clearError();
+
+ egl_display_t const* dp = 0;
+ egl_connection_t* cnx = validate_display_config(dpy, config, dp);
+ if (!cnx) return EGL_FALSE;
+
+ if (attribute == EGL_CONFIG_ID) {
+ *value = dp->configs[intptr_t(config)].configId;
+ return EGL_TRUE;
+ }
+ return cnx->egl.eglGetConfigAttrib(
+ dp->disp[ dp->configs[intptr_t(config)].impl ].dpy,
+ dp->configs[intptr_t(config)].config, attribute, value);
+}
+
+// ----------------------------------------------------------------------------
+// surfaces
+// ----------------------------------------------------------------------------
+
+EGLSurface eglCreateWindowSurface( EGLDisplay dpy, EGLConfig config,
+ NativeWindowType window,
+ const EGLint *attrib_list)
+{
+ clearError();
+
+ egl_display_t const* dp = 0;
+ egl_connection_t* cnx = validate_display_config(dpy, config, dp);
+ if (cnx) {
+ EGLDisplay iDpy = dp->disp[ dp->configs[intptr_t(config)].impl ].dpy;
+ EGLConfig iConfig = dp->configs[intptr_t(config)].config;
+ EGLint format;
+
+ // set the native window's buffers format to match this config
+ if (cnx->egl.eglGetConfigAttrib(iDpy,
+ iConfig, EGL_NATIVE_VISUAL_ID, &format)) {
+ if (format != 0) {
+ native_window_set_buffers_geometry(window, 0, 0, format);
+ }
+ }
+
+ EGLSurface surface = cnx->egl.eglCreateWindowSurface(
+ iDpy, iConfig, window, attrib_list);
+ if (surface != EGL_NO_SURFACE) {
+ egl_surface_t* s = new egl_surface_t(dpy, config, window, surface,
+ dp->configs[intptr_t(config)].impl, cnx);
+ return s;
+ }
+ }
+ return EGL_NO_SURFACE;
+}
+
+EGLSurface eglCreatePixmapSurface( EGLDisplay dpy, EGLConfig config,
+ NativePixmapType pixmap,
+ const EGLint *attrib_list)
+{
+ clearError();
+
+ egl_display_t const* dp = 0;
+ egl_connection_t* cnx = validate_display_config(dpy, config, dp);
+ if (cnx) {
+ EGLSurface surface = cnx->egl.eglCreatePixmapSurface(
+ dp->disp[ dp->configs[intptr_t(config)].impl ].dpy,
+ dp->configs[intptr_t(config)].config, pixmap, attrib_list);
+ if (surface != EGL_NO_SURFACE) {
+ egl_surface_t* s = new egl_surface_t(dpy, config, NULL, surface,
+ dp->configs[intptr_t(config)].impl, cnx);
+ return s;
+ }
+ }
+ return EGL_NO_SURFACE;
+}
+
+EGLSurface eglCreatePbufferSurface( EGLDisplay dpy, EGLConfig config,
+ const EGLint *attrib_list)
+{
+ clearError();
+
+ egl_display_t const* dp = 0;
+ egl_connection_t* cnx = validate_display_config(dpy, config, dp);
+ if (cnx) {
+ EGLSurface surface = cnx->egl.eglCreatePbufferSurface(
+ dp->disp[ dp->configs[intptr_t(config)].impl ].dpy,
+ dp->configs[intptr_t(config)].config, attrib_list);
+ if (surface != EGL_NO_SURFACE) {
+ egl_surface_t* s = new egl_surface_t(dpy, config, NULL, surface,
+ dp->configs[intptr_t(config)].impl, cnx);
+ return s;
+ }
+ }
+ return EGL_NO_SURFACE;
+}
+
+EGLBoolean eglDestroySurface(EGLDisplay dpy, EGLSurface surface)
+{
+ clearError();
+
+ egl_display_t const * const dp = validate_display(dpy);
+ if (!dp) return EGL_FALSE;
+
+ SurfaceRef _s(surface);
+ if (!_s.get())
+ return setError(EGL_BAD_SURFACE, EGL_FALSE);
+
+ egl_surface_t * const s = get_surface(surface);
+ EGLBoolean result = s->cnx->egl.eglDestroySurface(
+ dp->disp[s->impl].dpy, s->surface);
+ if (result == EGL_TRUE) {
+ if (s->win != NULL) {
+ native_window_set_buffers_geometry(s->win.get(), 0, 0, 0);
+ }
+ _s.terminate();
+ }
+ return result;
+}
+
+EGLBoolean eglQuerySurface( EGLDisplay dpy, EGLSurface surface,
+ EGLint attribute, EGLint *value)
+{
+ clearError();
+
+ egl_display_t const * const dp = validate_display(dpy);
+ if (!dp) return EGL_FALSE;
+
+ SurfaceRef _s(surface);
+ if (!_s.get())
+ return setError(EGL_BAD_SURFACE, EGL_FALSE);
+
+ egl_surface_t const * const s = get_surface(surface);
+ EGLBoolean result(EGL_TRUE);
+ if (attribute == EGL_CONFIG_ID) {
+ // We need to remap EGL_CONFIG_IDs
+ *value = dp->configs[intptr_t(s->config)].configId;
+ } else {
+ result = s->cnx->egl.eglQuerySurface(
+ dp->disp[s->impl].dpy, s->surface, attribute, value);
+ }
+
+ return result;
+}
+
+// ----------------------------------------------------------------------------
+// Contexts
+// ----------------------------------------------------------------------------
+
+EGLContext eglCreateContext(EGLDisplay dpy, EGLConfig config,
+ EGLContext share_list, const EGLint *attrib_list)
+{
+ clearError();
+
+ egl_display_t const* dp = 0;
+ egl_connection_t* cnx = validate_display_config(dpy, config, dp);
+ if (cnx) {
+ if (share_list != EGL_NO_CONTEXT) {
+ egl_context_t* const c = get_context(share_list);
+ share_list = c->context;
+ }
+ EGLContext context = cnx->egl.eglCreateContext(
+ dp->disp[ dp->configs[intptr_t(config)].impl ].dpy,
+ dp->configs[intptr_t(config)].config,
+ share_list, attrib_list);
+ if (context != EGL_NO_CONTEXT) {
+ // figure out if it's a GLESv1 or GLESv2
+ int version = 0;
+ if (attrib_list) {
+ while (*attrib_list != EGL_NONE) {
+ GLint attr = *attrib_list++;
+ GLint value = *attrib_list++;
+ if (attr == EGL_CONTEXT_CLIENT_VERSION) {
+ if (value == 1) {
+ version = GLESv1_INDEX;
+ } else if (value == 2) {
+ version = GLESv2_INDEX;
+ }
+ }
+ };
+ }
+ egl_context_t* c = new egl_context_t(dpy, context, config,
+ dp->configs[intptr_t(config)].impl, cnx, version);
+ return c;
+ }
+ }
+ return EGL_NO_CONTEXT;
+}
+
+EGLBoolean eglDestroyContext(EGLDisplay dpy, EGLContext ctx)
+{
+ clearError();
+
+ egl_display_t const * const dp = validate_display(dpy);
+ if (!dp)
+ return EGL_FALSE;
+
+ ContextRef _c(ctx);
+ if (!_c.get())
+ return setError(EGL_BAD_CONTEXT, EGL_FALSE);
+
+ egl_context_t * const c = get_context(ctx);
+ EGLBoolean result = c->cnx->egl.eglDestroyContext(
+ dp->disp[c->impl].dpy, c->context);
+ if (result == EGL_TRUE) {
+ _c.terminate();
+ }
+ 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)
+{
+ clearError();
+
+ egl_display_t const * const dp = get_display(dpy);
+ if (!dp) return setError(EGL_BAD_DISPLAY, EGL_FALSE);
+
+ // If ctx is not EGL_NO_CONTEXT, read is not EGL_NO_SURFACE, or draw is not
+ // EGL_NO_SURFACE, then an EGL_NOT_INITIALIZED error is generated if dpy is
+ // a valid but uninitialized display.
+ if ( (ctx != EGL_NO_CONTEXT) || (read != EGL_NO_SURFACE) ||
+ (draw != EGL_NO_SURFACE) ) {
+ if (!dp->isReady()) return setError(EGL_NOT_INITIALIZED, EGL_FALSE);
+ }
+
+ // get a reference to the object passed in
+ ContextRef _c(ctx);
+ SurfaceRef _d(draw);
+ SurfaceRef _r(read);
+
+ // validate the context (if not EGL_NO_CONTEXT)
+ if ((ctx != EGL_NO_CONTEXT) && !_c.get()) {
+ // EGL_NO_CONTEXT is valid
+ return EGL_FALSE;
+ }
+
+ // these are the underlying implementation's object
+ EGLContext impl_ctx = EGL_NO_CONTEXT;
+ EGLSurface impl_draw = EGL_NO_SURFACE;
+ EGLSurface impl_read = EGL_NO_SURFACE;
+
+ // these are our objects structs passed in
+ egl_context_t * c = NULL;
+ egl_surface_t const * d = NULL;
+ egl_surface_t const * r = NULL;
+
+ // these are the current objects structs
+ egl_context_t * cur_c = get_context(getContext());
+
+ if (ctx != EGL_NO_CONTEXT) {
+ c = get_context(ctx);
+ impl_ctx = c->context;
+ } else {
+ // no context given, use the implementation of the current context
+ if (cur_c == NULL) {
+ // no current context
+ if (draw != EGL_NO_SURFACE || read != EGL_NO_SURFACE) {
+ // calling eglMakeCurrent( ..., !=0, !=0, EGL_NO_CONTEXT);
+ return setError(EGL_BAD_MATCH, EGL_FALSE);
+ }
+ // not an error, there is just no current context.
+ return EGL_TRUE;
+ }
+ }
+
+ // retrieve the underlying implementation's draw EGLSurface
+ if (draw != EGL_NO_SURFACE) {
+ d = get_surface(draw);
+ // make sure the EGLContext and EGLSurface passed in are for
+ // the same driver
+ if (c && d->impl != c->impl)
+ return setError(EGL_BAD_MATCH, EGL_FALSE);
+ impl_draw = d->surface;
+ }
+
+ // retrieve the underlying implementation's read EGLSurface
+ if (read != EGL_NO_SURFACE) {
+ r = get_surface(read);
+ // make sure the EGLContext and EGLSurface passed in are for
+ // the same driver
+ if (c && r->impl != c->impl)
+ return setError(EGL_BAD_MATCH, EGL_FALSE);
+ 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);
+ }
+
+ if (result == EGL_TRUE) {
+
+ loseCurrent(cur_c);
+
+ if (ctx != EGL_NO_CONTEXT) {
+ setGLHooksThreadSpecific(c->cnx->hooks[c->version]);
+ egl_tls_t::setContext(ctx);
+ if (gEGLDebugLevel > 0) {
+ CreateDbgContext(c->version, c->cnx->hooks[c->version]);
+ }
+ _c.acquire();
+ _r.acquire();
+ _d.acquire();
+ c->read = read;
+ c->draw = draw;
+ } else {
+ setGLHooksThreadSpecific(&gHooksNoContext);
+ egl_tls_t::setContext(EGL_NO_CONTEXT);
+ }
+ }
+ return result;
+}
+
+
+EGLBoolean eglQueryContext( EGLDisplay dpy, EGLContext ctx,
+ EGLint attribute, EGLint *value)
+{
+ clearError();
+
+ egl_display_t const * const dp = validate_display(dpy);
+ if (!dp) return EGL_FALSE;
+
+ ContextRef _c(ctx);
+ if (!_c.get()) return setError(EGL_BAD_CONTEXT, EGL_FALSE);
+
+ egl_context_t * const c = get_context(ctx);
+
+ EGLBoolean result(EGL_TRUE);
+ if (attribute == EGL_CONFIG_ID) {
+ *value = dp->configs[intptr_t(c->config)].configId;
+ } else {
+ // We need to remap EGL_CONFIG_IDs
+ result = c->cnx->egl.eglQueryContext(
+ dp->disp[c->impl].dpy, c->context, attribute, value);
+ }
+
+ return result;
+}
+
+EGLContext eglGetCurrentContext(void)
+{
+ // could be called before eglInitialize(), but we wouldn't have a context
+ // then, and this function would correctly return EGL_NO_CONTEXT.
+
+ clearError();
+
+ EGLContext ctx = getContext();
+ return ctx;
+}
+
+EGLSurface eglGetCurrentSurface(EGLint readdraw)
+{
+ // could be called before eglInitialize(), but we wouldn't have a context
+ // then, and this function would correctly return EGL_NO_SURFACE.
+
+ clearError();
+
+ EGLContext ctx = getContext();
+ if (ctx) {
+ egl_context_t const * const c = get_context(ctx);
+ if (!c) return setError(EGL_BAD_CONTEXT, EGL_NO_SURFACE);
+ switch (readdraw) {
+ case EGL_READ: return c->read;
+ case EGL_DRAW: return c->draw;
+ default: return setError(EGL_BAD_PARAMETER, EGL_NO_SURFACE);
+ }
+ }
+ return EGL_NO_SURFACE;
+}
+
+EGLDisplay eglGetCurrentDisplay(void)
+{
+ // could be called before eglInitialize(), but we wouldn't have a context
+ // then, and this function would correctly return EGL_NO_DISPLAY.
+
+ clearError();
+
+ EGLContext ctx = getContext();
+ if (ctx) {
+ egl_context_t const * const c = get_context(ctx);
+ if (!c) return setError(EGL_BAD_CONTEXT, EGL_NO_SURFACE);
+ return c->dpy;
+ }
+ return EGL_NO_DISPLAY;
+}
+
+EGLBoolean eglWaitGL(void)
+{
+ // could be called before eglInitialize(), but we wouldn't have a context
+ // then, and this function would return GL_TRUE, which isn't wrong.
+
+ clearError();
+
+ EGLBoolean res = EGL_TRUE;
+ EGLContext ctx = getContext();
+ if (ctx) {
+ egl_context_t const * const c = get_context(ctx);
+ if (!c) return setError(EGL_BAD_CONTEXT, EGL_FALSE);
+ if (uint32_t(c->impl)>=2)
+ return setError(EGL_BAD_CONTEXT, EGL_FALSE);
+ egl_connection_t* const cnx = &gEGLImpl[c->impl];
+ if (!cnx->dso)
+ return setError(EGL_BAD_CONTEXT, EGL_FALSE);
+ res = cnx->egl.eglWaitGL();
+ }
+ return res;
+}
+
+EGLBoolean eglWaitNative(EGLint engine)
+{
+ // could be called before eglInitialize(), but we wouldn't have a context
+ // then, and this function would return GL_TRUE, which isn't wrong.
+
+ clearError();
+
+ EGLBoolean res = EGL_TRUE;
+ EGLContext ctx = getContext();
+ if (ctx) {
+ egl_context_t const * const c = get_context(ctx);
+ if (!c) return setError(EGL_BAD_CONTEXT, EGL_FALSE);
+ if (uint32_t(c->impl)>=2)
+ return setError(EGL_BAD_CONTEXT, EGL_FALSE);
+ egl_connection_t* const cnx = &gEGLImpl[c->impl];
+ if (!cnx->dso)
+ return setError(EGL_BAD_CONTEXT, EGL_FALSE);
+ res = cnx->egl.eglWaitNative(engine);
+ }
+ return res;
+}
+
+EGLint eglGetError(void)
+{
+ EGLint result = EGL_SUCCESS;
+ EGLint err;
+ for (int i=0 ; i<IMPL_NUM_IMPLEMENTATIONS ; i++) {
+ err = EGL_SUCCESS;
+ egl_connection_t* const cnx = &gEGLImpl[i];
+ if (cnx->dso)
+ err = cnx->egl.eglGetError();
+ if (err!=EGL_SUCCESS && result==EGL_SUCCESS)
+ result = err;
+ }
+ err = egl_tls_t::getError();
+ if (result == EGL_SUCCESS)
+ result = err;
+ return result;
+}
+
+// Note: Similar implementations of these functions also exist in
+// gl2.cpp and gl.cpp, and are used by applications that call the
+// exported entry points directly.
+typedef void (GL_APIENTRYP PFNGLEGLIMAGETARGETTEXTURE2DOESPROC) (GLenum target, GLeglImageOES image);
+typedef void (GL_APIENTRYP PFNGLEGLIMAGETARGETRENDERBUFFERSTORAGEOESPROC) (GLenum target, GLeglImageOES image);
+
+static PFNGLEGLIMAGETARGETTEXTURE2DOESPROC glEGLImageTargetTexture2DOES_impl = NULL;
+static PFNGLEGLIMAGETARGETRENDERBUFFERSTORAGEOESPROC glEGLImageTargetRenderbufferStorageOES_impl = NULL;
+
+static void glEGLImageTargetTexture2DOES_wrapper(GLenum target, GLeglImageOES image)
+{
+ GLeglImageOES implImage =
+ (GLeglImageOES)egl_get_image_for_current_context((EGLImageKHR)image);
+ glEGLImageTargetTexture2DOES_impl(target, implImage);
+}
+
+static void glEGLImageTargetRenderbufferStorageOES_wrapper(GLenum target, GLeglImageOES image)
+{
+ GLeglImageOES implImage =
+ (GLeglImageOES)egl_get_image_for_current_context((EGLImageKHR)image);
+ glEGLImageTargetRenderbufferStorageOES_impl(target, implImage);
+}
+
+__eglMustCastToProperFunctionPointerType eglGetProcAddress(const char *procname)
+{
+ // eglGetProcAddress() could be the very first function called
+ // in which case we must make sure we've initialized ourselves, this
+ // happens the first time egl_get_display() is called.
+
+ clearError();
+
+ if (egl_init_drivers() == EGL_FALSE) {
+ setError(EGL_BAD_PARAMETER, NULL);
+ return NULL;
+ }
+
+ __eglMustCastToProperFunctionPointerType addr;
+ addr = findProcAddress(procname, sExtentionMap, NELEM(sExtentionMap));
+ if (addr) return addr;
+
+ // this protects accesses to sGLExtentionMap and sGLExtentionSlot
+ pthread_mutex_lock(&sExtensionMapMutex);
+
+ /*
+ * Since eglGetProcAddress() is not associated to anything, it needs
+ * to return a function pointer that "works" regardless of what
+ * the current context is.
+ *
+ * For this reason, we return a "forwarder", a small stub that takes
+ * care of calling the function associated with the context
+ * currently bound.
+ *
+ * We first look for extensions we've already resolved, if we're seeing
+ * this extension for the first time, we go through all our
+ * implementations and call eglGetProcAddress() and record the
+ * result in the appropriate implementation hooks and return the
+ * address of the forwarder corresponding to that hook set.
+ *
+ */
+
+ const String8 name(procname);
+ addr = sGLExtentionMap.valueFor(name);
+ const int slot = sGLExtentionSlot;
+
+ LOGE_IF(slot >= MAX_NUMBER_OF_GL_EXTENSIONS,
+ "no more slots for eglGetProcAddress(\"%s\")",
+ procname);
+
+ if (!addr && (slot < MAX_NUMBER_OF_GL_EXTENSIONS)) {
+ bool found = false;
+ for (int i=0 ; i<IMPL_NUM_IMPLEMENTATIONS ; i++) {
+ egl_connection_t* const cnx = &gEGLImpl[i];
+ if (cnx->dso && cnx->egl.eglGetProcAddress) {
+ found = true;
+ // Extensions are independent of the bound context
+ cnx->hooks[GLESv1_INDEX]->ext.extensions[slot] =
+ cnx->hooks[GLESv2_INDEX]->ext.extensions[slot] =
+#if EGL_TRACE
+ gHooksDebug.ext.extensions[slot] = gHooksTrace.ext.extensions[slot] =
+#endif
+ cnx->egl.eglGetProcAddress(procname);
+ }
+ }
+ if (found) {
+ addr = gExtensionForwarders[slot];
+
+ if (!strcmp(procname, "glEGLImageTargetTexture2DOES")) {
+ glEGLImageTargetTexture2DOES_impl = (PFNGLEGLIMAGETARGETTEXTURE2DOESPROC)addr;
+ addr = (__eglMustCastToProperFunctionPointerType)glEGLImageTargetTexture2DOES_wrapper;
+ }
+ if (!strcmp(procname, "glEGLImageTargetRenderbufferStorageOES")) {
+ glEGLImageTargetRenderbufferStorageOES_impl = (PFNGLEGLIMAGETARGETRENDERBUFFERSTORAGEOESPROC)addr;
+ addr = (__eglMustCastToProperFunctionPointerType)glEGLImageTargetRenderbufferStorageOES_wrapper;
+ }
+
+ sGLExtentionMap.add(name, addr);
+ sGLExtentionSlot++;
+ }
+ }
+
+ pthread_mutex_unlock(&sExtensionMapMutex);
+ return addr;
+}
+
+EGLBoolean eglSwapBuffers(EGLDisplay dpy, EGLSurface draw)
+{
+ EGLBoolean Debug_eglSwapBuffers(EGLDisplay dpy, EGLSurface draw);
+ if (gEGLDebugLevel > 0)
+ Debug_eglSwapBuffers(dpy, draw);
+
+ clearError();
+
+ egl_display_t const * const dp = validate_display(dpy);
+ if (!dp) return EGL_FALSE;
+
+ SurfaceRef _s(draw);
+ if (!_s.get())
+ return setError(EGL_BAD_SURFACE, EGL_FALSE);
+
+ egl_surface_t const * const s = get_surface(draw);
+ return s->cnx->egl.eglSwapBuffers(dp->disp[s->impl].dpy, s->surface);
+}
+
+EGLBoolean eglCopyBuffers( EGLDisplay dpy, EGLSurface surface,
+ NativePixmapType target)
+{
+ clearError();
+
+ egl_display_t const * const dp = validate_display(dpy);
+ if (!dp) return EGL_FALSE;
+
+ SurfaceRef _s(surface);
+ if (!_s.get())
+ return setError(EGL_BAD_SURFACE, EGL_FALSE);
+
+ egl_surface_t const * const s = get_surface(surface);
+ return s->cnx->egl.eglCopyBuffers(
+ dp->disp[s->impl].dpy, s->surface, target);
+}
+
+const char* eglQueryString(EGLDisplay dpy, EGLint name)
+{
+ clearError();
+
+ egl_display_t const * const dp = validate_display(dpy);
+ if (!dp) return (const char *) NULL;
+
+ switch (name) {
+ case EGL_VENDOR:
+ return sVendorString;
+ case EGL_VERSION:
+ return sVersionString;
+ case EGL_EXTENSIONS:
+ return sExtensionString;
+ case EGL_CLIENT_APIS:
+ return sClientApiString;
+ }
+ return setError(EGL_BAD_PARAMETER, (const char *)0);
+}
+
+
+// ----------------------------------------------------------------------------
+// EGL 1.1
+// ----------------------------------------------------------------------------
+
+EGLBoolean eglSurfaceAttrib(
+ EGLDisplay dpy, EGLSurface surface, EGLint attribute, EGLint value)
+{
+ clearError();
+
+ egl_display_t const * const dp = validate_display(dpy);
+ if (!dp) return EGL_FALSE;
+
+ SurfaceRef _s(surface);
+ if (!_s.get())
+ return setError(EGL_BAD_SURFACE, EGL_FALSE);
+
+ egl_surface_t const * const s = get_surface(surface);
+ if (s->cnx->egl.eglSurfaceAttrib) {
+ return s->cnx->egl.eglSurfaceAttrib(
+ dp->disp[s->impl].dpy, s->surface, attribute, value);
+ }
+ return setError(EGL_BAD_SURFACE, EGL_FALSE);
+}
+
+EGLBoolean eglBindTexImage(
+ EGLDisplay dpy, EGLSurface surface, EGLint buffer)
+{
+ clearError();
+
+ egl_display_t const * const dp = validate_display(dpy);
+ if (!dp) return EGL_FALSE;
+
+ SurfaceRef _s(surface);
+ if (!_s.get())
+ return setError(EGL_BAD_SURFACE, EGL_FALSE);
+
+ egl_surface_t const * const s = get_surface(surface);
+ if (s->cnx->egl.eglBindTexImage) {
+ return s->cnx->egl.eglBindTexImage(
+ dp->disp[s->impl].dpy, s->surface, buffer);
+ }
+ return setError(EGL_BAD_SURFACE, EGL_FALSE);
+}
+
+EGLBoolean eglReleaseTexImage(
+ EGLDisplay dpy, EGLSurface surface, EGLint buffer)
+{
+ clearError();
+
+ egl_display_t const * const dp = validate_display(dpy);
+ if (!dp) return EGL_FALSE;
+
+ SurfaceRef _s(surface);
+ if (!_s.get())
+ return setError(EGL_BAD_SURFACE, EGL_FALSE);
+
+ egl_surface_t const * const s = get_surface(surface);
+ if (s->cnx->egl.eglReleaseTexImage) {
+ return s->cnx->egl.eglReleaseTexImage(
+ dp->disp[s->impl].dpy, s->surface, buffer);
+ }
+ return setError(EGL_BAD_SURFACE, EGL_FALSE);
+}
+
+EGLBoolean eglSwapInterval(EGLDisplay dpy, EGLint interval)
+{
+ clearError();
+
+ egl_display_t const * const dp = validate_display(dpy);
+ if (!dp) return EGL_FALSE;
+
+ EGLBoolean res = EGL_TRUE;
+ for (int i=0 ; i<IMPL_NUM_IMPLEMENTATIONS ; i++) {
+ egl_connection_t* const cnx = &gEGLImpl[i];
+ if (cnx->dso) {
+ if (cnx->egl.eglSwapInterval) {
+ if (cnx->egl.eglSwapInterval(
+ dp->disp[i].dpy, interval) == EGL_FALSE) {
+ res = EGL_FALSE;
+ }
+ }
+ }
+ }
+ return res;
+}
+
+
+// ----------------------------------------------------------------------------
+// EGL 1.2
+// ----------------------------------------------------------------------------
+
+EGLBoolean eglWaitClient(void)
+{
+ clearError();
+
+ // could be called before eglInitialize(), but we wouldn't have a context
+ // then, and this function would return GL_TRUE, which isn't wrong.
+ EGLBoolean res = EGL_TRUE;
+ EGLContext ctx = getContext();
+ if (ctx) {
+ egl_context_t const * const c = get_context(ctx);
+ if (!c) return setError(EGL_BAD_CONTEXT, EGL_FALSE);
+ if (uint32_t(c->impl)>=2)
+ return setError(EGL_BAD_CONTEXT, EGL_FALSE);
+ egl_connection_t* const cnx = &gEGLImpl[c->impl];
+ if (!cnx->dso)
+ return setError(EGL_BAD_CONTEXT, EGL_FALSE);
+ if (cnx->egl.eglWaitClient) {
+ res = cnx->egl.eglWaitClient();
+ } else {
+ res = cnx->egl.eglWaitGL();
+ }
+ }
+ return res;
+}
+
+EGLBoolean eglBindAPI(EGLenum api)
+{
+ clearError();
+
+ if (egl_init_drivers() == EGL_FALSE) {
+ return setError(EGL_BAD_PARAMETER, EGL_FALSE);
+ }
+
+ // bind this API on all EGLs
+ EGLBoolean res = EGL_TRUE;
+ for (int i=0 ; i<IMPL_NUM_IMPLEMENTATIONS ; i++) {
+ egl_connection_t* const cnx = &gEGLImpl[i];
+ if (cnx->dso) {
+ if (cnx->egl.eglBindAPI) {
+ if (cnx->egl.eglBindAPI(api) == EGL_FALSE) {
+ res = EGL_FALSE;
+ }
+ }
+ }
+ }
+ return res;
+}
+
+EGLenum eglQueryAPI(void)
+{
+ clearError();
+
+ if (egl_init_drivers() == EGL_FALSE) {
+ return setError(EGL_BAD_PARAMETER, EGL_FALSE);
+ }
+
+ for (int i=0 ; i<IMPL_NUM_IMPLEMENTATIONS ; i++) {
+ egl_connection_t* const cnx = &gEGLImpl[i];
+ if (cnx->dso) {
+ if (cnx->egl.eglQueryAPI) {
+ // the first one we find is okay, because they all
+ // should be the same
+ return cnx->egl.eglQueryAPI();
+ }
+ }
+ }
+ // or, it can only be OpenGL ES
+ return EGL_OPENGL_ES_API;
+}
+
+EGLBoolean eglReleaseThread(void)
+{
+ clearError();
+
+ // If there is context bound to the thread, release it
+ loseCurrent(get_context(getContext()));
+
+ for (int i=0 ; i<IMPL_NUM_IMPLEMENTATIONS ; i++) {
+ egl_connection_t* const cnx = &gEGLImpl[i];
+ if (cnx->dso) {
+ if (cnx->egl.eglReleaseThread) {
+ cnx->egl.eglReleaseThread();
+ }
+ }
+ }
+ egl_tls_t::clearTLS();
+ dbgReleaseThread();
+ return EGL_TRUE;
+}
+
+EGLSurface eglCreatePbufferFromClientBuffer(
+ EGLDisplay dpy, EGLenum buftype, EGLClientBuffer buffer,
+ EGLConfig config, const EGLint *attrib_list)
+{
+ clearError();
+
+ egl_display_t const* dp = 0;
+ egl_connection_t* cnx = validate_display_config(dpy, config, dp);
+ if (!cnx) return EGL_FALSE;
+ if (cnx->egl.eglCreatePbufferFromClientBuffer) {
+ return cnx->egl.eglCreatePbufferFromClientBuffer(
+ dp->disp[ dp->configs[intptr_t(config)].impl ].dpy,
+ buftype, buffer,
+ dp->configs[intptr_t(config)].config, attrib_list);
+ }
+ return setError(EGL_BAD_CONFIG, EGL_NO_SURFACE);
+}
+
+// ----------------------------------------------------------------------------
+// EGL_EGLEXT_VERSION 3
+// ----------------------------------------------------------------------------
+
+EGLBoolean eglLockSurfaceKHR(EGLDisplay dpy, EGLSurface surface,
+ const EGLint *attrib_list)
+{
+ clearError();
+
+ egl_display_t const * const dp = validate_display(dpy);
+ if (!dp) return EGL_FALSE;
+
+ SurfaceRef _s(surface);
+ if (!_s.get())
+ return setError(EGL_BAD_SURFACE, EGL_FALSE);
+
+ egl_surface_t const * const s = get_surface(surface);
+ if (s->cnx->egl.eglLockSurfaceKHR) {
+ return s->cnx->egl.eglLockSurfaceKHR(
+ dp->disp[s->impl].dpy, s->surface, attrib_list);
+ }
+ return setError(EGL_BAD_DISPLAY, EGL_FALSE);
+}
+
+EGLBoolean eglUnlockSurfaceKHR(EGLDisplay dpy, EGLSurface surface)
+{
+ clearError();
+
+ egl_display_t const * const dp = validate_display(dpy);
+ if (!dp) return EGL_FALSE;
+
+ SurfaceRef _s(surface);
+ if (!_s.get())
+ return setError(EGL_BAD_SURFACE, EGL_FALSE);
+
+ egl_surface_t const * const s = get_surface(surface);
+ if (s->cnx->egl.eglUnlockSurfaceKHR) {
+ return s->cnx->egl.eglUnlockSurfaceKHR(
+ dp->disp[s->impl].dpy, s->surface);
+ }
+ return setError(EGL_BAD_DISPLAY, EGL_FALSE);
+}
+
+EGLImageKHR eglCreateImageKHR(EGLDisplay dpy, EGLContext ctx, EGLenum target,
+ EGLClientBuffer buffer, const EGLint *attrib_list)
+{
+ clearError();
+
+ egl_display_t const * const dp = validate_display(dpy);
+ if (!dp) return EGL_NO_IMAGE_KHR;
+
+ if (ctx != EGL_NO_CONTEXT) {
+ ContextRef _c(ctx);
+ if (!_c.get())
+ return setError(EGL_BAD_CONTEXT, EGL_NO_IMAGE_KHR);
+ egl_context_t * const c = get_context(ctx);
+ // since we have an EGLContext, we know which implementation to use
+ EGLImageKHR image = c->cnx->egl.eglCreateImageKHR(
+ dp->disp[c->impl].dpy, c->context, target, buffer, attrib_list);
+ if (image == EGL_NO_IMAGE_KHR)
+ return image;
+
+ egl_image_t* result = new egl_image_t(dpy, ctx);
+ result->images[c->impl] = image;
+ return (EGLImageKHR)result;
+ } else {
+ // EGL_NO_CONTEXT is a valid parameter
+
+ /* Since we don't have a way to know which implementation to call,
+ * we're calling all of them. If at least one of the implementation
+ * succeeded, this is a success.
+ */
+
+ EGLint currentError = eglGetError();
+
+ EGLImageKHR implImages[IMPL_NUM_IMPLEMENTATIONS];
+ bool success = false;
+ for (int i=0 ; i<IMPL_NUM_IMPLEMENTATIONS ; i++) {
+ egl_connection_t* const cnx = &gEGLImpl[i];
+ implImages[i] = EGL_NO_IMAGE_KHR;
+ if (cnx->dso) {
+ if (cnx->egl.eglCreateImageKHR) {
+ implImages[i] = cnx->egl.eglCreateImageKHR(
+ dp->disp[i].dpy, ctx, target, buffer, attrib_list);
+ if (implImages[i] != EGL_NO_IMAGE_KHR) {
+ success = true;
+ }
+ }
+ }
+ }
+
+ if (!success) {
+ // failure, if there was an error when we entered this function,
+ // the error flag must not be updated.
+ // Otherwise, the error is whatever happened in the implementation
+ // that faulted.
+ if (currentError != EGL_SUCCESS) {
+ setError(currentError, EGL_NO_IMAGE_KHR);
+ }
+ return EGL_NO_IMAGE_KHR;
+ } else {
+ // In case of success, we need to clear all error flags
+ // (especially those caused by the implementation that didn't
+ // succeed). TODO: we could avoid this if we knew this was
+ // a "full" success (all implementation succeeded).
+ eglGetError();
+ }
+
+ egl_image_t* result = new egl_image_t(dpy, ctx);
+ memcpy(result->images, implImages, sizeof(implImages));
+ return (EGLImageKHR)result;
+ }
+}
+
+EGLBoolean eglDestroyImageKHR(EGLDisplay dpy, EGLImageKHR img)
+{
+ clearError();
+
+ egl_display_t const * const dp = validate_display(dpy);
+ if (!dp) return EGL_FALSE;
+
+ ImageRef _i(img);
+ if (!_i.get()) return setError(EGL_BAD_PARAMETER, EGL_FALSE);
+
+ egl_image_t* image = get_image(img);
+ bool success = false;
+ for (int i=0 ; i<IMPL_NUM_IMPLEMENTATIONS ; i++) {
+ egl_connection_t* const cnx = &gEGLImpl[i];
+ if (image->images[i] != EGL_NO_IMAGE_KHR) {
+ if (cnx->dso) {
+ if (cnx->egl.eglDestroyImageKHR) {
+ if (cnx->egl.eglDestroyImageKHR(
+ dp->disp[i].dpy, image->images[i])) {
+ success = true;
+ }
+ }
+ }
+ }
+ }
+ if (!success)
+ return EGL_FALSE;
+
+ _i.terminate();
+
+ return EGL_TRUE;
+}
+
+// ----------------------------------------------------------------------------
+// EGL_EGLEXT_VERSION 5
+// ----------------------------------------------------------------------------
+
+
+EGLSyncKHR eglCreateSyncKHR(EGLDisplay dpy, EGLenum type, const EGLint *attrib_list)
+{
+ clearError();
+
+ egl_display_t const * const dp = validate_display(dpy);
+ if (!dp) return EGL_NO_SYNC_KHR;
+
+ EGLContext ctx = eglGetCurrentContext();
+ ContextRef _c(ctx);
+ if (!_c.get())
+ return setError(EGL_BAD_CONTEXT, EGL_NO_SYNC_KHR);
+
+ egl_context_t * const c = get_context(ctx);
+ EGLSyncKHR result = EGL_NO_SYNC_KHR;
+ if (c->cnx->egl.eglCreateSyncKHR) {
+ EGLSyncKHR sync = c->cnx->egl.eglCreateSyncKHR(
+ dp->disp[c->impl].dpy, type, attrib_list);
+ if (sync == EGL_NO_SYNC_KHR)
+ return sync;
+ result = (egl_sync_t*)new egl_sync_t(dpy, ctx, sync);
+ }
+ return (EGLSyncKHR)result;
+}
+
+EGLBoolean eglDestroySyncKHR(EGLDisplay dpy, EGLSyncKHR sync)
+{
+ clearError();
+
+ egl_display_t const * const dp = validate_display(dpy);
+ if (!dp) return EGL_FALSE;
+
+ SyncRef _s(sync);
+ if (!_s.get()) return setError(EGL_BAD_PARAMETER, EGL_FALSE);
+ egl_sync_t* syncObject = get_sync(sync);
+
+ EGLContext ctx = syncObject->context;
+ ContextRef _c(ctx);
+ if (!_c.get())
+ return setError(EGL_BAD_CONTEXT, EGL_FALSE);
+
+ EGLBoolean result = EGL_FALSE;
+ egl_context_t * const c = get_context(ctx);
+ if (c->cnx->egl.eglDestroySyncKHR) {
+ result = c->cnx->egl.eglDestroySyncKHR(
+ dp->disp[c->impl].dpy, syncObject->sync);
+ if (result)
+ _s.terminate();
+ }
+ return result;
+}
+
+EGLint eglClientWaitSyncKHR(EGLDisplay dpy, EGLSyncKHR sync, EGLint flags, EGLTimeKHR timeout)
+{
+ clearError();
+
+ egl_display_t const * const dp = validate_display(dpy);
+ if (!dp) return EGL_FALSE;
+
+ SyncRef _s(sync);
+ if (!_s.get()) return setError(EGL_BAD_PARAMETER, EGL_FALSE);
+ egl_sync_t* syncObject = get_sync(sync);
+
+ EGLContext ctx = syncObject->context;
+ ContextRef _c(ctx);
+ if (!_c.get())
+ return setError(EGL_BAD_CONTEXT, EGL_FALSE);
+
+ egl_context_t * const c = get_context(ctx);
+ if (c->cnx->egl.eglClientWaitSyncKHR) {
+ return c->cnx->egl.eglClientWaitSyncKHR(
+ dp->disp[c->impl].dpy, syncObject->sync, flags, timeout);
+ }
+
+ return EGL_FALSE;
+}
+
+EGLBoolean eglGetSyncAttribKHR(EGLDisplay dpy, EGLSyncKHR sync, EGLint attribute, EGLint *value)
+{
+ clearError();
+
+ egl_display_t const * const dp = validate_display(dpy);
+ if (!dp) return EGL_FALSE;
+
+ SyncRef _s(sync);
+ if (!_s.get())
+ return setError(EGL_BAD_PARAMETER, EGL_FALSE);
+
+ egl_sync_t* syncObject = get_sync(sync);
+ EGLContext ctx = syncObject->context;
+ ContextRef _c(ctx);
+ if (!_c.get())
+ return setError(EGL_BAD_CONTEXT, EGL_FALSE);
+
+ egl_context_t * const c = get_context(ctx);
+ if (c->cnx->egl.eglGetSyncAttribKHR) {
+ return c->cnx->egl.eglGetSyncAttribKHR(
+ dp->disp[c->impl].dpy, syncObject->sync, attribute, value);
+ }
+
+ return EGL_FALSE;
+}
+
+// ----------------------------------------------------------------------------
+// ANDROID extensions
+// ----------------------------------------------------------------------------
+
+EGLBoolean eglSetSwapRectangleANDROID(EGLDisplay dpy, EGLSurface draw,
+ EGLint left, EGLint top, EGLint width, EGLint height)
+{
+ clearError();
+
+ egl_display_t const * const dp = validate_display(dpy);
+ if (!dp) return EGL_FALSE;
+
+ SurfaceRef _s(draw);
+ if (!_s.get())
+ return setError(EGL_BAD_SURFACE, EGL_FALSE);
+
+ egl_surface_t const * const s = get_surface(draw);
+ if (s->cnx->egl.eglSetSwapRectangleANDROID) {
+ return s->cnx->egl.eglSetSwapRectangleANDROID(
+ dp->disp[s->impl].dpy, s->surface, left, top, width, height);
+ }
+ return setError(EGL_BAD_DISPLAY, NULL);
+}
diff --git a/opengl/libs/EGL/egl_display.cpp b/opengl/libs/EGL/egl_display.cpp
new file mode 100644
index 0000000..83aafa6
--- /dev/null
+++ b/opengl/libs/EGL/egl_display.cpp
@@ -0,0 +1,276 @@
+/*
+ ** Copyright 2007, The Android Open Source Project
+ **
+ ** Licensed under the Apache License, Version 2.0 (the "License");
+ ** you may not use this file except in compliance with the License.
+ ** You may obtain a copy of the License at
+ **
+ ** http://www.apache.org/licenses/LICENSE-2.0
+ **
+ ** Unless required by applicable law or agreed to in writing, software
+ ** distributed under the License is distributed on an "AS IS" BASIS,
+ ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ** See the License for the specific language governing permissions and
+ ** limitations under the License.
+ */
+
+#include "egl_display.h"
+#include "egl_object.h"
+#include "egl_tls.h"
+#include "egl_impl.h"
+#include "Loader.h"
+
+// ----------------------------------------------------------------------------
+namespace android {
+// ----------------------------------------------------------------------------
+
+extern void initEglTraceLevel();
+extern void setGLHooksThreadSpecific(gl_hooks_t const *value);
+
+static int cmp_configs(const void* a, const void *b) {
+ const egl_config_t& c0 = *(egl_config_t const *)a;
+ const egl_config_t& c1 = *(egl_config_t const *)b;
+ return c0<c1 ? -1 : (c1<c0 ? 1 : 0);
+}
+
+// ----------------------------------------------------------------------------
+
+egl_display_t egl_display_t::sDisplay[NUM_DISPLAYS];
+
+egl_display_t::egl_display_t() :
+ magic('_dpy'), numTotalConfigs(0), configs(0), refs(0) {
+}
+
+egl_display_t::~egl_display_t() {
+ magic = 0;
+}
+
+egl_display_t* egl_display_t::get(EGLDisplay dpy) {
+ uintptr_t index = uintptr_t(dpy)-1U;
+ return (index >= NUM_DISPLAYS) ? NULL : &sDisplay[index];
+}
+
+void egl_display_t::addObject(egl_object_t* object) {
+ Mutex::Autolock _l(lock);
+ objects.add(object);
+}
+
+void egl_display_t::removeObject(egl_object_t* object) {
+ Mutex::Autolock _l(lock);
+ objects.remove(object);
+}
+
+bool egl_display_t::getObject(egl_object_t* object) {
+ Mutex::Autolock _l(lock);
+ if (objects.indexOf(object) >= 0) {
+ object->incRef();
+ return true;
+ }
+ return false;
+}
+
+EGLDisplay egl_display_t::getFromNativeDisplay(EGLNativeDisplayType disp) {
+ if (uintptr_t(disp) >= NUM_DISPLAYS)
+ return NULL;
+
+ return sDisplay[uintptr_t(disp)].getDisplay(disp);
+}
+
+EGLDisplay egl_display_t::getDisplay(EGLNativeDisplayType display) {
+
+ Mutex::Autolock _l(lock);
+
+ // get our driver loader
+ Loader& loader(Loader::getInstance());
+
+ for (int i = 0; i < IMPL_NUM_IMPLEMENTATIONS; i++) {
+ egl_connection_t* const cnx = &gEGLImpl[i];
+ if (cnx->dso && disp[i].dpy == EGL_NO_DISPLAY) {
+ EGLDisplay dpy = cnx->egl.eglGetDisplay(display);
+ disp[i].dpy = dpy;
+ if (dpy == EGL_NO_DISPLAY) {
+ loader.close(cnx->dso);
+ cnx->dso = NULL;
+ }
+ }
+ }
+
+ return EGLDisplay(uintptr_t(display) + 1U);
+}
+
+EGLBoolean egl_display_t::initialize(EGLint *major, EGLint *minor) {
+
+ Mutex::Autolock _l(lock);
+
+ if (refs > 0) {
+ if (major != NULL)
+ *major = VERSION_MAJOR;
+ if (minor != NULL)
+ *minor = VERSION_MINOR;
+ refs++;
+ return EGL_TRUE;
+ }
+
+#if EGL_TRACE
+
+ // Called both at early_init time and at this time. (Early_init is pre-zygote, so
+ // the information from that call may be stale.)
+ initEglTraceLevel();
+
+#endif
+
+ setGLHooksThreadSpecific(&gHooksNoContext);
+
+ // initialize each EGL and
+ // build our own extension string first, based on the extension we know
+ // and the extension supported by our client implementation
+ for (int i = 0; i < IMPL_NUM_IMPLEMENTATIONS; i++) {
+ egl_connection_t* const cnx = &gEGLImpl[i];
+ cnx->major = -1;
+ cnx->minor = -1;
+ if (!cnx->dso)
+ continue;
+
+#if defined(ADRENO130)
+#warning "Adreno-130 eglInitialize() workaround"
+ /*
+ * The ADRENO 130 driver returns a different EGLDisplay each time
+ * eglGetDisplay() is called, but also makes the EGLDisplay invalid
+ * after eglTerminate() has been called, so that eglInitialize()
+ * cannot be called again. Therefore, we need to make sure to call
+ * eglGetDisplay() before calling eglInitialize();
+ */
+ if (i == IMPL_HARDWARE) {
+ disp[i].dpy =
+ cnx->egl.eglGetDisplay(EGL_DEFAULT_DISPLAY);
+ }
+#endif
+
+ EGLDisplay idpy = disp[i].dpy;
+ if (cnx->egl.eglInitialize(idpy, &cnx->major, &cnx->minor)) {
+ //LOGD("initialized %d dpy=%p, ver=%d.%d, cnx=%p",
+ // i, idpy, cnx->major, cnx->minor, cnx);
+
+ // display is now initialized
+ disp[i].state = egl_display_t::INITIALIZED;
+
+ // get the query-strings for this display for each implementation
+ disp[i].queryString.vendor = cnx->egl.eglQueryString(idpy,
+ EGL_VENDOR);
+ disp[i].queryString.version = cnx->egl.eglQueryString(idpy,
+ EGL_VERSION);
+ disp[i].queryString.extensions = cnx->egl.eglQueryString(idpy,
+ EGL_EXTENSIONS);
+ disp[i].queryString.clientApi = cnx->egl.eglQueryString(idpy,
+ EGL_CLIENT_APIS);
+
+ } else {
+ LOGW("%d: eglInitialize(%p) failed (%s)", i, idpy,
+ egl_tls_t::egl_strerror(cnx->egl.eglGetError()));
+ }
+ }
+
+ EGLBoolean res = EGL_FALSE;
+ for (int i = 0; i < IMPL_NUM_IMPLEMENTATIONS; i++) {
+ egl_connection_t* const cnx = &gEGLImpl[i];
+ if (cnx->dso && cnx->major >= 0 && cnx->minor >= 0) {
+ EGLint n;
+ if (cnx->egl.eglGetConfigs(disp[i].dpy, 0, 0, &n)) {
+ disp[i].config = (EGLConfig*) malloc(sizeof(EGLConfig) * n);
+ if (disp[i].config) {
+ if (cnx->egl.eglGetConfigs(disp[i].dpy, disp[i].config, n,
+ &disp[i].numConfigs)) {
+ numTotalConfigs += n;
+ res = EGL_TRUE;
+ }
+ }
+ }
+ }
+ }
+
+ if (res == EGL_TRUE) {
+ configs = new egl_config_t[numTotalConfigs];
+ for (int i = 0, k = 0; i < IMPL_NUM_IMPLEMENTATIONS; i++) {
+ egl_connection_t* const cnx = &gEGLImpl[i];
+ if (cnx->dso && cnx->major >= 0 && cnx->minor >= 0) {
+ for (int j = 0; j < disp[i].numConfigs; j++) {
+ configs[k].impl = i;
+ configs[k].config = disp[i].config[j];
+ configs[k].configId = k + 1; // CONFIG_ID start at 1
+ // store the implementation's CONFIG_ID
+ cnx->egl.eglGetConfigAttrib(disp[i].dpy, disp[i].config[j],
+ EGL_CONFIG_ID, &configs[k].implConfigId);
+ k++;
+ }
+ }
+ }
+
+ // sort our configurations so we can do binary-searches
+ qsort(configs, numTotalConfigs, sizeof(egl_config_t), cmp_configs);
+
+ refs++;
+ if (major != NULL)
+ *major = VERSION_MAJOR;
+ if (minor != NULL)
+ *minor = VERSION_MINOR;
+ return EGL_TRUE;
+ }
+ return setError(EGL_NOT_INITIALIZED, EGL_FALSE);
+}
+
+EGLBoolean egl_display_t::terminate() {
+
+ Mutex::Autolock _l(lock);
+
+ if (refs == 0) {
+ return setError(EGL_NOT_INITIALIZED, EGL_FALSE);
+ }
+
+ // this is specific to Android, display termination is ref-counted.
+ if (refs > 1) {
+ refs--;
+ return EGL_TRUE;
+ }
+
+ EGLBoolean res = EGL_FALSE;
+ for (int i = 0; i < IMPL_NUM_IMPLEMENTATIONS; i++) {
+ egl_connection_t* const cnx = &gEGLImpl[i];
+ if (cnx->dso && disp[i].state == egl_display_t::INITIALIZED) {
+ if (cnx->egl.eglTerminate(disp[i].dpy) == EGL_FALSE) {
+ LOGW("%d: eglTerminate(%p) failed (%s)", i, disp[i].dpy,
+ egl_tls_t::egl_strerror(cnx->egl.eglGetError()));
+ }
+ // REVISIT: it's unclear what to do if eglTerminate() fails
+ free(disp[i].config);
+
+ disp[i].numConfigs = 0;
+ disp[i].config = 0;
+ disp[i].state = egl_display_t::TERMINATED;
+
+ res = EGL_TRUE;
+ }
+ }
+
+ // Mark all objects remaining in the list as terminated, unless
+ // there are no reference to them, it which case, we're free to
+ // delete them.
+ size_t count = objects.size();
+ LOGW_IF(count, "eglTerminate() called w/ %d objects remaining", count);
+ for (size_t i=0 ; i<count ; i++) {
+ egl_object_t* o = objects.itemAt(i);
+ o->destroy();
+ }
+
+ // this marks all object handles are "terminated"
+ objects.clear();
+
+ refs--;
+ numTotalConfigs = 0;
+ delete[] configs;
+ return res;
+}
+
+
+// ----------------------------------------------------------------------------
+}; // namespace android
+// ----------------------------------------------------------------------------
diff --git a/opengl/libs/EGL/egl_display.h b/opengl/libs/EGL/egl_display.h
new file mode 100644
index 0000000..8c482c3
--- /dev/null
+++ b/opengl/libs/EGL/egl_display.h
@@ -0,0 +1,143 @@
+/*
+ ** Copyright 2007, The Android Open Source Project
+ **
+ ** Licensed under the Apache License, Version 2.0 (the "License");
+ ** you may not use this file except in compliance with the License.
+ ** You may obtain a copy of the License at
+ **
+ ** http://www.apache.org/licenses/LICENSE-2.0
+ **
+ ** Unless required by applicable law or agreed to in writing, software
+ ** distributed under the License is distributed on an "AS IS" BASIS,
+ ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ** See the License for the specific language governing permissions and
+ ** limitations under the License.
+ */
+
+#ifndef ANDROID_EGL_DISPLAY_H
+#define ANDROID_EGL_DISPLAY_H
+
+
+#include <ctype.h>
+#include <stdint.h>
+#include <stdlib.h>
+
+#include <EGL/egl.h>
+#include <EGL/eglext.h>
+#include <GLES/gl.h>
+#include <GLES/glext.h>
+
+#include <utils/SortedVector.h>
+#include <utils/threads.h>
+
+#include "hooks.h"
+
+// ----------------------------------------------------------------------------
+namespace android {
+// ----------------------------------------------------------------------------
+
+class egl_object_t;
+class egl_connection_t;
+
+// ----------------------------------------------------------------------------
+
+struct egl_config_t {
+ egl_config_t() {}
+ egl_config_t(int impl, EGLConfig config)
+ : impl(impl), config(config), configId(0), implConfigId(0) { }
+ int impl; // the implementation this config is for
+ EGLConfig config; // the implementation's EGLConfig
+ EGLint configId; // our CONFIG_ID
+ EGLint implConfigId; // the implementation's CONFIG_ID
+ inline bool operator < (const egl_config_t& rhs) const {
+ if (impl < rhs.impl) return true;
+ if (impl > rhs.impl) return false;
+ return config < rhs.config;
+ }
+};
+
+// ----------------------------------------------------------------------------
+
+class egl_display_t {
+ static egl_display_t sDisplay[NUM_DISPLAYS];
+ EGLDisplay getDisplay(EGLNativeDisplayType display);
+
+public:
+ enum {
+ NOT_INITIALIZED = 0,
+ INITIALIZED = 1,
+ TERMINATED = 2
+ };
+
+ egl_display_t();
+ ~egl_display_t();
+
+ EGLBoolean initialize(EGLint *major, EGLint *minor);
+ EGLBoolean terminate();
+
+ // add object to this display's list
+ void addObject(egl_object_t* object);
+ // remove object from this display's list
+ void removeObject(egl_object_t* object);
+ // add reference to this object. returns true if this is a valid object.
+ bool getObject(egl_object_t* object);
+
+
+ static egl_display_t* get(EGLDisplay dpy);
+ static EGLDisplay getFromNativeDisplay(EGLNativeDisplayType disp);
+
+ inline bool isReady() const { return (refs > 0); }
+ inline bool isValid() const { return magic == '_dpy'; }
+ inline bool isAlive() const { return isValid(); }
+
+ struct strings_t {
+ char const * vendor;
+ char const * version;
+ char const * clientApi;
+ char const * extensions;
+ };
+
+ struct DisplayImpl {
+ DisplayImpl() : dpy(EGL_NO_DISPLAY), config(0),
+ state(NOT_INITIALIZED), numConfigs(0) { }
+ EGLDisplay dpy;
+ EGLConfig* config;
+ EGLint state;
+ EGLint numConfigs;
+ strings_t queryString;
+ };
+
+private:
+ uint32_t magic;
+
+public:
+ DisplayImpl disp[IMPL_NUM_IMPLEMENTATIONS];
+ EGLint numTotalConfigs;
+ egl_config_t* configs;
+
+private:
+ uint32_t refs;
+ Mutex lock;
+ SortedVector<egl_object_t*> objects;
+};
+
+// ----------------------------------------------------------------------------
+
+inline egl_display_t* get_display(EGLDisplay dpy) {
+ return egl_display_t::get(dpy);
+}
+
+// ----------------------------------------------------------------------------
+
+egl_display_t* validate_display(EGLDisplay dpy);
+egl_connection_t* validate_display_config(EGLDisplay dpy,
+ EGLConfig config, egl_display_t const*& dp);
+EGLBoolean validate_display_context(EGLDisplay dpy, EGLContext ctx);
+EGLBoolean validate_display_surface(EGLDisplay dpy, EGLSurface surface);
+
+// ----------------------------------------------------------------------------
+}; // namespace android
+// ----------------------------------------------------------------------------
+
+#endif // ANDROID_EGL_DISPLAY_H
+
diff --git a/opengl/libs/EGL/egl_object.cpp b/opengl/libs/EGL/egl_object.cpp
new file mode 100644
index 0000000..dbf9a01
--- /dev/null
+++ b/opengl/libs/EGL/egl_object.cpp
@@ -0,0 +1,66 @@
+/*
+ ** Copyright 2007, The Android Open Source Project
+ **
+ ** Licensed under the Apache License, Version 2.0 (the "License");
+ ** you may not use this file except in compliance with the License.
+ ** You may obtain a copy of the License at
+ **
+ ** http://www.apache.org/licenses/LICENSE-2.0
+ **
+ ** Unless required by applicable law or agreed to in writing, software
+ ** distributed under the License is distributed on an "AS IS" BASIS,
+ ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ** See the License for the specific language governing permissions and
+ ** limitations under the License.
+ */
+
+#include <ctype.h>
+#include <stdint.h>
+#include <stdlib.h>
+
+#include <EGL/egl.h>
+#include <EGL/eglext.h>
+#include <GLES/gl.h>
+#include <GLES/glext.h>
+
+#include <utils/threads.h>
+
+#include "egl_object.h"
+
+// ----------------------------------------------------------------------------
+namespace android {
+// ----------------------------------------------------------------------------
+
+egl_object_t::egl_object_t(egl_display_t* disp) :
+ display(disp), count(1) {
+ // NOTE: this does an implicit incRef
+ display->addObject(this);
+}
+
+egl_object_t::~egl_object_t() {
+}
+
+void egl_object_t::terminate() {
+ // this marks the object as "terminated"
+ display->removeObject(this);
+ if (decRef() == 1) {
+ // shouldn't happen because this is called from LocalRef
+ LOGE("egl_object_t::terminate() removed the last reference!");
+ }
+}
+
+void egl_object_t::destroy() {
+ if (decRef() == 1) {
+ delete this;
+ }
+}
+
+bool egl_object_t::get() {
+ // used by LocalRef, this does an incRef() atomically with
+ // checking that the object is valid.
+ return display->getObject(this);
+}
+
+// ----------------------------------------------------------------------------
+}; // namespace android
+// ----------------------------------------------------------------------------
diff --git a/opengl/libs/EGL/egl_object.h b/opengl/libs/EGL/egl_object.h
new file mode 100644
index 0000000..3459a8a
--- /dev/null
+++ b/opengl/libs/EGL/egl_object.h
@@ -0,0 +1,235 @@
+/*
+ ** Copyright 2007, The Android Open Source Project
+ **
+ ** Licensed under the Apache License, Version 2.0 (the "License");
+ ** you may not use this file except in compliance with the License.
+ ** You may obtain a copy of the License at
+ **
+ ** http://www.apache.org/licenses/LICENSE-2.0
+ **
+ ** Unless required by applicable law or agreed to in writing, software
+ ** distributed under the License is distributed on an "AS IS" BASIS,
+ ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ** See the License for the specific language governing permissions and
+ ** limitations under the License.
+ */
+
+#ifndef ANDROID_EGL_OBJECT_H
+#define ANDROID_EGL_OBJECT_H
+
+
+#include <ctype.h>
+#include <stdint.h>
+#include <stdlib.h>
+
+#include <EGL/egl.h>
+#include <EGL/eglext.h>
+#include <GLES/gl.h>
+#include <GLES/glext.h>
+
+#include <utils/threads.h>
+
+#include <system/window.h>
+
+#include "egl_display.h"
+
+// ----------------------------------------------------------------------------
+namespace android {
+// ----------------------------------------------------------------------------
+
+struct egl_display_t;
+
+class egl_object_t {
+ egl_display_t *display;
+ mutable volatile int32_t count;
+
+protected:
+ virtual ~egl_object_t();
+
+public:
+ egl_object_t(egl_display_t* display);
+ void destroy();
+
+ inline int32_t incRef() { return android_atomic_inc(&count); }
+ inline int32_t decRef() { return android_atomic_dec(&count); }
+
+private:
+ void terminate();
+ bool get();
+
+public:
+ template <typename N, typename T>
+ class LocalRef {
+ egl_object_t* ref;
+ LocalRef();
+ LocalRef(const LocalRef* rhs);
+ public:
+ ~LocalRef();
+ explicit LocalRef(egl_object_t* rhs);
+ explicit LocalRef(T o) : ref(0) {
+ egl_object_t* native = reinterpret_cast<N*>(o);
+ if (o && native->get()) {
+ ref = native;
+ }
+ }
+ inline N* get() {
+ return static_cast<N*>(ref);
+ }
+ void acquire() const;
+ void release() const;
+ void terminate();
+ };
+ template <typename N, typename T>
+ friend class LocalRef;
+};
+
+template<typename N, typename T>
+egl_object_t::LocalRef<N, T>::LocalRef(egl_object_t* rhs) : ref(rhs) {
+ if (ref) {
+ ref->incRef();
+ }
+}
+
+template <typename N, typename T>
+egl_object_t::LocalRef<N,T>::~LocalRef() {
+ if (ref) {
+ ref->destroy();
+ }
+}
+
+template <typename N, typename T>
+void egl_object_t::LocalRef<N,T>::acquire() const {
+ if (ref) {
+ ref->incRef();
+ }
+}
+
+template <typename N, typename T>
+void egl_object_t::LocalRef<N,T>::release() const {
+ if (ref) {
+ if (ref->decRef() == 1) {
+ // shouldn't happen because this is called from LocalRef
+ LOGE("LocalRef::release() removed the last reference!");
+ }
+ }
+}
+
+template <typename N, typename T>
+void egl_object_t::LocalRef<N,T>::terminate() {
+ if (ref) {
+ ref->terminate();
+ }
+}
+
+// ----------------------------------------------------------------------------
+
+class egl_surface_t: public egl_object_t {
+protected:
+ ~egl_surface_t() {}
+public:
+ typedef egl_object_t::LocalRef<egl_surface_t, EGLSurface> Ref;
+
+ egl_surface_t(EGLDisplay dpy, EGLConfig config, EGLNativeWindowType win,
+ EGLSurface surface, int impl, egl_connection_t const* cnx) :
+ egl_object_t(get_display(dpy)), dpy(dpy), surface(surface),
+ config(config), win(win), impl(impl), cnx(cnx) {
+ }
+ EGLDisplay dpy;
+ EGLSurface surface;
+ EGLConfig config;
+ sp<ANativeWindow> win;
+ int impl;
+ egl_connection_t const* cnx;
+};
+
+class egl_context_t: public egl_object_t {
+protected:
+ ~egl_context_t() {}
+public:
+ 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) {
+ }
+ EGLDisplay dpy;
+ EGLContext context;
+ EGLConfig config;
+ EGLSurface read;
+ EGLSurface draw;
+ int impl;
+ egl_connection_t const* cnx;
+ int version;
+};
+
+class egl_image_t: public egl_object_t {
+protected:
+ ~egl_image_t() {}
+public:
+ typedef egl_object_t::LocalRef<egl_image_t, EGLImageKHR> Ref;
+
+ egl_image_t(EGLDisplay dpy, EGLContext context) :
+ egl_object_t(get_display(dpy)), dpy(dpy), context(context) {
+ memset(images, 0, sizeof(images));
+ }
+ EGLDisplay dpy;
+ EGLContext context;
+ EGLImageKHR images[IMPL_NUM_IMPLEMENTATIONS];
+};
+
+class egl_sync_t: public egl_object_t {
+protected:
+ ~egl_sync_t() {}
+public:
+ typedef egl_object_t::LocalRef<egl_sync_t, EGLSyncKHR> Ref;
+
+ egl_sync_t(EGLDisplay dpy, EGLContext context, EGLSyncKHR sync) :
+ egl_object_t(get_display(dpy)), dpy(dpy), context(context), sync(sync) {
+ }
+ EGLDisplay dpy;
+ EGLContext context;
+ EGLSyncKHR sync;
+};
+
+// ----------------------------------------------------------------------------
+
+typedef egl_surface_t::Ref SurfaceRef;
+typedef egl_context_t::Ref ContextRef;
+typedef egl_image_t::Ref ImageRef;
+typedef egl_sync_t::Ref SyncRef;
+
+// ----------------------------------------------------------------------------
+
+template<typename NATIVE, typename EGL>
+static inline NATIVE* egl_to_native_cast(EGL arg) {
+ return reinterpret_cast<NATIVE*>(arg);
+}
+
+static inline
+egl_surface_t* get_surface(EGLSurface surface) {
+ return egl_to_native_cast<egl_surface_t>(surface);
+}
+
+static inline
+egl_context_t* get_context(EGLContext context) {
+ return egl_to_native_cast<egl_context_t>(context);
+}
+
+static inline
+egl_image_t* get_image(EGLImageKHR image) {
+ return egl_to_native_cast<egl_image_t>(image);
+}
+
+static inline
+egl_sync_t* get_sync(EGLSyncKHR sync) {
+ return egl_to_native_cast<egl_sync_t>(sync);
+}
+
+// ----------------------------------------------------------------------------
+}; // namespace android
+// ----------------------------------------------------------------------------
+
+#endif // ANDROID_EGL_OBJECT_H
+
diff --git a/opengl/libs/EGL/egl_tls.cpp b/opengl/libs/EGL/egl_tls.cpp
new file mode 100644
index 0000000..961a61e
--- /dev/null
+++ b/opengl/libs/EGL/egl_tls.cpp
@@ -0,0 +1,133 @@
+/*
+ ** 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 <pthread.h>
+
+#include <cutils/log.h>
+
+#include <EGL/egl.h>
+
+#include "egl_tls.h"
+
+
+namespace android {
+
+pthread_key_t egl_tls_t::sKey = -1;
+pthread_mutex_t egl_tls_t::sLockKey = PTHREAD_MUTEX_INITIALIZER;
+
+egl_tls_t::egl_tls_t()
+ : error(EGL_SUCCESS), ctx(0), logCallWithNoContext(EGL_TRUE), dbg(0) {
+}
+
+const char *egl_tls_t::egl_strerror(EGLint err) {
+ switch (err) {
+ case EGL_SUCCESS: return "EGL_SUCCESS";
+ case EGL_NOT_INITIALIZED: return "EGL_NOT_INITIALIZED";
+ case EGL_BAD_ACCESS: return "EGL_BAD_ACCESS";
+ case EGL_BAD_ALLOC: return "EGL_BAD_ALLOC";
+ case EGL_BAD_ATTRIBUTE: return "EGL_BAD_ATTRIBUTE";
+ case EGL_BAD_CONFIG: return "EGL_BAD_CONFIG";
+ case EGL_BAD_CONTEXT: return "EGL_BAD_CONTEXT";
+ case EGL_BAD_CURRENT_SURFACE: return "EGL_BAD_CURRENT_SURFACE";
+ case EGL_BAD_DISPLAY: return "EGL_BAD_DISPLAY";
+ case EGL_BAD_MATCH: return "EGL_BAD_MATCH";
+ case EGL_BAD_NATIVE_PIXMAP: return "EGL_BAD_NATIVE_PIXMAP";
+ case EGL_BAD_NATIVE_WINDOW: return "EGL_BAD_NATIVE_WINDOW";
+ case EGL_BAD_PARAMETER: return "EGL_BAD_PARAMETER";
+ case EGL_BAD_SURFACE: return "EGL_BAD_SURFACE";
+ case EGL_CONTEXT_LOST: return "EGL_CONTEXT_LOST";
+ default: return "UNKNOWN";
+ }
+}
+
+void egl_tls_t::validateTLSKey()
+{
+ if (sKey == -1) {
+ pthread_mutex_lock(&sLockKey);
+ if (sKey == -1)
+ pthread_key_create(&sKey, NULL);
+ pthread_mutex_unlock(&sLockKey);
+ }
+}
+
+void egl_tls_t::setErrorEtcImpl(const char* caller, int line, EGLint error) {
+ validateTLSKey();
+ egl_tls_t* tls = getTLS();
+ if (tls->error != error) {
+ LOGE("%s:%d error %x (%s)", caller, line, error, egl_strerror(error));
+ tls->error = error;
+ }
+}
+
+bool egl_tls_t::logNoContextCall() {
+ egl_tls_t* tls = getTLS();
+ if (tls->logCallWithNoContext == true) {
+ tls->logCallWithNoContext = false;
+ return true;
+ }
+ return false;
+}
+
+egl_tls_t* egl_tls_t::getTLS() {
+ egl_tls_t* tls = (egl_tls_t*)pthread_getspecific(sKey);
+ if (tls == 0) {
+ tls = new egl_tls_t;
+ pthread_setspecific(sKey, tls);
+ }
+ return tls;
+}
+
+void egl_tls_t::clearTLS() {
+ if (sKey != -1) {
+ egl_tls_t* tls = (egl_tls_t*)pthread_getspecific(sKey);
+ if (tls) {
+ delete tls;
+ pthread_setspecific(sKey, 0);
+ }
+ }
+}
+
+void egl_tls_t::clearError() {
+ // This must clear the error from all the underlying EGL implementations as
+ // well as the EGL wrapper layer.
+ eglGetError();
+}
+
+EGLint egl_tls_t::getError() {
+ if (sKey == -1)
+ return EGL_SUCCESS;
+ egl_tls_t* tls = (egl_tls_t*)pthread_getspecific(sKey);
+ if (!tls) return EGL_SUCCESS;
+ EGLint error = tls->error;
+ tls->error = EGL_SUCCESS;
+ return error;
+}
+
+void egl_tls_t::setContext(EGLContext ctx) {
+ validateTLSKey();
+ getTLS()->ctx = ctx;
+}
+
+EGLContext egl_tls_t::getContext() {
+ if (sKey == -1)
+ return EGL_NO_CONTEXT;
+ egl_tls_t* tls = (egl_tls_t *)pthread_getspecific(sKey);
+ if (!tls) return EGL_NO_CONTEXT;
+ return tls->ctx;
+}
+
+
+} // namespace android
diff --git a/opengl/libs/EGL/egl_tls.h b/opengl/libs/EGL/egl_tls.h
new file mode 100644
index 0000000..8b31468
--- /dev/null
+++ b/opengl/libs/EGL/egl_tls.h
@@ -0,0 +1,63 @@
+/*
+ ** 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_EGL_TLS_H
+#define ANDROID_EGL_TLS_H
+
+#include <pthread.h>
+
+#include <EGL/egl.h>
+
+namespace android {
+
+class DbgContext;
+
+class egl_tls_t {
+ static pthread_key_t sKey;
+ static pthread_mutex_t sLockKey;
+
+ EGLint error;
+ EGLContext ctx;
+ EGLBoolean logCallWithNoContext;
+ DbgContext* dbg;
+
+ egl_tls_t();
+ static void validateTLSKey();
+ static void setErrorEtcImpl(const char* caller, int line, EGLint error);
+
+public:
+ static egl_tls_t* getTLS();
+ static void clearTLS();
+ static void clearError();
+ static EGLint getError();
+ static void setContext(EGLContext ctx);
+ static EGLContext getContext();
+ static bool logNoContextCall();
+ static const char *egl_strerror(EGLint err);
+
+ template<typename T>
+ static T setErrorEtc(const char* caller,
+ int line, EGLint error, T returnValue) {
+ setErrorEtcImpl(caller, line, error);
+ return returnValue;
+ }
+};
+
+#define setError(_e, _r) egl_tls_t::setErrorEtc(__FUNCTION__, __LINE__, _e, _r)
+
+}; // namespace android
+
+#endif // ANDROID_EGL_TLS_H
diff --git a/opengl/libs/GLES2_dbg/src/dbgcontext.cpp b/opengl/libs/GLES2_dbg/src/dbgcontext.cpp
index 7f5b27b..ff9be3c 100644
--- a/opengl/libs/GLES2_dbg/src/dbgcontext.cpp
+++ b/opengl/libs/GLES2_dbg/src/dbgcontext.cpp
@@ -15,22 +15,18 @@
*/
#include "header.h"
-#include "egl_tls.h"
-extern "C"
-{
+extern "C" {
#include "liblzf/lzf.h"
}
-namespace android
-{
+namespace android {
-pthread_key_t dbgEGLThreadLocalStorageKey = -1;
+static pthread_key_t dbgEGLThreadLocalStorageKey = -1;
+static pthread_mutex_t gThreadLocalStorageKeyMutex = PTHREAD_MUTEX_INITIALIZER;
-DbgContext * getDbgContextThreadSpecific()
-{
- tls_t* tls = (tls_t*)pthread_getspecific(dbgEGLThreadLocalStorageKey);
- return tls->dbg;
+DbgContext * getDbgContextThreadSpecific() {
+ return (DbgContext*)pthread_getspecific(dbgEGLThreadLocalStorageKey);
}
DbgContext::DbgContext(const unsigned version, const gl_hooks_t * const hooks,
@@ -60,10 +56,13 @@
free(lzf_ref[1]);
}
-DbgContext * CreateDbgContext(const pthread_key_t EGLThreadLocalStorageKey,
- const unsigned version, const gl_hooks_t * const hooks)
+DbgContext* CreateDbgContext(const unsigned version, const gl_hooks_t * const hooks)
{
- dbgEGLThreadLocalStorageKey = EGLThreadLocalStorageKey;
+ 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;
@@ -71,7 +70,7 @@
GLint readFormat, readType;
hooks->gl.glGetIntegerv(GL_IMPLEMENTATION_COLOR_READ_FORMAT, &readFormat);
hooks->gl.glGetIntegerv(GL_IMPLEMENTATION_COLOR_READ_TYPE, &readType);
- DbgContext * const dbg = new DbgContext(version, hooks, MAX_VERTEX_ATTRIBS, readFormat, readType);
+ DbgContext* dbg = new DbgContext(version, hooks, MAX_VERTEX_ATTRIBS, readFormat, readType);
glesv2debugger::Message msg, cmd;
msg.set_context_id(reinterpret_cast<int>(dbg));
@@ -88,12 +87,13 @@
msg.set_arg0(GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS);
msg.set_arg1(MAX_COMBINED_TEXTURE_IMAGE_UNITS);
Send(msg, cmd);
+
+ *(DbgContext **)pthread_getspecific(dbgEGLThreadLocalStorageKey) = dbg;
return dbg;
}
-void DestroyDbgContext(DbgContext * const dbg)
-{
- delete dbg;
+void dbgReleaseThread() {
+ delete getDbgContextThreadSpecific();
}
unsigned GetBytesPerPixel(const GLenum format, const GLenum type)
diff --git a/opengl/libs/GLES2_dbg/test/test_server.cpp b/opengl/libs/GLES2_dbg/test/test_server.cpp
index b6401e0..bbbe913 100644
--- a/opengl/libs/GLES2_dbg/test/test_server.cpp
+++ b/opengl/libs/GLES2_dbg/test/test_server.cpp
@@ -16,14 +16,12 @@
#include "header.h"
#include "gtest/gtest.h"
-#include "egl_tls.h"
#include "hooks.h"
namespace android
{
extern FILE * file;
extern unsigned int MAX_FILE_SIZE;
-extern pthread_key_t dbgEGLThreadLocalStorageKey;
};
// tmpfile fails, so need to manually make a writable file first
@@ -114,7 +112,7 @@
};
hooks.gl.glGetError = HookMock::GetError;
hooks.gl.glGetIntegerv = HookMock::GetIntegerv;
- DbgContext * const dbg = CreateDbgContext(-1, 1, &hooks);
+ DbgContext * const dbg = CreateDbgContext(1, &hooks);
ASSERT_TRUE(dbg != NULL);
EXPECT_TRUE(dbg->vertexAttribs != NULL);
@@ -132,7 +130,7 @@
EXPECT_EQ(expectedConstant, read.arg1());
}
CheckNoAvailable();
- DestroyDbgContext(dbg);
+ dbgReleaseThread();
}
void * glNoop()
@@ -143,7 +141,7 @@
class ServerFileContextTest : public ServerFileTest
{
protected:
- tls_t tls;
+ DbgContext* dbg;
gl_hooks_t hooks;
ServerFileContextTest() { }
@@ -153,12 +151,8 @@
virtual void SetUp() {
ServerFileTest::SetUp();
- if (dbgEGLThreadLocalStorageKey == -1)
- pthread_key_create(&dbgEGLThreadLocalStorageKey, NULL);
- ASSERT_NE(-1, dbgEGLThreadLocalStorageKey);
- tls.dbg = new DbgContext(1, &hooks, 32, GL_RGBA, GL_UNSIGNED_BYTE);
- ASSERT_NE((void *)NULL, tls.dbg);
- pthread_setspecific(dbgEGLThreadLocalStorageKey, &tls);
+ dbg = new DbgContext(1, &hooks, 32, GL_RGBA, GL_UNSIGNED_BYTE);
+ ASSERT_NE((void *)NULL, dbg);
for (unsigned int i = 0; i < sizeof(hooks) / sizeof(void *); i++)
((void **)&hooks)[i] = reinterpret_cast<void *>(glNoop);
}
@@ -183,7 +177,7 @@
return ret;
}
} caller;
- const int contextId = reinterpret_cast<int>(tls.dbg);
+ const int contextId = reinterpret_cast<int>(dbg);
glesv2debugger::Message msg, read;
EXPECT_EQ(ret, MessageLoop(caller, msg, msg.glFinish));
@@ -214,25 +208,25 @@
TEST_F(ServerFileContextTest, DisableEnableVertexAttribArray)
{
- Debug_glEnableVertexAttribArray(tls.dbg->MAX_VERTEX_ATTRIBS + 2); // should just ignore invalid index
+ 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(tls.dbg->MAX_VERTEX_ATTRIBS + 2, read.arg0());
+ EXPECT_EQ(dbg->MAX_VERTEX_ATTRIBS + 2, read.arg0());
Read(read);
rewind(file);
- Debug_glDisableVertexAttribArray(tls.dbg->MAX_VERTEX_ATTRIBS + 4); // should just ignore invalid index
+ Debug_glDisableVertexAttribArray(dbg->MAX_VERTEX_ATTRIBS + 4); // should just ignore invalid index
rewind(file);
Read(read);
Read(read);
- for (unsigned int i = 0; i < tls.dbg->MAX_VERTEX_ATTRIBS; i += 5) {
+ for (unsigned int i = 0; i < dbg->MAX_VERTEX_ATTRIBS; i += 5) {
rewind(file);
Debug_glEnableVertexAttribArray(i);
- EXPECT_TRUE(tls.dbg->vertexAttribs[i].enabled);
+ EXPECT_TRUE(dbg->vertexAttribs[i].enabled);
rewind(file);
Read(read);
EXPECT_EQ(read.glEnableVertexAttribArray, read.function());
@@ -241,7 +235,7 @@
rewind(file);
Debug_glDisableVertexAttribArray(i);
- EXPECT_FALSE(tls.dbg->vertexAttribs[i].enabled);
+ EXPECT_FALSE(dbg->vertexAttribs[i].enabled);
rewind(file);
Read(read);
EXPECT_EQ(read.glDisableVertexAttribArray, read.function());
diff --git a/opengl/libs/GLES2_dbg/test/test_socket.cpp b/opengl/libs/GLES2_dbg/test/test_socket.cpp
index 617292e..b2148ac 100644
--- a/opengl/libs/GLES2_dbg/test/test_socket.cpp
+++ b/opengl/libs/GLES2_dbg/test/test_socket.cpp
@@ -19,13 +19,11 @@
#include "header.h"
#include "gtest/gtest.h"
-#include "egl_tls.h"
#include "hooks.h"
namespace android
{
extern int serverSock, clientSock;
-extern pthread_key_t dbgEGLThreadLocalStorageKey;
};
void * glNoop();
@@ -33,7 +31,7 @@
class SocketContextTest : public ::testing::Test
{
protected:
- tls_t tls;
+ DbgContext* dbg;
gl_hooks_t hooks;
int sock;
char * buffer;
@@ -46,12 +44,8 @@
}
virtual void SetUp() {
- if (dbgEGLThreadLocalStorageKey == -1)
- pthread_key_create(&dbgEGLThreadLocalStorageKey, NULL);
- ASSERT_NE(-1, dbgEGLThreadLocalStorageKey);
- tls.dbg = new DbgContext(1, &hooks, 32, GL_RGBA, GL_UNSIGNED_BYTE);
- ASSERT_TRUE(tls.dbg != NULL);
- pthread_setspecific(dbgEGLThreadLocalStorageKey, &tls);
+ dbg = new DbgContext(1, &hooks, 32, GL_RGBA, GL_UNSIGNED_BYTE);
+ ASSERT_TRUE(dbg != NULL);
for (unsigned int i = 0; i < sizeof(hooks) / sizeof(void *); i++)
((void **)&hooks)[i] = (void *)glNoop;
@@ -73,7 +67,7 @@
}
void Write(glesv2debugger::Message & msg) const {
- msg.set_context_id((int)tls.dbg);
+ msg.set_context_id((int)dbg);
msg.set_type(msg.Response);
ASSERT_TRUE(msg.has_context_id());
ASSERT_TRUE(msg.has_function());
@@ -129,7 +123,7 @@
}
} caller;
glesv2debugger::Message msg, read, cmd;
- tls.dbg->expectResponse.Bit(msg.glFinish, true);
+ dbg->expectResponse.Bit(msg.glFinish, true);
cmd.set_function(cmd.SKIP);
cmd.set_expect_response(false);
@@ -158,7 +152,7 @@
}
} caller;
glesv2debugger::Message msg, read, cmd;
- tls.dbg->expectResponse.Bit(msg.glCreateShader, true);
+ dbg->expectResponse.Bit(msg.glCreateShader, true);
cmd.set_function(cmd.CONTINUE);
cmd.set_expect_response(false); // MessageLoop should automatically skip after continue
@@ -204,7 +198,7 @@
glesv2debugger::Message msg, read, cmd;
hooks.gl.glCreateShader = caller.CreateShader;
hooks.gl.glCreateProgram = caller.CreateProgram;
- tls.dbg->expectResponse.Bit(msg.glCreateProgram, true);
+ dbg->expectResponse.Bit(msg.glCreateProgram, true);
cmd.set_function(cmd.glCreateShader);
cmd.set_arg0(GL_FRAGMENT_SHADER);
@@ -272,7 +266,7 @@
glesv2debugger::Message msg, read, cmd;
hooks.gl.glCreateShader = caller.CreateShader;
hooks.gl.glCreateProgram = caller.CreateProgram;
- tls.dbg->expectResponse.Bit(msg.glCreateProgram, false);
+ dbg->expectResponse.Bit(msg.glCreateProgram, false);
cmd.set_function(cmd.SETPROP);
cmd.set_prop(cmd.ExpectResponse);
@@ -305,8 +299,8 @@
EXPECT_EQ((int *)ret, MessageLoop(caller, msg, msg.glCreateProgram));
- EXPECT_TRUE(tls.dbg->expectResponse.Bit(msg.glCreateProgram));
- EXPECT_EQ(819, tls.dbg->captureDraw);
+ EXPECT_TRUE(dbg->expectResponse.Bit(msg.glCreateProgram));
+ EXPECT_EQ(819, dbg->captureDraw);
Read(read);
EXPECT_EQ(read.glCreateProgram, read.function());
@@ -362,7 +356,7 @@
} caller;
glesv2debugger::Message msg, read, cmd;
hooks.gl.glTexImage2D = caller.TexImage2D;
- tls.dbg->expectResponse.Bit(msg.glTexImage2D, false);
+ dbg->expectResponse.Bit(msg.glTexImage2D, false);
Debug_glTexImage2D(_target, _level, _internalformat, _width, _height, _border,
_format, _type, _pixels);
@@ -382,7 +376,7 @@
EXPECT_TRUE(read.has_data());
uint32_t dataLen = 0;
- const unsigned char * data = tls.dbg->Decompress(read.data().data(),
+ const unsigned char * data = dbg->Decompress(read.data().data(),
read.data().length(), &dataLen);
EXPECT_EQ(sizeof(_pixels), dataLen);
if (sizeof(_pixels) == dataLen)
@@ -435,7 +429,7 @@
glesv2debugger::Message msg, read, cmd;
hooks.gl.glCopyTexImage2D = caller.CopyTexImage2D;
hooks.gl.glReadPixels = caller.ReadPixels;
- tls.dbg->expectResponse.Bit(msg.glCopyTexImage2D, false);
+ dbg->expectResponse.Bit(msg.glCopyTexImage2D, false);
Debug_glCopyTexImage2D(_target, _level, _internalformat, _x, _y, _width, _height,
_border);
@@ -459,7 +453,7 @@
EXPECT_EQ(GL_RGBA, read.pixel_format());
EXPECT_EQ(GL_UNSIGNED_BYTE, read.pixel_type());
uint32_t dataLen = 0;
- unsigned char * const data = tls.dbg->Decompress(read.data().data(),
+ 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++)
diff --git a/opengl/libs/egl_impl.h b/opengl/libs/egl_impl.h
index c8f529a..d24b047 100644
--- a/opengl/libs/egl_impl.h
+++ b/opengl/libs/egl_impl.h
@@ -25,6 +25,9 @@
#include "hooks.h"
+#define VERSION_MAJOR 1
+#define VERSION_MINOR 4
+
// ----------------------------------------------------------------------------
namespace android {
// ----------------------------------------------------------------------------
@@ -41,6 +44,8 @@
EGLAPI EGLImageKHR egl_get_image_for_current_context(EGLImageKHR image);
+extern egl_connection_t gEGLImpl[IMPL_NUM_IMPLEMENTATIONS];
+
// ----------------------------------------------------------------------------
}; // namespace android
// ----------------------------------------------------------------------------
diff --git a/opengl/libs/egl_tls.h b/opengl/libs/egl_tls.h
deleted file mode 100644
index 087989a..0000000
--- a/opengl/libs/egl_tls.h
+++ /dev/null
@@ -1,40 +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_EGL_TLS_H
-#define ANDROID_EGL_TLS_H
-
-#include <EGL/egl.h>
-
-#include "glesv2dbg.h"
-
-namespace android
-{
-struct tls_t {
- tls_t() : error(EGL_SUCCESS), ctx(0), logCallWithNoContext(EGL_TRUE), dbg(0) { }
- ~tls_t() {
- if (dbg)
- DestroyDbgContext(dbg);
- }
-
- EGLint error;
- EGLContext ctx;
- EGLBoolean logCallWithNoContext;
- DbgContext* dbg;
-};
-}
-
-#endif
diff --git a/opengl/libs/glesv2dbg.h b/opengl/libs/glesv2dbg.h
index ee2c011..44bc288 100644
--- a/opengl/libs/glesv2dbg.h
+++ b/opengl/libs/glesv2dbg.h
@@ -23,10 +23,9 @@
{
struct DbgContext;
-DbgContext * CreateDbgContext(const pthread_key_t EGLThreadLocalStorageKey,
- const unsigned version, const gl_hooks_t * const hooks);
+DbgContext* CreateDbgContext(const unsigned version, const gl_hooks_t * const hooks);
-void DestroyDbgContext(DbgContext * const dbg);
+void dbgReleaseThread();
// create and bind socket if haven't already, if failed to create socket or
// forceUseFile, then open /data/local/tmp/dump.gles2dbg, exit when size reached
diff --git a/packages/SystemUI/res/drawable-hdpi/recents_bg_protect_tile.png b/packages/SystemUI/res/drawable-hdpi/recents_bg_protect_tile.png
new file mode 100644
index 0000000..87c7be6
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/recents_bg_protect_tile.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/recents_blue_glow.9.png b/packages/SystemUI/res/drawable-hdpi/recents_blue_glow.9.png
new file mode 100644
index 0000000..4f4ae78
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/recents_blue_glow.9.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/recents_callout_line.png b/packages/SystemUI/res/drawable-hdpi/recents_callout_line.png
new file mode 100644
index 0000000..5f4c035
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/recents_callout_line.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/recents_thumbnail_bg.png b/packages/SystemUI/res/drawable-hdpi/recents_thumbnail_bg.png
new file mode 100644
index 0000000..87a67c9
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/recents_thumbnail_bg.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/recents_bg_protect_tile.png b/packages/SystemUI/res/drawable-mdpi/recents_bg_protect_tile.png
new file mode 100644
index 0000000..87c7be6
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/recents_bg_protect_tile.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/recents_blue_glow.9.png b/packages/SystemUI/res/drawable-mdpi/recents_blue_glow.9.png
new file mode 100644
index 0000000..4f4ae78
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/recents_blue_glow.9.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/recents_callout_line.png b/packages/SystemUI/res/drawable-mdpi/recents_callout_line.png
new file mode 100644
index 0000000..5f4c035
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/recents_callout_line.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/recents_thumbnail_bg.png b/packages/SystemUI/res/drawable-mdpi/recents_thumbnail_bg.png
new file mode 100644
index 0000000..87a67c9
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/recents_thumbnail_bg.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/recents_thumbnail_bg_press.png b/packages/SystemUI/res/drawable-mdpi/recents_thumbnail_bg_press.png
new file mode 100644
index 0000000..a1c39e6
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/recents_thumbnail_bg_press.png
Binary files differ
diff --git a/packages/SystemUI/res/layout-land/status_bar_recent_item.xml b/packages/SystemUI/res/layout-land/status_bar_recent_item.xml
new file mode 100644
index 0000000..ce72f04
--- /dev/null
+++ b/packages/SystemUI/res/layout-land/status_bar_recent_item.xml
@@ -0,0 +1,79 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/* apps/common/assets/default/default/skins/StatusBar.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<!-- android:background="@drawable/status_bar_closed_default_background" -->
+<RelativeLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_height="wrap_content"
+ android:layout_width="@dimen/status_bar_recents_thumbnail_view_width">
+
+ <ImageView android:id="@+id/app_thumbnail"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_alignParentLeft="true"
+ android:layout_alignParentTop="true"
+ android:layout_marginLeft="@dimen/status_bar_recents_thumbnail_left_margin"
+ android:scaleType="center"
+ android:background="@drawable/recents_thumbnail_bg_selector"
+ />
+
+ <ImageView android:id="@+id/app_icon"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_alignLeft="@id/app_thumbnail"
+ android:layout_alignTop="@id/app_thumbnail"
+ android:layout_marginLeft="@dimen/status_bar_recents_thumbnail_border_width"
+ android:layout_marginTop="@dimen/status_bar_recents_thumbnail_border_height"
+ android:maxWidth="@dimen/status_bar_recents_thumbnail_max_width"
+ android:maxHeight="@dimen/status_bar_recents_thumbnail_max_height"
+ android:adjustViewBounds="true"
+ />
+
+ <TextView android:id="@+id/app_label"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:textSize="@dimen/status_bar_recents_app_label_text_size"
+ android:fadingEdge="horizontal"
+ android:fadingEdgeLength="@dimen/status_bar_recents_fading_edge_length"
+ android:scrollHorizontally="true"
+ android:layout_alignLeft="@id/app_thumbnail"
+ android:layout_below="@id/app_thumbnail"
+ android:layout_marginTop="@dimen/status_bar_recents_text_description_padding"
+ android:layout_marginLeft="@dimen/status_bar_recents_thumbnail_border_width"
+ android:singleLine="true"
+ android:ellipsize="marquee"
+ />
+
+ <TextView android:id="@+id/app_description"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:textSize="@dimen/status_bar_recents_app_description_text_size"
+ android:fadingEdge="horizontal"
+ android:fadingEdgeLength="@dimen/status_bar_recents_fading_edge_length"
+ android:scrollHorizontally="true"
+ android:layout_alignLeft="@id/app_thumbnail"
+ android:layout_below="@id/app_label"
+ android:layout_marginTop="@dimen/status_bar_recents_text_description_padding"
+ android:layout_marginLeft="@dimen/status_bar_recents_thumbnail_border_width"
+ android:singleLine="true"
+ android:ellipsize="marquee"
+ />
+
+</RelativeLayout>
diff --git a/packages/SystemUI/res/layout-land/status_bar_recent_panel.xml b/packages/SystemUI/res/layout-land/status_bar_recent_panel.xml
new file mode 100644
index 0000000..75f5ee4
--- /dev/null
+++ b/packages/SystemUI/res/layout-land/status_bar_recent_panel.xml
@@ -0,0 +1,84 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/* apps/common/assets/default/default/skins/StatusBar.xml
+**
+** Copyright 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.
+*/
+-->
+
+<com.android.systemui.recent.RecentsPanelView
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/recents_root"
+ android:layout_height="match_parent"
+ android:layout_width="wrap_content">
+
+ <FrameLayout
+ android:id="@+id/recents_bg_protect"
+ android:background="@drawable/recents_bg_protect_tile"
+ android:layout_width="wrap_content"
+ android:layout_height="match_parent"
+ android:layout_alignParentBottom="true"
+ android:layout_alignParentRight="true"
+ android:paddingBottom="@*android:dimen/status_bar_height"
+ android:clipToPadding="false"
+ android:clipChildren="false">
+
+ <LinearLayout android:id="@+id/recents_glow"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="bottom|right"
+ android:background="@drawable/recents_blue_glow"
+ android:orientation="horizontal"
+ android:clipToPadding="false"
+ android:clipChildren="false"
+ >
+ <com.android.systemui.recent.RecentsHorizontalScrollView android:id="@+id/recents_container"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginRight="@dimen/status_bar_recents_right_glow_margin"
+ android:divider="@null"
+ android:stackFromBottom="true"
+ android:fadingEdge="horizontal"
+ android:scrollbars="none"
+ android:fadingEdgeLength="@dimen/status_bar_recents_fading_edge_length"
+ android:listSelector="@drawable/recents_thumbnail_bg_selector"
+ android:layout_gravity="bottom|left"
+ android:orientation="horizontal"
+ android:clipToPadding="false"
+ android:clipChildren="false">
+
+ <LinearLayout android:id="@+id/recents_linear_layout"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:orientation="horizontal"
+ android:clipToPadding="false"
+ android:clipChildren="false">
+ </LinearLayout>
+
+ </com.android.systemui.recent.RecentsHorizontalScrollView>
+
+ </LinearLayout>
+
+ </FrameLayout>
+
+ <View android:id="@+id/recents_dismiss_button"
+ android:layout_width="80px"
+ android:layout_height="@*android:dimen/status_bar_height"
+ android:layout_alignParentBottom="true"
+ android:layout_alignParentLeft="true"
+ android:background="@drawable/ic_sysbar_back_ime"
+ />
+
+</com.android.systemui.recent.RecentsPanelView>
diff --git a/packages/SystemUI/res/layout-large/status_bar_recent_item.xml b/packages/SystemUI/res/layout-large/status_bar_recent_item.xml
index 3f172e6..cd42d7e 100644
--- a/packages/SystemUI/res/layout-large/status_bar_recent_item.xml
+++ b/packages/SystemUI/res/layout-large/status_bar_recent_item.xml
@@ -60,9 +60,9 @@
<TextView android:id="@+id/app_label"
android:layout_width="97dip"
android:layout_height="wrap_content"
- android:textSize="18dip"
+ android:textSize="@dimen/status_bar_recents_app_description_text_size"
android:fadingEdge="horizontal"
- android:fadingEdgeLength="10dip"
+ android:fadingEdgeLength="@dimen/status_bar_recents_fading_edge_length"
android:scrollHorizontally="true"
android:layout_alignParentLeft="true"
android:layout_alignParentTop="true"
@@ -75,9 +75,9 @@
<TextView android:id="@+id/app_description"
android:layout_width="97dip"
android:layout_height="wrap_content"
- android:textSize="18dip"
+ android:textSize="@dimen/status_bar_recents_app_description_text_size"
android:fadingEdge="horizontal"
- android:fadingEdgeLength="10dip"
+ android:fadingEdgeLength="@dimen/status_bar_recents_fading_edge_length"
android:scrollHorizontally="true"
android:layout_alignParentLeft="true"
android:layout_alignParentTop="true"
diff --git a/packages/SystemUI/res/layout-large/status_bar_recent_panel.xml b/packages/SystemUI/res/layout-large/status_bar_recent_panel.xml
index f019e2d..75fdc67 100644
--- a/packages/SystemUI/res/layout-large/status_bar_recent_panel.xml
+++ b/packages/SystemUI/res/layout-large/status_bar_recent_panel.xml
@@ -18,32 +18,23 @@
*/
-->
-<com.android.systemui.statusbar.tablet.RecentAppsPanel
+<com.android.systemui.recent.RecentsPanelView
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/recents_root"
android:layout_height="match_parent"
- android:layout_width="wrap_content">
-
- <CheckBox android:id="@+id/recents_compat_mode"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_alignParentBottom="true"
- android:layout_alignParentRight="true"
- android:layout_marginLeft="16dp"
- android:layout_marginBottom="@*android:dimen/status_bar_height"
- android:background="@drawable/hd"
- android:button="@null"
- />
+ android:layout_width="wrap_content"
+ android:clipToPadding="false"
+ android:clipChildren="false">
<FrameLayout
android:id="@+id/recents_bg_protect"
android:background="@drawable/recents_bg_protect_tile"
android:layout_width="wrap_content"
android:layout_height="match_parent"
- android:layout_toLeftOf="@id/recents_compat_mode"
android:layout_alignParentBottom="true"
android:paddingBottom="@*android:dimen/status_bar_height"
- android:clipToPadding="false">
+ android:clipToPadding="false"
+ android:clipChildren="false">
<LinearLayout android:id="@+id/recents_glow"
android:layout_width="wrap_content"
@@ -52,20 +43,32 @@
android:layout_gravity="bottom"
android:background="@drawable/recents_blue_glow"
android:orientation="horizontal"
+ android:clipToPadding="false"
+ android:clipChildren="false"
>
-
- <ListView android:id="@+id/recents_container"
+ <com.android.systemui.recent.RecentsVerticalScrollView android:id="@+id/recents_container"
android:layout_width="@dimen/status_bar_recents_width"
android:layout_height="wrap_content"
- android:layout_marginRight="100dip"
+ android:layout_marginRight="@dimen/status_bar_recents_right_glow_margin"
android:divider="@null"
- android:scrollingCache="true"
android:stackFromBottom="true"
android:fadingEdge="vertical"
android:scrollbars="none"
android:fadingEdgeLength="20dip"
+ android:layout_gravity="bottom|left"
android:listSelector="@drawable/recents_thumbnail_bg_selector"
- />
+ android:clipToPadding="false"
+ android:clipChildren="false">
+
+ <LinearLayout android:id="@+id/recents_linear_layout"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:orientation="vertical"
+ android:clipToPadding="false"
+ android:clipChildren="false">
+ </LinearLayout>
+
+ </com.android.systemui.recent.RecentsVerticalScrollView>
</LinearLayout>
@@ -79,4 +82,4 @@
android:background="@drawable/ic_sysbar_back_ime"
/>
-</com.android.systemui.statusbar.tablet.RecentAppsPanel>
+</com.android.systemui.recent.RecentsPanelView>
diff --git a/packages/SystemUI/res/layout/status_bar_recent_item.xml b/packages/SystemUI/res/layout/status_bar_recent_item.xml
new file mode 100644
index 0000000..cd42d7e
--- /dev/null
+++ b/packages/SystemUI/res/layout/status_bar_recent_item.xml
@@ -0,0 +1,90 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/* apps/common/assets/default/default/skins/StatusBar.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<!-- android:background="@drawable/status_bar_closed_default_background" -->
+<RelativeLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_height="wrap_content"
+ android:layout_width="@dimen/status_bar_recents_thumbnail_view_width">
+
+ <ImageView android:id="@+id/app_thumbnail"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_alignParentLeft="true"
+ android:layout_alignParentTop="true"
+ android:layout_marginLeft="@dimen/status_bar_recents_thumbnail_left_margin"
+ android:scaleType="center"
+ />
+
+ <ImageView android:id="@+id/app_icon"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_alignParentLeft="true"
+ android:layout_alignParentTop="true"
+ android:layout_marginLeft="131dip"
+ android:layout_marginTop="13dip"
+ android:maxWidth="@dimen/status_bar_recents_thumbnail_max_width"
+ android:maxHeight="@dimen/status_bar_recents_thumbnail_max_height"
+ android:adjustViewBounds="true"
+ />
+
+ <View android:id="@+id/recents_callout_line"
+ android:layout_width="97dip"
+ android:layout_height="1dip"
+ android:layout_alignParentTop="true"
+ android:layout_marginTop="61dip"
+ android:layout_alignParentLeft="true"
+ android:layout_marginLeft="16dip"
+ android:layout_toLeftOf="@id/app_thumbnail"
+ android:layout_marginRight="3dip"
+ android:background="@drawable/recents_callout_line"
+ />
+
+ <TextView android:id="@+id/app_label"
+ android:layout_width="97dip"
+ android:layout_height="wrap_content"
+ android:textSize="@dimen/status_bar_recents_app_description_text_size"
+ android:fadingEdge="horizontal"
+ android:fadingEdgeLength="@dimen/status_bar_recents_fading_edge_length"
+ android:scrollHorizontally="true"
+ android:layout_alignParentLeft="true"
+ android:layout_alignParentTop="true"
+ android:layout_marginLeft="16dip"
+ android:layout_marginTop="32dip"
+ android:singleLine="true"
+ android:ellipsize="marquee"
+ />
+
+ <TextView android:id="@+id/app_description"
+ android:layout_width="97dip"
+ android:layout_height="wrap_content"
+ android:textSize="@dimen/status_bar_recents_app_description_text_size"
+ android:fadingEdge="horizontal"
+ android:fadingEdgeLength="@dimen/status_bar_recents_fading_edge_length"
+ android:scrollHorizontally="true"
+ android:layout_alignParentLeft="true"
+ android:layout_alignParentTop="true"
+ android:layout_marginLeft="16dip"
+ android:layout_marginTop="61dip"
+ android:singleLine="true"
+ android:ellipsize="marquee"
+ />
+
+</RelativeLayout>
diff --git a/packages/SystemUI/res/layout/status_bar_recent_panel.xml b/packages/SystemUI/res/layout/status_bar_recent_panel.xml
new file mode 100644
index 0000000..703cbc1
--- /dev/null
+++ b/packages/SystemUI/res/layout/status_bar_recent_panel.xml
@@ -0,0 +1,84 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/* apps/common/assets/default/default/skins/StatusBar.xml
+**
+** Copyright 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.
+*/
+-->
+
+<com.android.systemui.recent.RecentsPanelView
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/recents_root"
+ android:layout_height="match_parent"
+ android:layout_width="wrap_content">
+
+ <FrameLayout
+ android:id="@+id/recents_bg_protect"
+ android:background="@drawable/recents_bg_protect_tile"
+ android:layout_width="wrap_content"
+ android:layout_height="match_parent"
+ android:layout_alignParentBottom="true"
+ android:paddingBottom="@*android:dimen/status_bar_height"
+ android:clipToPadding="false"
+ android:clipChildren="false">
+
+ <LinearLayout android:id="@+id/recents_glow"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginBottom="-49dip"
+ android:layout_gravity="bottom"
+ android:background="@drawable/recents_blue_glow"
+ android:orientation="horizontal"
+ android:clipToPadding="false"
+ android:clipChildren="false"
+ >
+ <com.android.systemui.recent.RecentsVerticalScrollView android:id="@+id/recents_container"
+ android:layout_width="@dimen/status_bar_recents_width"
+ android:layout_height="wrap_content"
+ android:layout_marginRight="@dimen/status_bar_recents_right_glow_margin"
+ android:divider="@null"
+ android:stackFromBottom="true"
+ android:fadingEdge="vertical"
+ android:scrollbars="none"
+ android:fadingEdgeLength="20dip"
+ android:listSelector="@drawable/recents_thumbnail_bg_selector"
+ android:layout_gravity="bottom|left"
+ android:clipToPadding="false"
+ android:clipChildren="false">
+
+ <LinearLayout android:id="@+id/recents_linear_layout"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:orientation="vertical"
+ android:clipToPadding="false"
+ android:clipChildren="false">
+ </LinearLayout>
+
+ </com.android.systemui.recent.RecentsVerticalScrollView>
+
+
+ </LinearLayout>
+
+ </FrameLayout>
+
+ <View android:id="@+id/recents_dismiss_button"
+ android:layout_width="80px"
+ android:layout_height="@*android:dimen/status_bar_height"
+ android:layout_alignParentBottom="true"
+ android:layout_alignParentLeft="true"
+ android:background="@drawable/ic_sysbar_back_ime"
+ />
+
+</com.android.systemui.recent.RecentsPanelView>
diff --git a/packages/SystemUI/res/values-en-rGB-large/strings.xml b/packages/SystemUI/res/values-en-rGB-large/strings.xml
new file mode 100644
index 0000000..aec6899
--- /dev/null
+++ b/packages/SystemUI/res/values-en-rGB-large/strings.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+/**
+ * Copyright (c) 2010, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+ -->
+
+<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">"Clear all"</string>
+ <string name="status_bar_settings_signal_meter_disconnected" msgid="383145178755329067">"No Internet connection"</string>
+ <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="2535465294437586528">"Wi-Fi connected"</string>
+ <string name="gps_notification_searching_text" msgid="4467935186864208249">"Searching for GPS"</string>
+ <string name="gps_notification_found_text" msgid="6270628388918822956">"Location set by GPS"</string>
+ <string name="notifications_off_title" msgid="1860117696034775851">"Notifications off"</string>
+ <string name="notifications_off_text" msgid="1439152806320786912">"Tap here to turn notifications back on."</string>
+</resources>
diff --git a/packages/SystemUI/res/values-it-large/strings.xml b/packages/SystemUI/res/values-it-large/strings.xml
new file mode 100644
index 0000000..3cde529
--- /dev/null
+++ b/packages/SystemUI/res/values-it-large/strings.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+/**
+ * Copyright (c) 2010, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+ -->
+
+<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">"Cancella tutto"</string>
+ <string name="status_bar_settings_signal_meter_disconnected" msgid="383145178755329067">"Nessuna conness. Internet"</string>
+ <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="2535465294437586528">"Wi-Fi connesso"</string>
+ <string name="gps_notification_searching_text" msgid="4467935186864208249">"Ricerca del GPS"</string>
+ <string name="gps_notification_found_text" msgid="6270628388918822956">"Posizione stabilita dal GPS"</string>
+ <string name="notifications_off_title" msgid="1860117696034775851">"Notifiche disattivate"</string>
+ <string name="notifications_off_text" msgid="1439152806320786912">"Tocca qui per riattivare le notifiche."</string>
+</resources>
diff --git a/packages/SystemUI/res/values-land/dimens.xml b/packages/SystemUI/res/values-land/dimens.xml
index bcc8da1..6f1453e 100644
--- a/packages/SystemUI/res/values-land/dimens.xml
+++ b/packages/SystemUI/res/values-land/dimens.xml
@@ -18,4 +18,20 @@
<resources>
<!-- thickness (width) of the navigation bar on phones that require it -->
<dimen name="navigation_bar_size">42dp</dimen>
+
+ <!-- Recent Applications parameters -->
+ <!-- Width of a recent app view, including all content -->
+ <dimen name="status_bar_recents_thumbnail_view_width">156dp</dimen>
+ <!-- How far the thumbnail for a recent app appears from left edge -->
+ <dimen name="status_bar_recents_thumbnail_left_margin">0dp</dimen>
+ <!-- Width of scrollable area in recents -->
+ <dimen name="status_bar_recents_width">128dp</dimen>
+ <!-- Thumbnail border width -->
+ <dimen name="status_bar_recents_thumbnail_border_width">8dp</dimen>
+ <!-- Thumbnail border height -->
+ <dimen name="status_bar_recents_thumbnail_border_height">12dp</dimen>
+ <!-- Padding for text descriptions -->
+ <dimen name="status_bar_recents_text_description_padding">8dp</dimen>
+ <!-- Margin between recents container and glow on the right -->
+ <dimen name="status_bar_recents_right_glow_margin">0dip</dimen>
</resources>
diff --git a/packages/SystemUI/res/values-large/dimens.xml b/packages/SystemUI/res/values-large/dimens.xml
index 9d89e21..f8a4a1c 100644
--- a/packages/SystemUI/res/values-large/dimens.xml
+++ b/packages/SystemUI/res/values-large/dimens.xml
@@ -22,6 +22,32 @@
<dimen name="status_bar_panel_bottom_offset">36dp</dimen>
<!-- gap on either side of status bar notification icons -->
<dimen name="status_bar_icon_padding">8dp</dimen>
+
+ <!-- Recent Applications parameters -->
+ <!-- Width of a recent app view, including all content -->
+ <dimen name="status_bar_recents_thumbnail_view_width">156dp</dimen>
+ <!-- How far the thumbnail for a recent app appears from left edge -->
+ <dimen name="status_bar_recents_thumbnail_left_margin">110dp</dimen>
+ <!-- Upper width limit for application icon -->
+ <dimen name="status_bar_recents_thumbnail_max_width">64dp</dimen>
+ <!-- Upper height limit for application icon -->
+ <dimen name="status_bar_recents_thumbnail_max_height">64dp</dimen>
+ <!-- Width of scrollable area in recents -->
+ <dimen name="status_bar_recents_width">356dp</dimen>
+ <!-- Thumbnail border width -->
+ <dimen name="status_bar_recents_thumbnail_border_width">12dp</dimen>
+ <!-- Thumbnail border height -->
+ <dimen name="status_bar_recents_thumbnail_border_height">12dp</dimen>
+ <!-- Padding for text descriptions -->
+ <dimen name="status_bar_recents_text_description_padding">8dp</dimen>
+ <!-- Size of application label text -->
+ <dimen name="status_bar_recents_app_label_text_size">18dip</dimen>
+ <!-- Size of application description text -->
+ <dimen name="status_bar_recents_app_description_text_size">18dip</dimen>
+ <!-- Size of fading edge for scroll effect -->
+ <dimen name="status_bar_recents_fading_edge_length">20dip</dimen>
+ <!-- Margin between recents container and glow on the right -->
+ <dimen name="status_bar_recents_right_glow_margin">100dip</dimen>
</resources>
diff --git a/packages/SystemUI/res/values-vi-large/strings.xml b/packages/SystemUI/res/values-vi-large/strings.xml
new file mode 100644
index 0000000..569d70f
--- /dev/null
+++ b/packages/SystemUI/res/values-vi-large/strings.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+/**
+ * Copyright (c) 2010, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+ -->
+
+<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">"Xóa tất cả"</string>
+ <string name="status_bar_settings_signal_meter_disconnected" msgid="383145178755329067">"Không có k.nối Internet"</string>
+ <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="2535465294437586528">"Đã kết nối Wi-Fi"</string>
+ <string name="gps_notification_searching_text" msgid="4467935186864208249">"Đang tìm kiếm GPS"</string>
+ <string name="gps_notification_found_text" msgid="6270628388918822956">"Vị trí đặt bởi GPS"</string>
+ <string name="notifications_off_title" msgid="1860117696034775851">"Tắt thông báo"</string>
+ <string name="notifications_off_text" msgid="1439152806320786912">"Chạm vào đây để bật lại thông báo."</string>
+</resources>
diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml
index c0c39d0..954a871 100644
--- a/packages/SystemUI/res/values/config.xml
+++ b/packages/SystemUI/res/values/config.xml
@@ -40,7 +40,7 @@
<!-- Whether a software navigation bar should be shown. NOTE: in the future this may be
autodetected from the Configuration. -->
- <bool name="config_showNavigationBar">true</bool>
+ <bool name="config_showNavigationBar">false</bool>
</resources>
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index a2577cb..657dc46 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -30,6 +30,20 @@
<dimen name="status_bar_recents_thumbnail_max_height">64dp</dimen>
<!-- Width of scrollable area in recents -->
<dimen name="status_bar_recents_width">356dp</dimen>
+ <!-- Thumbnail border width -->
+ <dimen name="status_bar_recents_thumbnail_border_width">12dp</dimen>
+ <!-- Thumbnail border height -->
+ <dimen name="status_bar_recents_thumbnail_border_height">12dp</dimen>
+ <!-- Padding for text descriptions -->
+ <dimen name="status_bar_recents_text_description_padding">8dp</dimen>
+ <!-- Size of application label text -->
+ <dimen name="status_bar_recents_app_label_text_size">18dip</dimen>
+ <!-- Size of application description text -->
+ <dimen name="status_bar_recents_app_description_text_size">18dip</dimen>
+ <!-- Size of fading edge for scroll effect -->
+ <dimen name="status_bar_recents_fading_edge_length">20dip</dimen>
+ <!-- Margin between recents container and glow on the right -->
+ <dimen name="status_bar_recents_right_glow_margin">100dip</dimen>
<!-- thickness (height) of the navigation bar on phones that require it -->
<dimen name="navigation_bar_size">42dp</dimen>
diff --git a/packages/SystemUI/src/com/android/systemui/recent/Choreographer.java b/packages/SystemUI/src/com/android/systemui/recent/Choreographer.java
new file mode 100644
index 0000000..b876075
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/recent/Choreographer.java
@@ -0,0 +1,131 @@
+/*
+ * 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.systemui.recent;
+
+import android.animation.Animator;
+import android.animation.AnimatorSet;
+import android.animation.ObjectAnimator;
+import android.util.Log;
+import android.util.Slog;
+import android.view.View;
+
+/* package */ class Choreographer implements Animator.AnimatorListener {
+ // should group this into a multi-property animation
+ private static final int OPEN_DURATION = 136;
+ private static final int CLOSE_DURATION = 250;
+ private static final String TAG = RecentsPanelView.TAG;
+ private static final boolean DEBUG = RecentsPanelView.DEBUG;
+
+ boolean mVisible;
+ int mPanelHeight;
+ View mRootView;
+ View mScrimView;
+ View mContentView;
+ AnimatorSet mContentAnim;
+
+ // the panel will start to appear this many px from the end
+ final int HYPERSPACE_OFFRAMP = 200;
+
+ public Choreographer(View root, View scrim, View content) {
+ mRootView = root;
+ mScrimView = scrim;
+ mContentView = content;
+ }
+
+ void createAnimation(boolean appearing) {
+ float start, end;
+
+ if (RecentsPanelView.DEBUG) Log.e(TAG, "createAnimation()", new Exception());
+
+ // 0: on-screen
+ // height: off-screen
+ float y = mContentView.getTranslationY();
+ if (appearing) {
+ // we want to go from near-the-top to the top, unless we're half-open in the right
+ // general vicinity
+ start = (y < HYPERSPACE_OFFRAMP) ? y : HYPERSPACE_OFFRAMP;
+ end = 0;
+ } else {
+ start = y;
+ end = y + HYPERSPACE_OFFRAMP;
+ }
+
+ Animator posAnim = ObjectAnimator.ofFloat(mContentView, "translationY",
+ start, end);
+ posAnim.setInterpolator(appearing
+ ? new android.view.animation.DecelerateInterpolator(2.5f)
+ : new android.view.animation.AccelerateInterpolator(2.5f));
+
+ Animator glowAnim = ObjectAnimator.ofFloat(mContentView, "alpha",
+ mContentView.getAlpha(), appearing ? 1.0f : 0.0f);
+ glowAnim.setInterpolator(appearing
+ ? new android.view.animation.AccelerateInterpolator(1.0f)
+ : new android.view.animation.DecelerateInterpolator(1.0f));
+
+ Animator bgAnim = ObjectAnimator.ofInt(mScrimView.getBackground(),
+ "alpha", appearing ? 0 : 255, appearing ? 255 : 0);
+
+ mContentAnim = new AnimatorSet();
+ mContentAnim
+ .play(bgAnim)
+ .with(glowAnim)
+ .with(posAnim);
+ mContentAnim.setDuration(appearing ? OPEN_DURATION : CLOSE_DURATION);
+ mContentAnim.addListener(this);
+ }
+
+ void startAnimation(boolean appearing) {
+ if (DEBUG) Slog.d(TAG, "startAnimation(appearing=" + appearing + ")");
+
+ createAnimation(appearing);
+
+ mContentView.setLayerType(View.LAYER_TYPE_HARDWARE, null);
+ mContentAnim.start();
+
+ mVisible = appearing;
+ }
+
+ void jumpTo(boolean appearing) {
+ mContentView.setTranslationY(appearing ? 0 : mPanelHeight);
+ }
+
+ public void setPanelHeight(int h) {
+ if (DEBUG) Slog.d(TAG, "panelHeight=" + h);
+ mPanelHeight = h;
+ }
+
+ public void onAnimationCancel(Animator animation) {
+ if (DEBUG) Slog.d(TAG, "onAnimationCancel");
+ // force this to zero so we close the window
+ mVisible = false;
+ }
+
+ public void onAnimationEnd(Animator animation) {
+ if (DEBUG) Slog.d(TAG, "onAnimationEnd");
+ if (!mVisible) {
+ mRootView.setVisibility(View.GONE);
+ }
+ mContentView.setLayerType(View.LAYER_TYPE_NONE, null);
+ mContentAnim = null;
+ }
+
+ public void onAnimationRepeat(Animator animation) {
+ }
+
+ public void onAnimationStart(Animator animation) {
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/recent/RecentsCallback.java b/packages/SystemUI/src/com/android/systemui/recent/RecentsCallback.java
new file mode 100644
index 0000000..5d29e2a
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/recent/RecentsCallback.java
@@ -0,0 +1,30 @@
+/*
+ * 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.systemui.recent;
+
+import android.view.View;
+
+public interface RecentsCallback {
+ static final int SWIPE_LEFT = 0;
+ static final int SWIPE_RIGHT = 1;
+ static final int SWIPE_UP = 2;
+ static final int SWIPE_DOWN = 3;
+
+ void handleOnClick(View selectedView);
+ void handleSwipe(View selectedView, int direction);
+ void handleLongPress(View selectedView);
+}
diff --git a/packages/SystemUI/src/com/android/systemui/recent/RecentsHorizontalScrollView.java b/packages/SystemUI/src/com/android/systemui/recent/RecentsHorizontalScrollView.java
new file mode 100644
index 0000000..194c9d1
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/recent/RecentsHorizontalScrollView.java
@@ -0,0 +1,307 @@
+/*
+ * 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.systemui.recent;
+
+import com.android.systemui.recent.RecentsPanelView.ActvityDescriptionAdapter;
+
+import android.animation.Animator;
+import android.animation.Animator.AnimatorListener;
+import android.animation.LayoutTransition;
+import android.animation.ObjectAnimator;
+import android.animation.ValueAnimator;
+import android.animation.ValueAnimator.AnimatorUpdateListener;
+import android.content.Context;
+import android.database.DataSetObserver;
+import android.graphics.RectF;
+import android.util.AttributeSet;
+import android.util.Log;
+import android.view.LayoutInflater;
+import android.view.MotionEvent;
+import android.view.VelocityTracker;
+import android.view.View;
+import android.view.animation.DecelerateInterpolator;
+import android.view.animation.LinearInterpolator;
+import android.widget.HorizontalScrollView;
+import android.widget.LinearLayout;
+
+import com.android.systemui.R;
+
+public class RecentsHorizontalScrollView extends HorizontalScrollView
+ implements View.OnClickListener, View.OnTouchListener {
+ private static final float FADE_CONSTANT = 0.5f;
+ private static final int SNAP_BACK_DURATION = 250;
+ private static final int ESCAPE_VELOCITY = 100; // speed of item required to "curate" it
+ private static final String TAG = RecentsPanelView.TAG;
+ private static final float THRESHHOLD = 50;
+ private static final boolean DEBUG_INVALIDATE = false;
+ private LinearLayout mLinearLayout;
+ private ActvityDescriptionAdapter mAdapter;
+ private RecentsCallback mCallback;
+ protected int mLastScrollPosition;
+ private View mCurrentView;
+ private float mLastY;
+ private boolean mDragging;
+ private VelocityTracker mVelocityTracker;
+
+ public RecentsHorizontalScrollView(Context context) {
+ this(context, null);
+ }
+
+ public RecentsHorizontalScrollView(Context context, AttributeSet attrs) {
+ super(context, attrs, 0);
+ }
+
+ private int scrollPositionOfMostRecent() {
+ return mLinearLayout.getWidth() - getWidth();
+ }
+
+ public void update() {
+ mLinearLayout.removeAllViews();
+ for (int i = 0; i < mAdapter.getCount(); i++) {
+ View view = mAdapter.getView(i, null, mLinearLayout);
+ view.setClickable(true);
+ view.setOnClickListener(this);
+ view.setOnTouchListener(this);
+ mLinearLayout.addView(view);
+ }
+ // Scroll to end after layout.
+ post(new Runnable() {
+ public void run() {
+ mLastScrollPosition = scrollPositionOfMostRecent();
+ scrollTo(mLastScrollPosition, 0);
+ }
+ });
+ }
+
+ @Override
+ public boolean onInterceptTouchEvent(MotionEvent ev) {
+ if (mVelocityTracker == null) {
+ mVelocityTracker = VelocityTracker.obtain();
+ }
+ mVelocityTracker.addMovement(ev);
+ switch (ev.getAction()) {
+ case MotionEvent.ACTION_DOWN:
+ mDragging = false;
+ mLastY = ev.getY();
+ break;
+
+ case MotionEvent.ACTION_MOVE:
+ float delta = ev.getY() - mLastY;
+ if (Math.abs(delta) > THRESHHOLD) {
+ mDragging = true;
+ }
+ break;
+
+ case MotionEvent.ACTION_UP:
+ mDragging = false;
+ break;
+ }
+ return mDragging ? true : super.onInterceptTouchEvent(ev);
+ }
+
+ private float getAlphaForOffset(View view, float thumbHeight) {
+ final float fadeHeight = FADE_CONSTANT * thumbHeight;
+ float result = 1.0f;
+ if (view.getY() >= thumbHeight) {
+ result = 1.0f - (view.getY() - thumbHeight) / fadeHeight;
+ } else if (view.getY() < 0.0f) {
+ result = 1.0f + (thumbHeight + view.getY()) / fadeHeight;
+ }
+ return result;
+ }
+
+ @Override
+ public boolean onTouchEvent(MotionEvent ev) {
+ if (!mDragging) {
+ return super.onTouchEvent(ev);
+ }
+
+ mVelocityTracker.addMovement(ev);
+
+ final View animView = mCurrentView;
+ // TODO: Cache thumbnail
+ final View thumb = animView.findViewById(R.id.app_thumbnail);
+ switch (ev.getAction()) {
+ case MotionEvent.ACTION_MOVE:
+ if (animView != null) {
+ final float delta = ev.getY() - mLastY;
+ animView.setY(animView.getY() + delta);
+ animView.setAlpha(getAlphaForOffset(animView, thumb.getHeight()));
+ invalidateGlobalRegion(animView);
+ }
+ mLastY = ev.getY();
+ break;
+
+ case MotionEvent.ACTION_UP:
+ final ObjectAnimator anim;
+ if (animView != null) {
+ final VelocityTracker velocityTracker = mVelocityTracker;
+ velocityTracker.computeCurrentVelocity(1000, 10000);
+ final float velocityX = velocityTracker.getXVelocity();
+ final float velocityY = velocityTracker.getYVelocity();
+ final float curY = animView.getY();
+ final float newY = (velocityY >= 0.0f ? 1 : -1) * animView.getHeight();
+
+ if (Math.abs(velocityY) > Math.abs(velocityX)
+ && Math.abs(velocityY) > ESCAPE_VELOCITY
+ && (velocityY >= 0.0f) == (animView.getY() >= 0)) {
+ final long duration =
+ (long) (Math.abs(newY - curY) * 1000.0f / Math.abs(velocityY));
+ anim = ObjectAnimator.ofFloat(animView, "y", curY, newY);
+ anim.setInterpolator(new LinearInterpolator());
+ final int swipeDirection = animView.getY() >= 0.0f ?
+ RecentsCallback.SWIPE_RIGHT : RecentsCallback.SWIPE_LEFT;
+ anim.addListener(new AnimatorListener() {
+ public void onAnimationStart(Animator animation) {
+ }
+ public void onAnimationRepeat(Animator animation) {
+ }
+ public void onAnimationEnd(Animator animation) {
+ mLinearLayout.removeView(mCurrentView);
+ mCallback.handleSwipe(animView, swipeDirection);
+ }
+ public void onAnimationCancel(Animator animation) {
+ mLinearLayout.removeView(mCurrentView);
+ mCallback.handleSwipe(animView, swipeDirection);
+ }
+ });
+ anim.setDuration(duration);
+ } else { // Animate back to position
+ final long duration = Math.abs(velocityY) > 0.0f ?
+ (long) (Math.abs(newY - curY) * 1000.0f / Math.abs(velocityY))
+ : SNAP_BACK_DURATION;
+ anim = ObjectAnimator.ofFloat(animView, "y", animView.getY(), 0.0f);
+ anim.setInterpolator(new DecelerateInterpolator(2.0f));
+ anim.setDuration(duration);
+ }
+
+ anim.addUpdateListener(new AnimatorUpdateListener() {
+ public void onAnimationUpdate(ValueAnimator animation) {
+ animView.setAlpha(getAlphaForOffset(animView, thumb.getHeight()));
+ invalidateGlobalRegion(animView);
+ }
+ });
+ anim.start();
+ }
+
+ mVelocityTracker.recycle();
+ mVelocityTracker = null;
+ break;
+ }
+ return true;
+ }
+
+ void invalidateGlobalRegion(View view) {
+ RectF childBounds
+ = new RectF(view.getLeft(), view.getTop(), view.getRight(), view.getBottom());
+ childBounds.offset(view.getX(), view.getY());
+ if (DEBUG_INVALIDATE) Log.v(TAG, "-------------");
+ while (view.getParent() != null && view.getParent() instanceof View) {
+ view = (View) view.getParent();
+ view.getMatrix().mapRect(childBounds);
+ view.invalidate((int) Math.floor(childBounds.left),
+ (int) Math.floor(childBounds.top),
+ (int) Math.ceil(childBounds.right),
+ (int) Math.ceil(childBounds.bottom));
+ if (DEBUG_INVALIDATE) {
+ Log.v(TAG, "INVALIDATE(" + (int) Math.floor(childBounds.left)
+ + "," + (int) Math.floor(childBounds.top)
+ + "," + (int) Math.ceil(childBounds.right)
+ + "," + (int) Math.ceil(childBounds.bottom));
+ }
+ }
+ }
+
+ @Override
+ protected void onFinishInflate() {
+ super.onFinishInflate();
+ LayoutInflater inflater = (LayoutInflater)
+ mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
+
+ setScrollbarFadingEnabled(true);
+
+ mLinearLayout = (LinearLayout) findViewById(R.id.recents_linear_layout);
+
+ final int leftPadding = mContext.getResources()
+ .getDimensionPixelOffset(R.dimen.status_bar_recents_thumbnail_left_margin);
+ setOverScrollEffectPadding(leftPadding, 0);
+ }
+
+ private void setOverScrollEffectPadding(int leftPadding, int i) {
+ // TODO Add to RecentsHorizontalScrollView
+ }
+
+ @Override
+ protected void onSizeChanged(int w, int h, int oldw, int oldh) {
+ super.onSizeChanged(w, h, oldw, oldh);
+ // Keep track of the last visible item in the list so we can restore it
+ // to the bottom when the orientation changes.
+ mLastScrollPosition = scrollPositionOfMostRecent();
+
+ // This has to happen post-layout, so run it "in the future"
+ post(new Runnable() {
+ public void run() {
+ scrollTo(0, mLastScrollPosition);
+ }
+ });
+ }
+
+ @Override
+ protected void onVisibilityChanged(View changedView, int visibility) {
+ super.onVisibilityChanged(changedView, visibility);
+ // scroll to bottom after reloading
+ if (visibility == View.VISIBLE && changedView == this) {
+ post(new Runnable() {
+ public void run() {
+ update();
+ }
+ });
+ }
+ }
+
+ public void setAdapter(ActvityDescriptionAdapter adapter) {
+ mAdapter = adapter;
+ mAdapter.registerDataSetObserver(new DataSetObserver() {
+ public void onChanged() {
+ update();
+ }
+
+ public void onInvalidated() {
+ update();
+ }
+ });
+ }
+
+ @Override
+ public void setLayoutTransition(LayoutTransition transition) {
+ // The layout transition applies to our embedded LinearLayout
+ mLinearLayout.setLayoutTransition(transition);
+ }
+
+ public void onClick(View view) {
+ mCallback.handleOnClick(view);
+ }
+
+ public void setCallback(RecentsCallback callback) {
+ mCallback = callback;
+ }
+
+ public boolean onTouch(View v, MotionEvent event) {
+ mCurrentView = v;
+ return false;
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/recent/RecentsListView.java b/packages/SystemUI/src/com/android/systemui/recent/RecentsListView.java
new file mode 100644
index 0000000..d8b086b
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/recent/RecentsListView.java
@@ -0,0 +1,92 @@
+/*
+ * 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.systemui.recent;
+
+import android.content.Context;
+import android.util.AttributeSet;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.widget.ListView;
+
+import com.android.systemui.R;
+
+public class RecentsListView extends ListView {
+ private int mLastVisiblePosition;
+ private RecentsCallback mCallback;
+
+ public RecentsListView(Context context) {
+ this(context, null);
+ }
+
+ public RecentsListView(Context context, AttributeSet attrs) {
+ super(context, attrs, 0);
+ }
+
+ @Override
+ protected void onFinishInflate() {
+ super.onFinishInflate();
+ LayoutInflater inflater = (LayoutInflater)
+ mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
+
+ View footer = inflater.inflate(R.layout.status_bar_recent_panel_footer, this, false);
+ setScrollbarFadingEnabled(true);
+ addFooterView(footer, null, false);
+ final int leftPadding = mContext.getResources()
+ .getDimensionPixelOffset(R.dimen.status_bar_recents_thumbnail_left_margin);
+ setOverScrollEffectPadding(leftPadding, 0);
+ }
+
+ @Override
+ protected void onSizeChanged(int w, int h, int oldw, int oldh) {
+ super.onSizeChanged(w, h, oldw, oldh);
+ // Keep track of the last visible item in the list so we can restore it
+ // to the bottom when the orientation changes.
+ final int childCount = getChildCount();
+ if (childCount > 0) {
+ mLastVisiblePosition = getFirstVisiblePosition() + childCount - 1;
+ View view = getChildAt(childCount - 1);
+ final int distanceFromBottom = getHeight() - view.getTop();
+
+ // This has to happen post-layout, so run it "in the future"
+ post(new Runnable() {
+ public void run() {
+ setSelectionFromTop(mLastVisiblePosition, getHeight() - distanceFromBottom);
+ }
+ });
+ }
+ }
+
+ @Override
+ protected void onVisibilityChanged(View changedView, int visibility) {
+ super.onVisibilityChanged(changedView, visibility);
+ // scroll to bottom after reloading
+ int count = getAdapter().getCount();
+ mLastVisiblePosition = count - 1;
+ if (visibility == View.VISIBLE && changedView == this) {
+ post(new Runnable() {
+ public void run() {
+ setSelection(mLastVisiblePosition);
+ }
+ });
+ }
+ }
+
+ public void setCallback(RecentsCallback callback) {
+ mCallback = callback;
+ }
+
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/RecentAppsPanel.java b/packages/SystemUI/src/com/android/systemui/recent/RecentsPanelView.java
similarity index 64%
rename from packages/SystemUI/src/com/android/systemui/statusbar/tablet/RecentAppsPanel.java
rename to packages/SystemUI/src/com/android/systemui/recent/RecentsPanelView.java
index d0e6551..e2b3446 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/RecentAppsPanel.java
+++ b/packages/SystemUI/src/com/android/systemui/recent/RecentsPanelView.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2010 The Android Open Source Project
+ * Copyright (C) 2011 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -14,14 +14,12 @@
* limitations under the License.
*/
-package com.android.systemui.statusbar.tablet;
+package com.android.systemui.recent;
import java.util.ArrayList;
import java.util.List;
-import android.animation.Animator;
-import android.animation.AnimatorSet;
-import android.animation.ObjectAnimator;
+import android.animation.LayoutTransition;
import android.app.ActivityManager;
import android.content.Context;
import android.content.Intent;
@@ -43,25 +41,25 @@
import android.util.AttributeSet;
import android.util.DisplayMetrics;
import android.util.Log;
-import android.util.Slog;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.BaseAdapter;
-import android.widget.CheckBox;
import android.widget.ImageView;
-import android.widget.ListView;
import android.widget.RelativeLayout;
import android.widget.TextView;
import com.android.systemui.R;
+import com.android.systemui.statusbar.tablet.StatusBarPanel;
+import com.android.systemui.statusbar.tablet.TabletStatusBar;
-public class RecentAppsPanel extends RelativeLayout implements StatusBarPanel, OnItemClickListener {
+public class RecentsPanelView extends RelativeLayout
+ implements OnItemClickListener, RecentsCallback, StatusBarPanel {
private static final int GLOW_PADDING = 15;
- private static final String TAG = "RecentAppsPanel";
- private static final boolean DEBUG = TabletStatusBar.DEBUG;
+ static final String TAG = "RecentsListView";
+ static final boolean DEBUG = TabletStatusBar.DEBUG;
private static final int DISPLAY_TASKS = 20;
private static final int MAX_TASKS = DISPLAY_TASKS + 1; // allow extra for non-apps
private TabletStatusBar mBar;
@@ -69,17 +67,15 @@
private int mIconDpi;
private View mRecentsScrim;
private View mRecentsGlowView;
- private ListView mRecentsContainer;
- private CheckBox mCompatMode;
+ private View mRecentsContainer;
private Bitmap mGlowBitmap;
private boolean mShowing;
private Choreographer mChoreo;
private View mRecentsDismissButton;
private ActvityDescriptionAdapter mListAdapter;
- protected int mLastVisibleItem;
- static class ActivityDescription {
- int id;
+ /* package */ final static class ActivityDescription {
+ int taskId; // application task id for curating apps
Bitmap thumbnail; // generated by Activity.onCreateThumbnail()
Drawable icon; // application package icon
String label; // application package label
@@ -98,18 +94,18 @@
label = _label;
description = _desc;
intent = _intent;
- id = _id;
+ taskId = _id;
position = _pos;
packageName = _packageName;
}
};
/* package */ final static class ViewHolder {
- private ImageView thumbnailView;
- private ImageView iconView;
- private TextView labelView;
- private TextView descriptionView;
- private ActivityDescription activityDescription;
+ ImageView thumbnailView;
+ ImageView iconView;
+ TextView labelView;
+ TextView descriptionView;
+ ActivityDescription activityDescription;
}
/* package */ final class ActvityDescriptionAdapter extends BaseAdapter {
@@ -205,120 +201,15 @@
return mShowing;
}
- private static class Choreographer implements Animator.AnimatorListener {
- // should group this into a multi-property animation
- private static final int OPEN_DURATION = 136;
- private static final int CLOSE_DURATION = 250;
-
- boolean mVisible;
- int mPanelHeight;
- View mRootView;
- View mScrimView;
- View mContentView;
- AnimatorSet mContentAnim;
-
- // the panel will start to appear this many px from the end
- final int HYPERSPACE_OFFRAMP = 200;
-
- public Choreographer(View root, View scrim, View content) {
- mRootView = root;
- mScrimView = scrim;
- mContentView = content;
- }
-
- void createAnimation(boolean appearing) {
- float start, end;
-
- if (DEBUG) Log.e(TAG, "createAnimation()", new Exception());
-
- // 0: on-screen
- // height: off-screen
- float y = mContentView.getTranslationY();
- if (appearing) {
- // we want to go from near-the-top to the top, unless we're half-open in the right
- // general vicinity
- start = (y < HYPERSPACE_OFFRAMP) ? y : HYPERSPACE_OFFRAMP;
- end = 0;
- } else {
- start = y;
- end = y + HYPERSPACE_OFFRAMP;
- }
-
- Animator posAnim = ObjectAnimator.ofFloat(mContentView, "translationY",
- start, end);
- posAnim.setInterpolator(appearing
- ? new android.view.animation.DecelerateInterpolator(2.5f)
- : new android.view.animation.AccelerateInterpolator(2.5f));
-
- Animator glowAnim = ObjectAnimator.ofFloat(mContentView, "alpha",
- mContentView.getAlpha(), appearing ? 1.0f : 0.0f);
- glowAnim.setInterpolator(appearing
- ? new android.view.animation.AccelerateInterpolator(1.0f)
- : new android.view.animation.DecelerateInterpolator(1.0f));
-
- Animator bgAnim = ObjectAnimator.ofInt(mScrimView.getBackground(),
- "alpha", appearing ? 0 : 255, appearing ? 255 : 0);
-
- mContentAnim = new AnimatorSet();
- mContentAnim
- .play(bgAnim)
- .with(glowAnim)
- .with(posAnim);
- mContentAnim.setDuration(appearing ? OPEN_DURATION : CLOSE_DURATION);
- mContentAnim.addListener(this);
- }
-
- void startAnimation(boolean appearing) {
- if (DEBUG) Slog.d(TAG, "startAnimation(appearing=" + appearing + ")");
-
- createAnimation(appearing);
-
- mContentView.setLayerType(View.LAYER_TYPE_HARDWARE, null);
- mContentAnim.start();
-
- mVisible = appearing;
- }
-
- void jumpTo(boolean appearing) {
- mContentView.setTranslationY(appearing ? 0 : mPanelHeight);
- }
-
- public void setPanelHeight(int h) {
- if (DEBUG) Slog.d(TAG, "panelHeight=" + h);
- mPanelHeight = h;
- }
-
- public void onAnimationCancel(Animator animation) {
- if (DEBUG) Slog.d(TAG, "onAnimationCancel");
- // force this to zero so we close the window
- mVisible = false;
- }
-
- public void onAnimationEnd(Animator animation) {
- if (DEBUG) Slog.d(TAG, "onAnimationEnd");
- if (!mVisible) {
- mRootView.setVisibility(View.GONE);
- }
- mContentView.setLayerType(View.LAYER_TYPE_NONE, null);
- mContentAnim = null;
- }
-
- public void onAnimationRepeat(Animator animation) {
- }
-
- public void onAnimationStart(Animator animation) {
- }
- }
-
public void setBar(TabletStatusBar bar) {
mBar = bar;
}
- public RecentAppsPanel(Context context, AttributeSet attrs) {
+ public RecentsPanelView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
- public RecentAppsPanel(Context context, AttributeSet attrs, int defStyle) {
+ public RecentsPanelView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
Resources res = context.getResources();
@@ -330,52 +221,34 @@
}
@Override
- protected void onSizeChanged(int w, int h, int oldw, int oldh) {
- super.onSizeChanged(w, h, oldw, oldh);
- // Keep track of the last visible item in the list so we can restore it
- // to the bottom when the orientation changes.
- int childCount = mRecentsContainer.getChildCount();
- if (childCount > 0) {
- mLastVisibleItem = mRecentsContainer.getFirstVisiblePosition() + childCount - 1;
- View view = mRecentsContainer.getChildAt(childCount - 1);
- final int distanceFromBottom = mRecentsContainer.getHeight() - view.getTop();
- //final int distanceFromBottom = view.getHeight() + BOTTOM_OFFSET;
-
- // This has to happen post-layout, so run it "in the future"
- post(new Runnable() {
- public void run() {
- mRecentsContainer.setSelectionFromTop(mLastVisibleItem,
- mRecentsContainer.getHeight() - distanceFromBottom);
- }
- });
- }
- }
-
- @Override
protected void onFinishInflate() {
super.onFinishInflate();
- LayoutInflater inflater = (LayoutInflater)
mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
+ mRecentsContainer = findViewById(R.id.recents_container);
+ mListAdapter = new ActvityDescriptionAdapter(mContext);
+ if (mRecentsContainer instanceof RecentsListView) {
+ RecentsListView listView = (RecentsListView) mRecentsContainer;
+ listView.setAdapter(mListAdapter);
+ listView.setOnItemClickListener(this);
+ listView.setCallback(this);
+ } else if (mRecentsContainer instanceof RecentsHorizontalScrollView){
+ RecentsHorizontalScrollView scrollView
+ = (RecentsHorizontalScrollView) mRecentsContainer;
+ scrollView.setAdapter(mListAdapter);
+ scrollView.setCallback(this);
+ } else if (mRecentsContainer instanceof RecentsVerticalScrollView){
+ RecentsVerticalScrollView scrollView
+ = (RecentsVerticalScrollView) mRecentsContainer;
+ scrollView.setAdapter(mListAdapter);
+ scrollView.setCallback(this);
+ }
+ else {
+ throw new IllegalArgumentException("missing RecentsListView/RecentsScrollView");
+ }
- mRecentsContainer = (ListView) findViewById(R.id.recents_container);
- mCompatMode = (CheckBox) findViewById(R.id.recents_compat_mode);
- mCompatMode.setOnClickListener(new OnClickListener() {
- public void onClick(View v) {
- final ActivityManager am = (ActivityManager)
- mContext.getSystemService(Context.ACTIVITY_SERVICE);
- am.setFrontActivityScreenCompatMode(ActivityManager.COMPAT_MODE_TOGGLE);
- hide(true);
- }
- });
- View footer = inflater.inflate(R.layout.status_bar_recent_panel_footer,
- mRecentsContainer, false);
- mRecentsContainer.setScrollbarFadingEnabled(true);
- mRecentsContainer.addFooterView(footer, null, false);
- mRecentsContainer.setAdapter(mListAdapter = new ActvityDescriptionAdapter(mContext));
- mRecentsContainer.setOnItemClickListener(this);
- final int leftPadding = mContext.getResources()
- .getDimensionPixelOffset(R.dimen.status_bar_recents_thumbnail_left_margin);
- mRecentsContainer.setOverScrollEffectPadding(leftPadding, 0);
+ final LayoutTransition transitioner = new LayoutTransition();
+ ((ViewGroup)mRecentsContainer).setLayoutTransition(transitioner);
+ createCustomAnimations(transitioner);
mRecentsGlowView = findViewById(R.id.recents_glow);
mRecentsScrim = (View) findViewById(R.id.recents_bg_protect);
@@ -393,17 +266,16 @@
}
}
+ private void createCustomAnimations(LayoutTransition transitioner) {
+ transitioner.setDuration(LayoutTransition.DISAPPEARING, 250);
+ }
+
@Override
protected void onVisibilityChanged(View changedView, int visibility) {
super.onVisibilityChanged(changedView, visibility);
if (DEBUG) Log.v(TAG, "onVisibilityChanged(" + changedView + ", " + visibility + ")");
if (visibility == View.VISIBLE && changedView == this) {
refreshApplicationList();
- post(new Runnable() {
- public void run() {
- mRecentsContainer.setSelection(mActivityDescriptions.size() - 1);
- }
- });
}
}
@@ -496,7 +368,7 @@
ActivityDescription desc = null;
for (int i = 0; i < mActivityDescriptions.size(); i++) {
ActivityDescription item = mActivityDescriptions.get(i);
- if (item != null && item.id == id) {
+ if (item != null && item.taskId == id) {
desc = item;
break;
}
@@ -504,34 +376,15 @@
return desc;
}
- private void updateShownCompatMode() {
- final ActivityManager am = (ActivityManager)
- mContext.getSystemService(Context.ACTIVITY_SERVICE);
- int mode = am.getFrontActivityScreenCompatMode();
- switch (mode) {
- case ActivityManager.COMPAT_MODE_DISABLED:
- mCompatMode.setVisibility(View.VISIBLE);
- mCompatMode.setChecked(true);
- break;
- case ActivityManager.COMPAT_MODE_ENABLED:
- mCompatMode.setVisibility(View.VISIBLE);
- mCompatMode.setChecked(false);
- break;
- default:
- mCompatMode.setVisibility(View.GONE);
- break;
- }
- }
-
private void refreshApplicationList() {
mActivityDescriptions = getRecentTasks();
mListAdapter.notifyDataSetInvalidated();
if (mActivityDescriptions.size() > 0) {
- mLastVisibleItem = mActivityDescriptions.size() - 1; // scroll to bottom after reloading
+ Log.v(TAG, "Showing " + mActivityDescriptions.size() + " apps");
updateUiElements(getResources().getConfiguration());
- updateShownCompatMode();
} else {
// Immediately hide this panel
+ Log.v(TAG, "Nothing to show");
hide(false);
}
}
@@ -546,6 +399,7 @@
paint.setAlpha(255);
final int srcWidth = thumbnail.getWidth();
final int srcHeight = thumbnail.getHeight();
+ Log.v(TAG, "Source thumb: " + srcWidth + "x" + srcHeight);
canvas.drawBitmap(thumbnail,
new Rect(0, 0, srcWidth-1, srcHeight-1),
new RectF(GLOW_PADDING,
@@ -563,27 +417,57 @@
mRecentsGlowView.setVisibility(items > 0 ? View.VISIBLE : View.GONE);
}
- private void hide(boolean animate) {
+ public void hide(boolean animate) {
if (!animate) {
setVisibility(View.GONE);
}
- mBar.animateCollapse();
+ if (mBar != null) {
+ mBar.animateCollapse();
+ }
}
- public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
+ public void handleOnClick(View view) {
ActivityDescription ad = ((ViewHolder) view.getTag()).activityDescription;
+ final Context context = view.getContext();
final ActivityManager am = (ActivityManager)
- getContext().getSystemService(Context.ACTIVITY_SERVICE);
- if (ad.id >= 0) {
+ context.getSystemService(Context.ACTIVITY_SERVICE);
+ if (ad.taskId >= 0) {
// This is an active task; it should just go to the foreground.
- am.moveTaskToFront(ad.id, ActivityManager.MOVE_TASK_WITH_HOME);
+ am.moveTaskToFront(ad.taskId, ActivityManager.MOVE_TASK_WITH_HOME);
} else {
Intent intent = ad.intent;
intent.addFlags(Intent.FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY
| Intent.FLAG_ACTIVITY_TASK_ON_HOME);
if (DEBUG) Log.v(TAG, "Starting activity " + intent);
- getContext().startActivity(intent);
+ context.startActivity(intent);
}
hide(true);
}
+
+ public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
+ handleOnClick(view);
+ }
+
+ public void handleSwipe(View view, int direction) {
+ ActivityDescription ad = ((ViewHolder) view.getTag()).activityDescription;
+ Log.v(TAG, "Jettison " + ad.label);
+ mActivityDescriptions.remove(ad);
+
+ // Handled by widget containers to enable LayoutTransitions properly
+ // mListAdapter.notifyDataSetChanged();
+
+ if (mActivityDescriptions.size() == 0) {
+ hide(false);
+ }
+
+ // Currently, either direction means the same thing, so ignore direction and remove
+ // the task.
+ final ActivityManager am = (ActivityManager)
+ mContext.getSystemService(Context.ACTIVITY_SERVICE);
+ am.removeTask(ad.taskId, 0);
+ }
+
+ public void handleLongPress(View selectedView) {
+ // TODO show context menu : "Remove from list", "Show properties"
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/recent/RecentsVerticalScrollView.java b/packages/SystemUI/src/com/android/systemui/recent/RecentsVerticalScrollView.java
new file mode 100644
index 0000000..54ec6b5
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/recent/RecentsVerticalScrollView.java
@@ -0,0 +1,309 @@
+/*
+ * 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.systemui.recent;
+
+import com.android.systemui.recent.RecentsPanelView.ActvityDescriptionAdapter;
+
+import android.animation.Animator;
+import android.animation.Animator.AnimatorListener;
+import android.animation.LayoutTransition;
+import android.animation.ObjectAnimator;
+import android.animation.ValueAnimator;
+import android.animation.ValueAnimator.AnimatorUpdateListener;
+import android.content.Context;
+import android.database.DataSetObserver;
+import android.graphics.RectF;
+import android.util.AttributeSet;
+import android.util.Log;
+import android.view.LayoutInflater;
+import android.view.MotionEvent;
+import android.view.VelocityTracker;
+import android.view.View;
+import android.view.animation.DecelerateInterpolator;
+import android.view.animation.LinearInterpolator;
+import android.widget.LinearLayout;
+import android.widget.ScrollView;
+
+import com.android.systemui.R;
+
+public class RecentsVerticalScrollView extends ScrollView
+ implements View.OnClickListener, View.OnTouchListener {
+ private static final float FADE_CONSTANT = 0.5f;
+ private static final int SNAP_BACK_DURATION = 250;
+ private static final int ESCAPE_VELOCITY = 100; // speed of item required to "curate" it
+ private static final String TAG = RecentsPanelView.TAG;
+ private static final float THRESHHOLD = 50;
+ private static final boolean DEBUG_INVALIDATE = false;
+ private LinearLayout mLinearLayout;
+ private ActvityDescriptionAdapter mAdapter;
+ private RecentsCallback mCallback;
+ protected int mLastScrollPosition;
+ private View mCurrentView;
+ private float mLastX;
+ private boolean mDragging;
+ private VelocityTracker mVelocityTracker;
+
+ public RecentsVerticalScrollView(Context context) {
+ this(context, null);
+ }
+
+ public RecentsVerticalScrollView(Context context, AttributeSet attrs) {
+ super(context, attrs, 0);
+ }
+
+ private int scrollPositionOfMostRecent() {
+ return mLinearLayout.getHeight() - getHeight();
+ }
+
+ public void update() {
+ mLinearLayout.removeAllViews();
+ for (int i = 0; i < mAdapter.getCount(); i++) {
+ View view = mAdapter.getView(i, null, mLinearLayout);
+ view.setClickable(true);
+ view.setOnClickListener(this);
+ view.setOnTouchListener(this);
+ mLinearLayout.addView(view);
+ }
+ // Scroll to end after layout.
+ post(new Runnable() {
+ public void run() {
+ mLastScrollPosition = scrollPositionOfMostRecent();
+ scrollTo(0, mLastScrollPosition);
+ }
+ });
+ }
+
+ @Override
+ public boolean onInterceptTouchEvent(MotionEvent ev) {
+ if (mVelocityTracker == null) {
+ mVelocityTracker = VelocityTracker.obtain();
+ }
+ mVelocityTracker.addMovement(ev);
+ switch (ev.getAction()) {
+ case MotionEvent.ACTION_DOWN:
+ mDragging = false;
+ mLastX = ev.getX();
+ break;
+
+ case MotionEvent.ACTION_MOVE:
+ float delta = ev.getX() - mLastX;
+ Log.v(TAG, "ACTION_MOVE : " + delta);
+ if (Math.abs(delta) > THRESHHOLD) {
+ mDragging = true;
+ }
+ break;
+
+ case MotionEvent.ACTION_UP:
+ mDragging = false;
+ break;
+ }
+ return mDragging ? true : super.onInterceptTouchEvent(ev);
+ }
+
+ private float getAlphaForOffset(View view, float thumbWidth) {
+ final float fadeWidth = FADE_CONSTANT * thumbWidth;
+ float result = 1.0f;
+ if (view.getX() >= thumbWidth) {
+ result = 1.0f - (view.getX() - thumbWidth) / fadeWidth;
+ } else if (view.getX() < 0.0f) {
+ result = 1.0f + (thumbWidth + view.getX()) / fadeWidth;
+ }
+ Log.v(TAG, "FADE AMOUNT: " + result);
+ return result;
+ }
+
+ @Override
+ public boolean onTouchEvent(MotionEvent ev) {
+ if (!mDragging) {
+ return super.onTouchEvent(ev);
+ }
+
+ mVelocityTracker.addMovement(ev);
+
+ final View animView = mCurrentView;
+ // TODO: Cache thumbnail
+ final View thumb = animView.findViewById(R.id.app_thumbnail);
+ switch (ev.getAction()) {
+ case MotionEvent.ACTION_MOVE:
+ if (animView != null) {
+ final float delta = ev.getX() - mLastX;
+ animView.setX(animView.getX() + delta);
+ animView.setAlpha(getAlphaForOffset(animView, thumb.getWidth()));
+ invalidateGlobalRegion(animView);
+ }
+ mLastX = ev.getX();
+ break;
+
+ case MotionEvent.ACTION_UP:
+ final ObjectAnimator anim;
+ if (animView != null) {
+ final VelocityTracker velocityTracker = mVelocityTracker;
+ velocityTracker.computeCurrentVelocity(1000, 10000);
+ final float velocityX = velocityTracker.getXVelocity();
+ final float velocityY = velocityTracker.getYVelocity();
+ final float curX = animView.getX();
+ final float newX = (velocityX >= 0.0f ? 1 : -1) * animView.getWidth();
+
+ if (Math.abs(velocityX) > Math.abs(velocityY)
+ && Math.abs(velocityX) > ESCAPE_VELOCITY
+ && (velocityX > 0.0f) == (animView.getX() >= 0)) {
+ final long duration =
+ (long) (Math.abs(newX-curX) * 1000.0f / Math.abs(velocityX));
+ anim = ObjectAnimator.ofFloat(animView, "x", curX, newX);
+ anim.setInterpolator(new LinearInterpolator());
+ final int swipeDirection = animView.getX() >= 0.0f ?
+ RecentsCallback.SWIPE_RIGHT : RecentsCallback.SWIPE_LEFT;
+ anim.addListener(new AnimatorListener() {
+ public void onAnimationStart(Animator animation) {
+ }
+ public void onAnimationRepeat(Animator animation) {
+ }
+ public void onAnimationEnd(Animator animation) {
+ mLinearLayout.removeView(mCurrentView);
+ mCallback.handleSwipe(animView, swipeDirection);
+ }
+ public void onAnimationCancel(Animator animation) {
+ mLinearLayout.removeView(mCurrentView);
+ mCallback.handleSwipe(animView, swipeDirection);
+ }
+ });
+ anim.setDuration(duration);
+ } else { // Animate back to position
+ final long duration = Math.abs(velocityX) > 0.0f ?
+ (long) (Math.abs(newX-curX) * 1000.0f / Math.abs(velocityX))
+ : SNAP_BACK_DURATION;
+ anim = ObjectAnimator.ofFloat(animView, "x", animView.getX(), 0.0f);
+ anim.setInterpolator(new DecelerateInterpolator(4.0f));
+ anim.setDuration(duration);
+ }
+
+ anim.addUpdateListener(new AnimatorUpdateListener() {
+ public void onAnimationUpdate(ValueAnimator animation) {
+ animView.setAlpha(getAlphaForOffset(animView, thumb.getWidth()));
+ invalidateGlobalRegion(animView);
+ }
+ });
+ anim.start();
+ }
+
+ mVelocityTracker.recycle();
+ mVelocityTracker = null;
+ break;
+ }
+ return true;
+ }
+
+ void invalidateGlobalRegion(View view) {
+ RectF childBounds
+ = new RectF(view.getLeft(), view.getTop(), view.getRight(), view.getBottom());
+ childBounds.offset(view.getX(), view.getY());
+ if (DEBUG_INVALIDATE) Log.v(TAG, "-------------");
+ while (view.getParent() != null && view.getParent() instanceof View) {
+ view = (View) view.getParent();
+ view.getMatrix().mapRect(childBounds);
+ view.invalidate((int) Math.floor(childBounds.left),
+ (int) Math.floor(childBounds.top),
+ (int) Math.ceil(childBounds.right),
+ (int) Math.ceil(childBounds.bottom));
+ if (DEBUG_INVALIDATE) {
+ Log.v(TAG, "INVALIDATE(" + (int) Math.floor(childBounds.left)
+ + "," + (int) Math.floor(childBounds.top)
+ + "," + (int) Math.ceil(childBounds.right)
+ + "," + (int) Math.ceil(childBounds.bottom));
+ }
+ }
+ }
+
+ @Override
+ protected void onFinishInflate() {
+ super.onFinishInflate();
+ LayoutInflater inflater = (LayoutInflater)
+ mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
+
+ setScrollbarFadingEnabled(true);
+
+ mLinearLayout = (LinearLayout) findViewById(R.id.recents_linear_layout);
+
+ final int leftPadding = mContext.getResources()
+ .getDimensionPixelOffset(R.dimen.status_bar_recents_thumbnail_left_margin);
+ setOverScrollEffectPadding(leftPadding, 0);
+ }
+
+ private void setOverScrollEffectPadding(int leftPadding, int i) {
+ // TODO Add to (Vertical)ScrollView
+ }
+
+ @Override
+ protected void onSizeChanged(int w, int h, int oldw, int oldh) {
+ super.onSizeChanged(w, h, oldw, oldh);
+ // Keep track of the last visible item in the list so we can restore it
+ // to the bottom when the orientation changes.
+ mLastScrollPosition = scrollPositionOfMostRecent();
+
+ // This has to happen post-layout, so run it "in the future"
+ post(new Runnable() {
+ public void run() {
+ scrollTo(0, mLastScrollPosition);
+ }
+ });
+ }
+
+ @Override
+ protected void onVisibilityChanged(View changedView, int visibility) {
+ super.onVisibilityChanged(changedView, visibility);
+ // scroll to bottom after reloading
+ if (visibility == View.VISIBLE && changedView == this) {
+ post(new Runnable() {
+ public void run() {
+ update();
+ }
+ });
+ }
+ }
+
+ public void setAdapter(ActvityDescriptionAdapter adapter) {
+ mAdapter = adapter;
+ mAdapter.registerDataSetObserver(new DataSetObserver() {
+ public void onChanged() {
+ update();
+ }
+
+ public void onInvalidated() {
+ update();
+ }
+ });
+ }
+
+ @Override
+ public void setLayoutTransition(LayoutTransition transition) {
+ // The layout transition applies to our embedded LinearLayout
+ mLinearLayout.setLayoutTransition(transition);
+ }
+
+ public void onClick(View view) {
+ mCallback.handleOnClick(view);
+ }
+
+ public void setCallback(RecentsCallback callback) {
+ mCallback = callback;
+ }
+
+ public boolean onTouch(View v, MotionEvent event) {
+ mCurrentView = v;
+ return false;
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/recent/RecentApplicationsActivity.java b/packages/SystemUI/src/com/android/systemui/recent/carousel/RecentApplicationsActivity.java
similarity index 99%
rename from packages/SystemUI/src/com/android/systemui/recent/RecentApplicationsActivity.java
rename to packages/SystemUI/src/com/android/systemui/recent/carousel/RecentApplicationsActivity.java
index 7d4629e..45e230f 100644
--- a/packages/SystemUI/src/com/android/systemui/recent/RecentApplicationsActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/recent/carousel/RecentApplicationsActivity.java
@@ -15,7 +15,7 @@
*/
-package com.android.systemui.recent;
+package com.android.systemui.recent.carousel;
import com.android.systemui.R;
diff --git a/packages/SystemUI/src/com/android/systemui/recent/RecentApplicationsCarouselView.java b/packages/SystemUI/src/com/android/systemui/recent/carousel/RecentApplicationsCarouselView.java
similarity index 95%
rename from packages/SystemUI/src/com/android/systemui/recent/RecentApplicationsCarouselView.java
rename to packages/SystemUI/src/com/android/systemui/recent/carousel/RecentApplicationsCarouselView.java
index 1c8ec95..1afb086 100644
--- a/packages/SystemUI/src/com/android/systemui/recent/RecentApplicationsCarouselView.java
+++ b/packages/SystemUI/src/com/android/systemui/recent/carousel/RecentApplicationsCarouselView.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.systemui.recent;
+package com.android.systemui.recent.carousel;
import android.content.Context;
import android.util.AttributeSet;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBar.java
index f74fcc6..91c3cc1 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBar.java
@@ -71,7 +71,8 @@
import com.android.systemui.statusbar.policy.LocationController;
import com.android.systemui.statusbar.policy.NetworkController;
import com.android.systemui.statusbar.policy.Prefs;
-import com.android.systemui.recent.RecentApplicationsActivity;
+import com.android.systemui.recent.RecentsPanelView;
+import com.android.systemui.recent.carousel.RecentApplicationsActivity;
public class TabletStatusBar extends StatusBar implements
HeightReceiver.OnBarHeightChangedListener,
@@ -162,7 +163,7 @@
// for disabling the status bar
int mDisabled = 0;
- private RecentAppsPanel mRecentsPanel;
+ private RecentsPanelView mRecentsPanel;
private InputMethodsPanel mInputMethodsPanel;
public Context getContext() { return mContext; }
@@ -253,7 +254,7 @@
WindowManagerImpl.getDefault().addView(mNotificationPeekWindow, lp);
// Recents Panel
- mRecentsPanel = (RecentAppsPanel) View.inflate(context,
+ mRecentsPanel = (RecentsPanelView) View.inflate(context,
R.layout.status_bar_recent_panel, null);
mRecentsPanel.setVisibility(View.GONE);
mRecentsPanel.setOnTouchListener(new TouchOutsideListener(MSG_CLOSE_RECENTS_PANEL,
@@ -1195,7 +1196,7 @@
if (mVT != null) {
if (action == MotionEvent.ACTION_UP
// was this a sloppy tap?
- && Math.abs(event.getX() - mInitialTouchX) < mTouchSlop
+ && Math.abs(event.getX() - mInitialTouchX) < mTouchSlop
&& Math.abs(event.getY() - mInitialTouchY) < (mTouchSlop / 3)
// dragging off the bottom doesn't count
&& (int)event.getY() < v.getBottom()) {
@@ -1298,7 +1299,7 @@
if (!peeking) {
if (action == MotionEvent.ACTION_UP
// was this a sloppy tap?
- && Math.abs(event.getX() - mInitialTouchX) < mTouchSlop
+ && Math.abs(event.getX() - mInitialTouchX) < mTouchSlop
&& Math.abs(event.getY() - mInitialTouchY) < (mTouchSlop / 3)
// dragging off the bottom doesn't count
&& (int)event.getY() < v.getBottom()) {
diff --git a/services/java/com/android/server/ConnectivityService.java b/services/java/com/android/server/ConnectivityService.java
index db831c7..ca2adb4 100644
--- a/services/java/com/android/server/ConnectivityService.java
+++ b/services/java/com/android/server/ConnectivityService.java
@@ -26,6 +26,7 @@
import android.net.DummyDataStateTracker;
import android.net.EthernetDataTracker;
import android.net.IConnectivityManager;
+import android.net.LinkAddress;
import android.net.LinkProperties;
import android.net.MobileDataStateTracker;
import android.net.NetworkConfig;
@@ -61,6 +62,7 @@
import java.io.IOException;
import java.io.PrintWriter;
import java.net.InetAddress;
+import java.net.Inet4Address;
import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.Collection;
@@ -125,6 +127,8 @@
private AtomicBoolean mBackgroundDataEnabled = new AtomicBoolean(true);
+ private INetworkManagementService mNetd;
+
private static final int ENABLED = 1;
private static final int DISABLED = 0;
@@ -933,10 +937,6 @@
* @return {@code true} on success, {@code false} on failure
*/
private boolean addHostRoute(NetworkStateTracker nt, InetAddress hostAddress, int cycleCount) {
- if (nt.getNetworkInfo().getType() == ConnectivityManager.TYPE_WIFI) {
- return false;
- }
-
LinkProperties lp = nt.getLinkProperties();
if ((lp == null) || (hostAddress == null)) return false;
@@ -951,20 +951,28 @@
}
RouteInfo bestRoute = RouteInfo.selectBestRoute(lp.getRoutes(), hostAddress);
- InetAddress gateway = null;
+ InetAddress gatewayAddress = null;
if (bestRoute != null) {
- gateway = bestRoute.getGateway();
+ gatewayAddress = bestRoute.getGateway();
// if the best route is ourself, don't relf-reference, just add the host route
- if (hostAddress.equals(gateway)) gateway = null;
+ if (hostAddress.equals(gatewayAddress)) gatewayAddress = null;
}
- if (gateway != null) {
+ if (gatewayAddress != null) {
if (cycleCount > MAX_HOSTROUTE_CYCLE_COUNT) {
loge("Error adding hostroute - too much recursion");
return false;
}
- if (!addHostRoute(nt, gateway, cycleCount+1)) return false;
+ if (!addHostRoute(nt, gatewayAddress, cycleCount+1)) return false;
}
- return NetworkUtils.addHostRoute(interfaceName, hostAddress, gateway);
+
+ RouteInfo route = RouteInfo.makeHostRoute(hostAddress, gatewayAddress);
+
+ try {
+ mNetd.addRoute(interfaceName, route);
+ return true;
+ } catch (Exception ex) {
+ return false;
+ }
}
// TODO support the removal of single host routes. Keep a ref count of them so we
@@ -1291,6 +1299,9 @@
}
void systemReady() {
+ IBinder b = ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE);
+ mNetd = INetworkManagementService.Stub.asInterface(b);
+
synchronized(this) {
mSystemReady = true;
if (mInitialBroadcast != null) {
@@ -1399,6 +1410,12 @@
}
addPrivateDnsRoutes(mNetTrackers[netType]);
}
+
+ /** Notify TetheringService if interface name has been changed. */
+ if (TextUtils.equals(mNetTrackers[netType].getNetworkInfo().getReason(),
+ Phone.REASON_LINK_PROPERTIES_CHANGED)) {
+ handleTetherIfaceChange(netType);
+ }
} else {
if (mNetConfigs[netType].isDefault()) {
removeDefaultRoute(mNetTrackers[netType]);
@@ -1421,7 +1438,6 @@
if (interfaceName != null && !privateDnsRouteSet) {
Collection<InetAddress> dnsList = p.getDnses();
for (InetAddress dns : dnsList) {
- if (DBG) log(" adding " + dns);
addHostRoute(nt, dns, 0);
}
nt.privateDnsRouteSet(true);
@@ -1429,8 +1445,6 @@
}
private void removePrivateDnsRoutes(NetworkStateTracker nt) {
- // TODO - we should do this explicitly but the NetUtils api doesnt
- // support this yet - must remove all. No worse than before
LinkProperties p = nt.getLinkProperties();
if (p == null) return;
String interfaceName = p.getInterfaceName();
@@ -1440,7 +1454,17 @@
log("removePrivateDnsRoutes for " + nt.getNetworkInfo().getTypeName() +
" (" + interfaceName + ")");
}
- NetworkUtils.removeHostRoutes(interfaceName);
+
+ Collection<InetAddress> dnsList = p.getDnses();
+ for (InetAddress dns : dnsList) {
+ if (DBG) log(" removing " + dns);
+ RouteInfo route = RouteInfo.makeHostRoute(dns);
+ try {
+ mNetd.removeRoute(interfaceName, route);
+ } catch (Exception ex) {
+ loge("error (" + ex + ") removing dns route " + route);
+ }
+ }
nt.privateDnsRouteSet(false);
}
}
@@ -1451,19 +1475,27 @@
if (p == null) return;
String interfaceName = p.getInterfaceName();
if (TextUtils.isEmpty(interfaceName)) return;
- for (RouteInfo route : p.getRoutes()) {
+ for (RouteInfo route : p.getRoutes()) {
//TODO - handle non-default routes
if (route.isDefaultRoute()) {
+ if (DBG) log("adding default route " + route);
InetAddress gateway = route.getGateway();
- if (addHostRoute(nt, gateway, 0) &&
- NetworkUtils.addDefaultRoute(interfaceName, gateway)) {
+ if (addHostRoute(nt, gateway, 0)) {
+ try {
+ mNetd.addRoute(interfaceName, route);
+ } catch (Exception e) {
+ loge("error adding default route " + route);
+ continue;
+ }
if (DBG) {
NetworkInfo networkInfo = nt.getNetworkInfo();
log("addDefaultRoute for " + networkInfo.getTypeName() +
" (" + interfaceName + "), GatewayAddr=" +
gateway.getHostAddress());
}
+ } else {
+ loge("error adding host route for default route " + route);
}
}
}
@@ -1475,8 +1507,17 @@
if (p == null) return;
String interfaceName = p.getInterfaceName();
- if (interfaceName != null) {
- if (NetworkUtils.removeDefaultRoute(interfaceName) >= 0) {
+ if (interfaceName == null) return;
+
+ for (RouteInfo route : p.getRoutes()) {
+ //TODO - handle non-default routes
+ if (route.isDefaultRoute()) {
+ try {
+ mNetd.removeRoute(interfaceName, route);
+ } catch (Exception ex) {
+ loge("error (" + ex + ") removing default route " + route);
+ continue;
+ }
if (DBG) {
NetworkInfo networkInfo = nt.getNetworkInfo();
log("removeDefaultRoute for " + networkInfo.getTypeName() + " (" +
@@ -2211,6 +2252,14 @@
}
}
+ private void handleTetherIfaceChange(int type) {
+ String iface = mNetTrackers[type].getLinkProperties().getInterfaceName();
+
+ if (isTetheringSupported()) {
+ mTethering.handleTetherIfaceChange(iface);
+ }
+ }
+
private void log(String s) {
Slog.d(TAG, s);
}
diff --git a/services/java/com/android/server/MountService.java b/services/java/com/android/server/MountService.java
index 03d5728..ae04b7f 100644
--- a/services/java/com/android/server/MountService.java
+++ b/services/java/com/android/server/MountService.java
@@ -1148,6 +1148,11 @@
} catch (IOException e) {
throw new RuntimeException(e);
} finally {
+ // compute storage ID for each volume
+ int length = mVolumes.size();
+ for (int i = 0; i < length; i++) {
+ mVolumes.get(i).setStorageId(i);
+ }
parser.close();
}
}
diff --git a/services/java/com/android/server/NetworkManagementService.java b/services/java/com/android/server/NetworkManagementService.java
index d931350..7c613c1 100644
--- a/services/java/com/android/server/NetworkManagementService.java
+++ b/services/java/com/android/server/NetworkManagementService.java
@@ -29,6 +29,7 @@
import android.net.INetworkManagementEventObserver;
import android.net.LinkAddress;
import android.net.NetworkUtils;
+import android.net.RouteInfo;
import android.net.wifi.WifiConfiguration;
import android.net.wifi.WifiConfiguration.KeyMgmt;
import android.os.INetworkManagementService;
@@ -46,6 +47,8 @@
import android.content.ContentResolver;
import android.database.ContentObserver;
+import java.io.BufferedReader;
+import java.io.DataInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileReader;
@@ -55,8 +58,8 @@
import java.io.RandomAccessFile;
import java.io.Reader;
import java.lang.IllegalStateException;
-
import java.net.InetAddress;
+import java.net.Inet4Address;
import java.net.UnknownHostException;
import java.util.concurrent.CountDownLatch;
@@ -71,6 +74,9 @@
private static final boolean DBG = false;
private static final String NETD_TAG = "NetdConnector";
+ private static final int ADD = 1;
+ private static final int REMOVE = 2;
+
class NetdResponseCode {
public static final int InterfaceListResult = 110;
public static final int TetherInterfaceListResult = 111;
@@ -320,6 +326,164 @@
}
}
+ public void addRoute(String interfaceName, RouteInfo route) {
+ modifyRoute(interfaceName, ADD, route);
+ }
+
+ public void removeRoute(String interfaceName, RouteInfo route) {
+ modifyRoute(interfaceName, REMOVE, route);
+ }
+
+ private void modifyRoute(String interfaceName, int action, RouteInfo route) {
+ ArrayList<String> rsp;
+
+ StringBuilder cmd;
+
+ switch (action) {
+ case ADD:
+ {
+ cmd = new StringBuilder("interface route add " + interfaceName);
+ break;
+ }
+ case REMOVE:
+ {
+ cmd = new StringBuilder("interface route remove " + interfaceName);
+ break;
+ }
+ default:
+ throw new IllegalStateException("Unknown action type " + action);
+ }
+
+ // create triplet: dest-ip-addr prefixlength gateway-ip-addr
+ LinkAddress la = route.getDestination();
+ cmd.append(' ');
+ cmd.append(la.getAddress().getHostAddress());
+ cmd.append(' ');
+ cmd.append(la.getNetworkPrefixLength());
+ cmd.append(' ');
+ if (route.getGateway() == null) {
+ if (la.getAddress() instanceof Inet4Address) {
+ cmd.append("0.0.0.0");
+ } else {
+ cmd.append ("::0");
+ }
+ } else {
+ cmd.append(route.getGateway().getHostAddress());
+ }
+ try {
+ rsp = mConnector.doCommand(cmd.toString());
+ } catch (NativeDaemonConnectorException e) {
+ throw new IllegalStateException(
+ "Unable to communicate with native dameon to add routes - "
+ + e);
+ }
+
+ for (String line : rsp) {
+ Log.v(TAG, "add route response is " + line);
+ }
+ }
+
+ private ArrayList<String> readRouteList(String filename) {
+ FileInputStream fstream = null;
+ ArrayList<String> list = new ArrayList<String>();
+
+ try {
+ fstream = new FileInputStream(filename);
+ DataInputStream in = new DataInputStream(fstream);
+ BufferedReader br = new BufferedReader(new InputStreamReader(in));
+ String s;
+
+ // throw away the title line
+
+ while (((s = br.readLine()) != null) && (s.length() != 0)) {
+ list.add(s);
+ }
+ } catch (IOException ex) {
+ // return current list, possibly empty
+ } finally {
+ if (fstream != null) {
+ try {
+ fstream.close();
+ } catch (IOException ex) {}
+ }
+ }
+
+ return list;
+ }
+
+ public RouteInfo[] getRoutes(String interfaceName) {
+ ArrayList<RouteInfo> routes = new ArrayList<RouteInfo>();
+
+ // v4 routes listed as:
+ // iface dest-addr gateway-addr flags refcnt use metric netmask mtu window IRTT
+ for (String s : readRouteList("/proc/net/route")) {
+ String[] fields = s.split("\t");
+
+ if (fields.length > 7) {
+ String iface = fields[0];
+
+ if (interfaceName.equals(iface)) {
+ String dest = fields[1];
+ String gate = fields[2];
+ String flags = fields[3]; // future use?
+ String mask = fields[7];
+ try {
+ // address stored as a hex string, ex: 0014A8C0
+ InetAddress destAddr =
+ NetworkUtils.intToInetAddress((int)Long.parseLong(dest, 16));
+ int prefixLength =
+ NetworkUtils.netmaskIntToPrefixLength(
+ (int)Long.parseLong(mask, 16));
+ LinkAddress linkAddress = new LinkAddress(destAddr, prefixLength);
+
+ // address stored as a hex string, ex 0014A8C0
+ InetAddress gatewayAddr =
+ NetworkUtils.intToInetAddress((int)Long.parseLong(gate, 16));
+
+ RouteInfo route = new RouteInfo(linkAddress, gatewayAddr);
+ routes.add(route);
+ } catch (Exception e) {
+ Log.e(TAG, "Error parsing route " + s + " : " + e);
+ continue;
+ }
+ }
+ }
+ }
+
+ // v6 routes listed as:
+ // dest-addr prefixlength ?? ?? gateway-addr ?? ?? ?? ?? iface
+ for (String s : readRouteList("/proc/net/ipv6_route")) {
+ String[]fields = s.split("\\s+");
+ if (fields.length > 9) {
+ String iface = fields[9].trim();
+ if (interfaceName.equals(iface)) {
+ String dest = fields[0];
+ String prefix = fields[1];
+ String gate = fields[4];
+
+ try {
+ // prefix length stored as a hex string, ex 40
+ int prefixLength = Integer.parseInt(prefix, 16);
+
+ // address stored as a 32 char hex string
+ // ex fe800000000000000000000000000000
+ InetAddress destAddr = NetworkUtils.hexToInet6Address(dest);
+ LinkAddress linkAddress = new LinkAddress(destAddr, prefixLength);
+
+ InetAddress gateAddr = NetworkUtils.hexToInet6Address(gate);
+
+ RouteInfo route = new RouteInfo(linkAddress, gateAddr);
+ routes.add(route);
+ } catch (Exception e) {
+ Log.e(TAG, "Error parsing route " + s + " : " + e);
+ continue;
+ }
+ }
+ }
+ }
+ return (RouteInfo[]) routes.toArray(new RouteInfo[0]);
+ }
+
public void shutdown() {
if (mContext.checkCallingOrSelfPermission(
android.Manifest.permission.SHUTDOWN)
diff --git a/services/java/com/android/server/WifiService.java b/services/java/com/android/server/WifiService.java
index a2d10df..41ec63a 100644
--- a/services/java/com/android/server/WifiService.java
+++ b/services/java/com/android/server/WifiService.java
@@ -568,31 +568,10 @@
* @param wifiConfig SSID, security and channel details as
* part of WifiConfiguration
* @param enabled true to enable and false to disable
- * @return {@code true} if the start operation was
- * started or is already in the queue.
*/
- public synchronized boolean setWifiApEnabled(WifiConfiguration wifiConfig, boolean enabled) {
+ public void setWifiApEnabled(WifiConfiguration wifiConfig, boolean enabled) {
enforceChangePermission();
-
- if (enabled) {
- /* Use default config if there is no existing config */
- if (wifiConfig == null && ((wifiConfig = getWifiApConfiguration()) == null)) {
- wifiConfig = new WifiConfiguration();
- wifiConfig.SSID = mContext.getString(R.string.wifi_tether_configure_ssid_default);
- wifiConfig.allowedKeyManagement.set(KeyMgmt.NONE);
- }
- /*
- * Caller might not have WRITE_SECURE_SETTINGS,
- * only CHANGE_WIFI_STATE is enforced
- */
- long ident = Binder.clearCallingIdentity();
- setWifiApConfiguration(wifiConfig);
- Binder.restoreCallingIdentity(ident);
- }
-
mWifiStateMachine.setWifiApEnabled(wifiConfig, enabled);
-
- return true;
}
/**
@@ -612,38 +591,20 @@
* see {@link WifiManager#getWifiApConfiguration()}
* @return soft access point configuration
*/
- public synchronized WifiConfiguration getWifiApConfiguration() {
- final ContentResolver cr = mContext.getContentResolver();
- WifiConfiguration wifiConfig = new WifiConfiguration();
- int authType;
- try {
- wifiConfig.SSID = Settings.Secure.getString(cr, Settings.Secure.WIFI_AP_SSID);
- if (wifiConfig.SSID == null)
- return null;
- authType = Settings.Secure.getInt(cr, Settings.Secure.WIFI_AP_SECURITY);
- wifiConfig.allowedKeyManagement.set(authType);
- wifiConfig.preSharedKey = Settings.Secure.getString(cr, Settings.Secure.WIFI_AP_PASSWD);
- return wifiConfig;
- } catch (Settings.SettingNotFoundException e) {
- Slog.e(TAG,"AP settings not found, returning");
- return null;
- }
+ public WifiConfiguration getWifiApConfiguration() {
+ enforceAccessPermission();
+ return mWifiStateMachine.syncGetWifiApConfiguration(mWifiStateMachineChannel);
}
/**
* see {@link WifiManager#setWifiApConfiguration(WifiConfiguration)}
* @param wifiConfig WifiConfiguration details for soft access point
*/
- public synchronized void setWifiApConfiguration(WifiConfiguration wifiConfig) {
+ public void setWifiApConfiguration(WifiConfiguration wifiConfig) {
enforceChangePermission();
- final ContentResolver cr = mContext.getContentResolver();
if (wifiConfig == null)
return;
- int authType = wifiConfig.getAuthType();
- Settings.Secure.putString(cr, Settings.Secure.WIFI_AP_SSID, wifiConfig.SSID);
- Settings.Secure.putInt(cr, Settings.Secure.WIFI_AP_SECURITY, authType);
- if (authType != KeyMgmt.NONE)
- Settings.Secure.putString(cr, Settings.Secure.WIFI_AP_PASSWD, wifiConfig.preSharedKey);
+ mWifiStateMachine.setWifiApConfiguration(wifiConfig);
}
/**
diff --git a/services/java/com/android/server/accessibility/TouchExplorer.java b/services/java/com/android/server/accessibility/TouchExplorer.java
index fb97089..4c7f595 100644
--- a/services/java/com/android/server/accessibility/TouchExplorer.java
+++ b/services/java/com/android/server/accessibility/TouchExplorer.java
@@ -110,9 +110,6 @@
// Temporary array for storing pointer IDs.
private final int[] mTempPointerIds = new int[MAX_POINTER_COUNT];
- // Temporary array for mapping new to old pointer IDs while filtering inactive pointers.
- private final int [] mTempNewToOldPointerIndexMap = new int[MAX_POINTER_COUNT];
-
// Temporary array for storing PointerProperties
private final PointerProperties[] mTempPointerProperties =
PointerProperties.createArray(MAX_POINTER_COUNT);
@@ -229,7 +226,7 @@
// Send a hover for every finger down so the user gets feedback
// where she is currently touching.
mSendHoverDelayed.forceSendAndRemove();
- mSendHoverDelayed.post(event, MotionEvent.ACTION_HOVER_ENTER, 0, policyFlags,
+ mSendHoverDelayed.post(event, MotionEvent.ACTION_HOVER_ENTER, 1, policyFlags,
DELAY_SEND_HOVER_MOVE);
} break;
case MotionEvent.ACTION_POINTER_DOWN: {
@@ -243,13 +240,13 @@
// accessibility event from the hovered view.
mSendHoverDelayed.remove();
final int pointerId = pointerTracker.getPrimaryActivePointerId();
- final int pointerIndex = event.findPointerIndex(pointerId);
+ final int pointerIdBits = (1 << pointerId);
final int lastAction = pointerTracker.getLastInjectedHoverAction();
// If a schedules hover enter for another pointer is delivered we send move.
final int action = (lastAction == MotionEvent.ACTION_HOVER_ENTER)
? MotionEvent.ACTION_HOVER_MOVE
: MotionEvent.ACTION_HOVER_ENTER;
- mSendHoverDelayed.post(event, action, pointerIndex, policyFlags,
+ mSendHoverDelayed.post(event, action, pointerIdBits, policyFlags,
DELAY_SEND_HOVER_MOVE);
if (mLastTouchExploreEvent == null) {
@@ -268,14 +265,14 @@
}
} break;
case MotionEvent.ACTION_MOVE: {
+ final int pointerId = pointerTracker.getPrimaryActivePointerId();
+ final int pointerIndex = event.findPointerIndex(pointerId);
+ final int pointerIdBits = (1 << pointerId);
switch (activePointerCount) {
case 0: {
/* do nothing - no active pointers so we swallow the event */
} break;
case 1: {
- final int pointerId = pointerTracker.getPrimaryActivePointerId();
- final int pointerIndex = event.findPointerIndex(pointerId);
-
// Detect touch exploration gesture start by having one active pointer
// that moved more than a given distance.
if (!mTouchExploreGestureInProgress) {
@@ -290,12 +287,19 @@
sendAccessibilityEvent(TYPE_TOUCH_EXPLORATION_GESTURE_START);
// Make sure the scheduled down/move event is sent.
mSendHoverDelayed.forceSendAndRemove();
- sendHoverEvent(event, MotionEvent.ACTION_HOVER_MOVE, pointerIndex,
+ // If we have transitioned to exploring state from another one
+ // we need to send a hover enter event here.
+ final int lastAction = mPointerTracker.getLastInjectedHoverAction();
+ if (lastAction == MotionEvent.ACTION_HOVER_EXIT) {
+ sendMotionEvent(event, MotionEvent.ACTION_HOVER_ENTER,
+ pointerIdBits, policyFlags);
+ }
+ sendMotionEvent(event, MotionEvent.ACTION_HOVER_MOVE, pointerIdBits,
policyFlags);
}
} else {
// Touch exploration gesture in progress so send a hover event.
- sendHoverEvent(event, MotionEvent.ACTION_HOVER_MOVE, pointerIndex,
+ sendMotionEvent(event, MotionEvent.ACTION_HOVER_MOVE, pointerIdBits,
policyFlags);
}
@@ -337,13 +341,10 @@
}
} break;
case 2: {
- // Make sure the scheduled hover enter is delivered.
mSendHoverDelayed.forceSendAndRemove();
// We want to no longer hover over the location so subsequent
// touch at the same spot will generate a hover enter.
- final int pointerId = pointerTracker.getPrimaryActivePointerId();
- final int pointerIndex = event.findPointerIndex(pointerId);
- sendHoverEvent(event, MotionEvent.ACTION_HOVER_EXIT, pointerIndex,
+ sendMotionEvent(event, MotionEvent.ACTION_HOVER_EXIT, pointerIdBits,
policyFlags);
if (isDraggingGesture(event)) {
@@ -354,8 +355,9 @@
sendAccessibilityEvent(TYPE_TOUCH_EXPLORATION_GESTURE_END);
mTouchExploreGestureInProgress = false;
}
- mDraggingPointerId = pointerTracker.getPrimaryActivePointerId();
- sendDragEvent(event, MotionEvent.ACTION_DOWN, policyFlags);
+ mDraggingPointerId = pointerId;
+ sendMotionEvent(event, MotionEvent.ACTION_DOWN, pointerIdBits,
+ policyFlags);
} else {
// Two pointers moving arbitrary are delegated to the view hierarchy.
mCurrentState = STATE_DELEGATING;
@@ -367,13 +369,10 @@
}
} break;
default: {
- // Make sure the scheduled hover enter is delivered.
mSendHoverDelayed.forceSendAndRemove();
// We want to no longer hover over the location so subsequent
// touch at the same spot will generate a hover enter.
- final int pointerId = pointerTracker.getPrimaryActivePointerId();
- final int pointerIndex = event.findPointerIndex(pointerId);
- sendHoverEvent(event, MotionEvent.ACTION_HOVER_EXIT, pointerIndex,
+ sendMotionEvent(event, MotionEvent.ACTION_HOVER_EXIT, pointerIdBits,
policyFlags);
// More than two pointers are delegated to the view hierarchy.
@@ -389,6 +388,8 @@
} break;
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_POINTER_UP: {
+ final int pointerId = pointerTracker.getLastReceivedUpPointerId();
+ final int pointerIdBits = (1 << pointerId);
switch (activePointerCount) {
case 0: {
// If the pointer that went up was not active we have nothing to do.
@@ -404,7 +405,6 @@
// Detect whether to activate i.e. click on the last explored location.
if (mLastTouchExploreEvent != null) {
- final int pointerId = pointerTracker.getLastReceivedUpPointerId();
// If the down was not in the time slop => nothing else to do.
final long eventTime =
@@ -413,7 +413,11 @@
final long deltaTime = eventTime - exploreTime;
if (deltaTime > ACTIVATION_TIME_SLOP) {
mSendHoverDelayed.forceSendAndRemove();
- scheduleHoverExit(event, policyFlags);
+ final int lastAction = mPointerTracker.getLastInjectedHoverAction();
+ if (lastAction != MotionEvent.ACTION_HOVER_EXIT) {
+ sendMotionEvent(event, MotionEvent.ACTION_HOVER_EXIT,
+ pointerIdBits, policyFlags);
+ }
mLastTouchExploreEvent = MotionEvent.obtain(event);
break;
}
@@ -427,7 +431,11 @@
final float deltaMove = (float) Math.hypot(deltaX, deltaY);
if (deltaMove > mTouchExplorationTapSlop) {
mSendHoverDelayed.forceSendAndRemove();
- scheduleHoverExit(event, policyFlags);
+ final int lastAction = mPointerTracker.getLastInjectedHoverAction();
+ if (lastAction != MotionEvent.ACTION_HOVER_EXIT) {
+ sendMotionEvent(event, MotionEvent.ACTION_HOVER_EXIT,
+ pointerIdBits, policyFlags);
+ }
mLastTouchExploreEvent = MotionEvent.obtain(event);
break;
}
@@ -438,7 +446,11 @@
mLastTouchExploreEvent = null;
} else {
mSendHoverDelayed.forceSendAndRemove();
- scheduleHoverExit(event, policyFlags);
+ final int lastAction = mPointerTracker.getLastInjectedHoverAction();
+ if (lastAction != MotionEvent.ACTION_HOVER_EXIT) {
+ sendMotionEvent(event, MotionEvent.ACTION_HOVER_EXIT,
+ pointerIdBits, policyFlags);
+ }
mLastTouchExploreEvent = MotionEvent.obtain(event);
}
} break;
@@ -448,8 +460,8 @@
final int lastAction = pointerTracker.getLastInjectedHoverAction();
if (lastAction != MotionEvent.ACTION_HOVER_EXIT) {
final int pointerId = pointerTracker.getPrimaryActivePointerId();
- final int pointerIndex = event.findPointerIndex(pointerId);
- sendHoverEvent(event, MotionEvent.ACTION_HOVER_EXIT, pointerIndex,
+ final int pointerIdBits = (1 << pointerId);
+ sendMotionEvent(event, MotionEvent.ACTION_HOVER_EXIT, pointerIdBits,
policyFlags);
}
clear();
@@ -464,6 +476,7 @@
* @param policyFlags The policy flags associated with the event.
*/
private void handleMotionEventStateDragging(MotionEvent event, int policyFlags) {
+ final int pointerIdBits = (1 << mDraggingPointerId);
switch (event.getActionMasked()) {
case MotionEvent.ACTION_DOWN: {
throw new IllegalStateException("Dragging state can be reached only if two "
@@ -473,7 +486,7 @@
// We are in dragging state so we have two pointers and another one
// goes down => delegate the three pointers to the view hierarchy
mCurrentState = STATE_DELEGATING;
- sendDragEvent(event, MotionEvent.ACTION_UP, policyFlags);
+ sendMotionEvent(event, MotionEvent.ACTION_UP, pointerIdBits, policyFlags);
sendDownForAllActiveNotInjectedPointers(event, policyFlags);
} break;
case MotionEvent.ACTION_MOVE: {
@@ -482,13 +495,15 @@
case 2: {
if (isDraggingGesture(event)) {
// If still dragging send a drag event.
- sendDragEvent(event, MotionEvent.ACTION_MOVE, policyFlags);
+ sendMotionEvent(event, MotionEvent.ACTION_MOVE, pointerIdBits,
+ policyFlags);
} else {
// The two pointers are moving either in different directions or
// no close enough => delegate the gesture to the view hierarchy.
mCurrentState = STATE_DELEGATING;
// Send an event to the end of the drag gesture.
- sendDragEvent(event, MotionEvent.ACTION_UP, policyFlags);
+ sendMotionEvent(event, MotionEvent.ACTION_UP, pointerIdBits,
+ policyFlags);
// Deliver all active pointers to the view hierarchy.
sendDownForAllActiveNotInjectedPointers(event, policyFlags);
}
@@ -496,7 +511,8 @@
default: {
mCurrentState = STATE_DELEGATING;
// Send an event to the end of the drag gesture.
- sendDragEvent(event, MotionEvent.ACTION_UP, policyFlags);
+ sendMotionEvent(event, MotionEvent.ACTION_UP, pointerIdBits,
+ policyFlags);
// Deliver all active pointers to the view hierarchy.
sendDownForAllActiveNotInjectedPointers(event, policyFlags);
}
@@ -505,7 +521,7 @@
case MotionEvent.ACTION_POINTER_UP: {
mCurrentState = STATE_TOUCH_EXPLORING;
// Send an event to the end of the drag gesture.
- sendDragEvent(event, MotionEvent.ACTION_UP, policyFlags);
+ sendMotionEvent(event, MotionEvent.ACTION_UP, pointerIdBits, policyFlags);
} break;
case MotionEvent.ACTION_CANCEL: {
clear();
@@ -551,23 +567,6 @@
}
/**
- * Schedules a hover up event so subsequent poking on the same location after
- * the scheduled delay will perform exploration.
- *
- * @param prototype The prototype from which to create the injected events.
- * @param policyFlags The policy flags associated with the event.
- */
- private void scheduleHoverExit(MotionEvent prototype,
- int policyFlags) {
- final int pointerId = mPointerTracker.getLastReceivedUpPointerId();
- final int pointerIndex = prototype.findPointerIndex(pointerId);
- // We want to no longer hover over the location so subsequent
- // touch at the same spot will generate a hover enter.
- mSendHoverDelayed.post(prototype, MotionEvent.ACTION_HOVER_EXIT,
- pointerIndex, policyFlags, ACTIVATION_TIME_SLOP);
- }
-
- /**
* Sends down events to the view hierarchy for all active pointers which are
* not already being delivered i.e. pointers that are not yet injected.
*
@@ -600,9 +599,9 @@
final long downTime = pointerTracker.getLastInjectedDownEventTime();
final int action = computeInjectionAction(MotionEvent.ACTION_DOWN, pointerDataIndex);
final int pointerCount = pointerDataIndex + 1;
- final long pointerDownTime = SystemClock.uptimeMillis();
+ final long eventTime = SystemClock.uptimeMillis();
- MotionEvent event = MotionEvent.obtain(downTime, pointerDownTime,
+ MotionEvent event = MotionEvent.obtain(downTime, eventTime,
action, pointerCount, pointerProperties, pointerCoords,
prototype.getMetaState(), prototype.getButtonState(),
prototype.getXPrecision(), prototype.getYPrecision(), prototype.getDeviceId(),
@@ -680,89 +679,18 @@
return;
}
- // Filter out inactive pointers from the event and inject it.
- final PointerProperties[] pointerProperties = mTempPointerProperties;
- final PointerCoords[] pointerCoords = mTempPointerCoords;
- int [] newToOldPointerIndexMap = mTempNewToOldPointerIndexMap;
- int newPointerIndex = 0;
- int actionIndex = prototype.getActionIndex();
-
- final int oldPointerCount = prototype.getPointerCount();
- for (int oldPointerIndex = 0; oldPointerIndex < oldPointerCount; oldPointerIndex++) {
- final int pointerId = prototype.getPointerId(oldPointerIndex);
-
+ int pointerIdBits = 0;
+ final int pointerCount = prototype.getPointerCount();
+ for (int pointerIndex = 0; pointerIndex < pointerCount; pointerIndex++) {
+ final int pointerId = prototype.getPointerId(pointerIndex);
// If the pointer is inactive or the pointer that just went up
// was inactive we strip the pointer data from the event.
- if (!pointerTracker.isActiveOrWasLastActiveUpPointer(pointerId)) {
- if (oldPointerIndex <= prototype.getActionIndex()) {
- actionIndex--;
- }
- continue;
+ if (pointerTracker.isActiveOrWasLastActiveUpPointer(pointerId)) {
+ pointerIdBits |= (1 << pointerId);
}
-
- newToOldPointerIndexMap[newPointerIndex] = oldPointerIndex;
- prototype.getPointerProperties(oldPointerIndex, pointerProperties[newPointerIndex]);
- prototype.getPointerCoords(oldPointerIndex, pointerCoords[newPointerIndex]);
-
- newPointerIndex++;
}
- // If we skipped all pointers => nothing to do.
- if (newPointerIndex == 0) {
- return;
- }
-
- // Populate and inject the event.
- final long downTime = pointerTracker.getLastInjectedDownEventTime();
- final int action = computeInjectionAction(prototype.getActionMasked(), actionIndex);
- final int newPointerCount = newPointerIndex;
- MotionEvent prunedEvent = MotionEvent.obtain(downTime, prototype.getEventTime(), action,
- newPointerCount, pointerProperties, pointerCoords,
- prototype.getMetaState(), prototype.getButtonState(),
- prototype.getXPrecision(), prototype.getYPrecision(), prototype.getDeviceId(),
- prototype.getEdgeFlags(), prototype.getSource(),prototype.getFlags());
-
- // Add the filtered history.
- final int historySize = prototype.getHistorySize();
- for (int historyIndex = 0; historyIndex < historySize; historyIndex++) {
- for (int pointerIndex = 0; pointerIndex < newPointerCount; pointerIndex++) {
- final int oldPointerIndex = newToOldPointerIndexMap[pointerIndex];
- prototype.getPointerCoords(oldPointerIndex, pointerCoords[pointerIndex]);
- }
- final long historicalTime = prototype.getHistoricalEventTime(historyIndex);
- prunedEvent.addBatch(historicalTime, pointerCoords, 0);
- }
-
- sendMotionEvent(prunedEvent, policyFlags);
- prunedEvent.recycle();
- }
-
- /**
- * Sends a dragging event from a two pointer event. The two pointers are
- * merged into one and delivered to the view hierarchy. Through the entire
- * drag gesture the pointer id delivered to the view hierarchy is the same.
- *
- * @param prototype The prototype from which to create the injected event.
- * @param action The dragging action that is to be injected.
- * @param policyFlags The policy flags associated with the event.
- */
- private void sendDragEvent(MotionEvent prototype, int action, int policyFlags) {
- final PointerProperties[] pointerProperties = mTempPointerProperties;
- final PointerCoords[] pointerCoords = mTempPointerCoords;
- final int pointerId = mDraggingPointerId;
- final int pointerIndex = prototype.findPointerIndex(pointerId);
-
- // Populate the event with the date of the dragging pointer and inject it.
- prototype.getPointerProperties(pointerIndex, pointerProperties[0]);
- prototype.getPointerCoords(pointerIndex, pointerCoords[0]);
-
- MotionEvent event = MotionEvent.obtain(prototype.getDownTime(),
- prototype.getEventTime(), action, 1, pointerProperties, pointerCoords,
- prototype.getMetaState(), prototype.getButtonState(),
- prototype.getXPrecision(), prototype.getYPrecision(),
- prototype.getDeviceId(), prototype.getEdgeFlags(), prototype.getSource(),
- prototype.getFlags());
-
+ MotionEvent event = prototype.split(pointerIdBits);
sendMotionEvent(event, policyFlags);
event.recycle();
}
@@ -798,32 +726,20 @@
}
/**
- * Sends a hover event.
+ * Sends an event.
*
- * @param prototype The prototype from which to create the injected event.
- * @param action The hover action.
- * @param pointerIndex The action pointer index.
+ * @param event The event to send.
+ * @param action The action of the event.
+ * @param pointerIdBits The bits of the pointers to send.
* @param policyFlags The policy flags associated with the event.
*/
- private void sendHoverEvent(MotionEvent prototype, int action, int pointerIndex, int
- policyFlags) {
- final PointerProperties[] pointerProperties = mTempPointerProperties;
- final PointerCoords[] pointerCoords = mTempPointerCoords;
-
- prototype.getPointerProperties(pointerIndex, pointerProperties[0]);
- prototype.getPointerCoords(pointerIndex, pointerCoords[0]);
-
- final long downTime = mPointerTracker.getLastInjectedDownEventTime();
-
- // Populate and inject a hover event.
- MotionEvent hoverEvent = MotionEvent.obtain(downTime, prototype.getEventTime(), action,
- 1, pointerProperties, pointerCoords,
- prototype.getMetaState(), prototype.getButtonState(),
- prototype.getXPrecision(), prototype.getYPrecision(), prototype.getDeviceId(),
- prototype.getEdgeFlags(), prototype.getSource(), prototype.getFlags());
-
- sendMotionEvent(hoverEvent, policyFlags);
- hoverEvent.recycle();
+ private void sendMotionEvent(MotionEvent prototype, int action, int pointerIdBits,
+ int policyFlags) {
+ MotionEvent event = prototype.split(pointerIdBits);
+ event.setDownTime(mPointerTracker.getLastInjectedDownEventTime());
+ event.setAction(action);
+ sendMotionEvent(event, policyFlags);
+ event.recycle();
}
/**
@@ -1381,6 +1297,9 @@
final int pointerId = event.getPointerId(pointerIndex);
final int pointerFlag = (1 << pointerId);
mInjectedPointersDown &= ~pointerFlag;
+ if (mInjectedPointersDown == 0) {
+ mLastInjectedDownEventTime = 0;
+ }
}
/**
@@ -1481,15 +1400,15 @@
private MotionEvent mEvent;
private int mAction;
- private int mPointerIndex;
+ private int mPointerIdBits;
private int mPolicyFlags;
- public void post(MotionEvent prototype, int action, int pointerIndex, int policyFlags,
+ public void post(MotionEvent prototype, int action, int pointerIdBits, int policyFlags,
long delay) {
remove();
mEvent = MotionEvent.obtain(prototype);
mAction = action;
- mPointerIndex = pointerIndex;
+ mPointerIdBits = pointerIdBits;
mPolicyFlags = policyFlags;
mHandler.postDelayed(this, delay);
}
@@ -1510,7 +1429,7 @@
mEvent.recycle();
mEvent = null;
mAction = 0;
- mPointerIndex = -1;
+ mPointerIdBits = -1;
mPolicyFlags = 0;
}
@@ -1532,7 +1451,7 @@
}
}
- sendHoverEvent(mEvent, mAction, mPointerIndex, mPolicyFlags);
+ sendMotionEvent(mEvent, mAction, mPointerIdBits, mPolicyFlags);
clear();
}
}
diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java
index f6ae523..5aae539 100644
--- a/services/java/com/android/server/am/ActivityManagerService.java
+++ b/services/java/com/android/server/am/ActivityManagerService.java
@@ -25,6 +25,7 @@
import com.android.server.SystemServer;
import com.android.server.Watchdog;
import com.android.server.am.ActivityStack.ActivityState;
+import com.android.server.net.NetworkPolicyManagerService;
import com.android.server.wm.WindowManagerService;
import dalvik.system.Zygote;
@@ -751,6 +752,8 @@
*/
final UsageStatsService mUsageStatsService;
+ final NetworkPolicyManagerService mNetworkPolicyService;
+
/**
* Current configuration information. HistoryRecord objects are given
* a reference to this object to indicate which configuration they are
@@ -971,6 +974,8 @@
static final int CHECK_EXCESSIVE_WAKE_LOCKS_MSG = 27;
static final int CLEAR_DNS_CACHE = 28;
static final int UPDATE_HTTP_PROXY = 29;
+ static final int DISPATCH_FOREGROUND_ACTIVITIES_CHANGED = 30;
+ static final int DISPATCH_PROCESS_DIED = 31;
AlertDialog mUidAlert;
@@ -1271,6 +1276,19 @@
sendMessageDelayed(nmsg, POWER_CHECK_DELAY);
}
} break;
+ case DISPATCH_FOREGROUND_ACTIVITIES_CHANGED: {
+ // Flag might have changed during dispatch, but it's always
+ // consistent since we dispatch for every change.
+ final ProcessRecord app = (ProcessRecord) msg.obj;
+ mNetworkPolicyService.onForegroundActivitiesChanged(
+ app.info.uid, app.pid, app.foregroundActivities);
+ break;
+ }
+ case DISPATCH_PROCESS_DIED: {
+ final ProcessRecord app = (ProcessRecord) msg.obj;
+ mNetworkPolicyService.onProcessDied(app.info.uid, app.pid);
+ break;
+ }
}
}
};
@@ -1340,6 +1358,7 @@
m.mBatteryStatsService.publish(context);
m.mUsageStatsService.publish(context);
+ m.mNetworkPolicyService.publish(context);
synchronized (thr) {
thr.mReady = true;
@@ -1461,6 +1480,8 @@
mUsageStatsService = new UsageStatsService(new File(
systemDir, "usagestats").toString());
+ mNetworkPolicyService = new NetworkPolicyManagerService();
+
GL_ES_VERSION = SystemProperties.getInt("ro.opengles.version",
ConfigurationInfo.GL_ES_VERSION_UNDEFINED);
@@ -1743,7 +1764,7 @@
mLruSeq++;
updateLruProcessInternalLocked(app, oomAdj, updateActivityTime, 0);
}
-
+
final ProcessRecord getProcessRecordLocked(
String processName, int uid) {
if (uid == Process.SYSTEM_UID) {
@@ -3339,7 +3360,8 @@
private final boolean forceStopPackageLocked(String name, int uid,
boolean callerWillRestart, boolean purgeCache, boolean doit) {
- int i, N;
+ int i;
+ int N;
if (uid < 0) {
try {
@@ -6062,6 +6084,7 @@
mUsageStatsService.shutdown();
mBatteryStatsService.shutdown();
+ mNetworkPolicyService.shutdown();
return timedout;
}
@@ -8691,9 +8714,17 @@
schedGroup = Integer.toString(r.setSchedGroup);
break;
}
- pw.println(String.format("%s%s #%2d: adj=%s/%s %s (%s)",
+ String foreground;
+ if (r.foregroundActivities) {
+ foreground = "A";
+ } else if (r.foregroundServices) {
+ foreground = "S";
+ } else {
+ foreground = " ";
+ }
+ pw.println(String.format("%s%s #%2d: adj=%s/%s%s %s (%s)",
prefix, (r.persistent ? persistentLabel : normalLabel),
- N-i, oomAdj, schedGroup, r.toShortString(), r.adjType));
+ N-i, oomAdj, schedGroup, foreground, r.toShortString(), r.adjType));
if (r.adjSource != null || r.adjTarget != null) {
pw.print(prefix);
pw.print(" ");
@@ -9069,6 +9100,7 @@
app.thread = null;
app.forcingToForeground = null;
app.foregroundServices = false;
+ app.foregroundActivities = false;
killServicesLocked(app, true);
@@ -9162,6 +9194,8 @@
}
}
+ mHandler.obtainMessage(DISPATCH_PROCESS_DIED, app).sendToTarget();
+
// If the caller is restarting this app, then leave it in its
// current lists and let the caller take care of it.
if (restarting) {
@@ -12400,25 +12434,30 @@
app.keeping = true;
app.curSchedGroup = Process.THREAD_GROUP_DEFAULT;
return (app.curAdj=app.maxAdj);
- }
-
+ }
+
+ final boolean hadForegroundActivities = app.foregroundActivities;
+
app.adjTypeCode = ActivityManager.RunningAppProcessInfo.REASON_UNKNOWN;
app.adjSource = null;
app.adjTarget = null;
app.keeping = false;
app.empty = false;
app.hidden = false;
+ app.foregroundActivities = false;
+
+ final int activitiesSize = app.activities.size();
// Determine the importance of the process, starting with most
// important to least, and assign an appropriate OOM adjustment.
int adj;
int schedGroup;
- int N;
if (app == TOP_APP) {
// The last app on the list is the foreground app.
adj = FOREGROUND_APP_ADJ;
schedGroup = Process.THREAD_GROUP_DEFAULT;
app.adjType = "top-activity";
+ app.foregroundActivities = true;
} else if (app.instrumentationClass != null) {
// Don't want to kill running instrumentation.
adj = FOREGROUND_APP_ADJ;
@@ -12437,54 +12476,64 @@
adj = FOREGROUND_APP_ADJ;
schedGroup = Process.THREAD_GROUP_DEFAULT;
app.adjType = "exec-service";
- } else if ((N=app.activities.size()) != 0) {
+ } else if (activitiesSize > 0) {
// This app is in the background with paused activities.
- app.hidden = true;
+ // We inspect activities to potentially upgrade adjustment further below.
adj = hiddenAdj;
schedGroup = Process.THREAD_GROUP_BG_NONINTERACTIVE;
+ app.hidden = true;
app.adjType = "bg-activities";
- N = app.activities.size();
- for (int j=0; j<N; j++) {
- ActivityRecord r = app.activities.get(j);
- if (r.visible) {
- // This app has a visible activity!
- app.hidden = false;
- adj = VISIBLE_APP_ADJ;
- schedGroup = Process.THREAD_GROUP_DEFAULT;
- app.adjType = "visible";
- break;
- } else if (r.state == ActivityState.PAUSING
- || r.state == ActivityState.PAUSED
- || r.state == ActivityState.STOPPING) {
- adj = PERCEPTIBLE_APP_ADJ;
- app.adjType = "stopping";
- }
- }
} else {
// A very not-needed process. If this is lower in the lru list,
// we will push it in to the empty bucket.
+ adj = hiddenAdj;
+ schedGroup = Process.THREAD_GROUP_BG_NONINTERACTIVE;
app.hidden = true;
app.empty = true;
- schedGroup = Process.THREAD_GROUP_BG_NONINTERACTIVE;
- adj = hiddenAdj;
app.adjType = "bg-empty";
}
-
+
+ // Examine all activities if not already foreground.
+ if (!app.foregroundActivities && activitiesSize > 0) {
+ for (int j = 0; j < activitiesSize; j++) {
+ final ActivityRecord r = app.activities.get(j);
+ if (r.visible) {
+ // App has a visible activity; only upgrade adjustment.
+ if (adj > VISIBLE_APP_ADJ) {
+ adj = VISIBLE_APP_ADJ;
+ app.adjType = "visible";
+ }
+ schedGroup = Process.THREAD_GROUP_DEFAULT;
+ app.hidden = false;
+ app.foregroundActivities = true;
+ break;
+ } else if (r.state == ActivityState.PAUSING || r.state == ActivityState.PAUSED
+ || r.state == ActivityState.STOPPING) {
+ // Only upgrade adjustment.
+ if (adj > PERCEPTIBLE_APP_ADJ) {
+ adj = PERCEPTIBLE_APP_ADJ;
+ app.adjType = "stopping";
+ }
+ app.foregroundActivities = true;
+ }
+ }
+ }
+
if (adj > PERCEPTIBLE_APP_ADJ) {
if (app.foregroundServices) {
// The user is aware of this app, so make it visible.
adj = PERCEPTIBLE_APP_ADJ;
- schedGroup = Process.THREAD_GROUP_DEFAULT;
app.adjType = "foreground-service";
+ schedGroup = Process.THREAD_GROUP_DEFAULT;
} else if (app.forcingToForeground != null) {
// The user is aware of this app, so make it visible.
adj = PERCEPTIBLE_APP_ADJ;
- schedGroup = Process.THREAD_GROUP_DEFAULT;
app.adjType = "force-foreground";
app.adjSource = app.forcingToForeground;
+ schedGroup = Process.THREAD_GROUP_DEFAULT;
}
}
-
+
if (adj > HEAVY_WEIGHT_APP_ADJ && app == mHeavyWeightProcess) {
// We don't want to kill the current heavy-weight process.
adj = HEAVY_WEIGHT_APP_ADJ;
@@ -12704,7 +12753,11 @@
app.curAdj = adj;
app.curSchedGroup = schedGroup;
-
+
+ if (hadForegroundActivities != app.foregroundActivities) {
+ mHandler.obtainMessage(DISPATCH_FOREGROUND_ACTIVITIES_CHANGED, app).sendToTarget();
+ }
+
return adj;
}
@@ -12937,13 +12990,15 @@
}
private final boolean updateOomAdjLocked(
- ProcessRecord app, int hiddenAdj, ProcessRecord TOP_APP) {
+ ProcessRecord app, int hiddenAdj, ProcessRecord TOP_APP) {
app.hiddenAdj = hiddenAdj;
if (app.thread == null) {
return true;
}
+ boolean success = true;
+
final boolean wasKeeping = app.keeping;
int adj = computeOomAdjLocked(app, hiddenAdj, TOP_APP, false);
@@ -12983,7 +13038,7 @@
" oom adj to " + adj);
app.setAdj = adj;
} else {
- return false;
+ success = false;
}
}
if (app.setSchedGroup != app.curSchedGroup) {
@@ -13022,7 +13077,7 @@
}
}
- return true;
+ return success;
}
private final ActivityRecord resumedAppLocked() {
diff --git a/services/java/com/android/server/am/ProcessRecord.java b/services/java/com/android/server/am/ProcessRecord.java
index 5be35ee..beef136 100644
--- a/services/java/com/android/server/am/ProcessRecord.java
+++ b/services/java/com/android/server/am/ProcessRecord.java
@@ -64,6 +64,7 @@
boolean keeping; // Actively running code so don't kill due to that?
boolean setIsForeground; // Running foreground UI when last set?
boolean foregroundServices; // Running any services that are foreground?
+ boolean foregroundActivities; // Running any activities that are foreground?
boolean bad; // True if disabled in the bad process list
boolean killedBackground; // True when proc has been killed due to too many bg
String waitingToKill; // Process is waiting to be killed when in the bg; reason
diff --git a/services/java/com/android/server/connectivity/Tethering.java b/services/java/com/android/server/connectivity/Tethering.java
index 316db2e..e8155b4 100644
--- a/services/java/com/android/server/connectivity/Tethering.java
+++ b/services/java/com/android/server/connectivity/Tethering.java
@@ -636,6 +636,16 @@
return retVal;
}
+ public void handleTetherIfaceChange(String iface) {
+ // check if iface is white listed
+ for (String regex : mUpstreamIfaceRegexs) {
+ if (iface.matches(regex)) {
+ if (DEBUG) Log.d(TAG, "Tethering got Interface Change");
+ mTetherMasterSM.sendMessage(TetherMasterSM.CMD_IFACE_CHANGED, iface);
+ break;
+ }
+ }
+ }
class TetherInterfaceSM extends StateMachine {
// notification from the master SM that it's not in tether mode
@@ -1034,6 +1044,8 @@
static final int CMD_CELL_CONNECTION_RENEW = 4;
// we don't have a valid upstream conn, check again after a delay
static final int CMD_RETRY_UPSTREAM = 5;
+ // received an indication that upstream interface has changed
+ static final int CMD_IFACE_CHANGED = 6;
// This indicates what a timeout event relates to. A state that
// sends itself a delayed timeout event and handles incoming timeout events
@@ -1377,13 +1389,18 @@
turnOnMobileConnection();
}
break;
- case CMD_RETRY_UPSTREAM:
- chooseUpstreamType(mTryCell);
- mTryCell = !mTryCell;
- break;
- default:
- retValue = false;
- break;
+ case CMD_RETRY_UPSTREAM:
+ chooseUpstreamType(mTryCell);
+ mTryCell = !mTryCell;
+ break;
+ case CMD_IFACE_CHANGED:
+ String iface = (String)message.obj;
+ if (DEBUG) Log.d(TAG, "Activie upstream interface changed: " + iface);
+ notifyTetheredOfNewUpstreamIface(iface);
+ break;
+ default:
+ retValue = false;
+ break;
}
return retValue;
}
diff --git a/services/java/com/android/server/net/NetworkPolicyManagerService.java b/services/java/com/android/server/net/NetworkPolicyManagerService.java
new file mode 100644
index 0000000..a7a4f07
--- /dev/null
+++ b/services/java/com/android/server/net/NetworkPolicyManagerService.java
@@ -0,0 +1,165 @@
+/*
+ * 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.server.net;
+
+import static android.Manifest.permission.MANAGE_APP_TOKENS;
+import static android.Manifest.permission.UPDATE_DEVICE_STATS;
+import static android.net.NetworkPolicyManager.POLICY_NONE;
+import static android.net.NetworkPolicyManager.POLICY_REJECT_PAID;
+import static android.net.NetworkPolicyManager.POLICY_REJECT_BACKGROUND;
+
+import android.content.Context;
+import android.net.INetworkPolicyManager;
+import android.os.ServiceManager;
+import android.util.Log;
+import android.util.SparseArray;
+import android.util.SparseBooleanArray;
+import android.util.SparseIntArray;
+
+/**
+ * Service that maintains low-level network policy rules and collects usage
+ * statistics to drive those rules.
+ */
+public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
+ private static final String TAG = "NetworkPolicy";
+ private static final boolean LOGD = true;
+
+ private static final String SERVICE_NAME = "netpolicy";
+
+ private Context mContext;
+
+ /** Current network policy for each UID. */
+ private SparseIntArray mUidPolicy;
+
+ /** Foreground at both UID and PID granularity. */
+ private SparseBooleanArray mUidForeground;
+ private SparseArray<SparseBooleanArray> mUidPidForeground;
+
+ // TODO: periodically poll network stats and write to disk
+ // TODO: save/restore policy information from disk
+
+ // TODO: watch screen on/off broadcasts to track foreground
+
+ public void publish(Context context) {
+ mContext = context;
+ ServiceManager.addService(SERVICE_NAME, asBinder());
+
+ mUidPolicy = new SparseIntArray();
+ mUidForeground = new SparseBooleanArray();
+ mUidPidForeground = new SparseArray<SparseBooleanArray>();
+
+ // TODO: register for NetworkManagementService callbacks
+ // TODO: read current policy+stats from disk and generate NMS rules
+ }
+
+ public void shutdown() {
+ // TODO: persist any pending stats during clean shutdown
+
+ mUidPolicy = null;
+ mUidForeground = null;
+ mUidPidForeground = null;
+ }
+
+ @Override
+ public void onForegroundActivitiesChanged(int uid, int pid, boolean foreground) {
+ // only someone like AMS should only be calling us
+ mContext.enforceCallingOrSelfPermission(
+ MANAGE_APP_TOKENS, "requires MANAGE_APP_TOKENS permission");
+
+ // because a uid can have multiple pids running inside, we need to
+ // remember all pid states and summarize foreground at uid level.
+
+ // record foreground for this specific pid
+ SparseBooleanArray pidForeground = mUidPidForeground.get(uid);
+ if (pidForeground == null) {
+ pidForeground = new SparseBooleanArray(2);
+ mUidPidForeground.put(uid, pidForeground);
+ }
+ pidForeground.put(pid, foreground);
+ computeUidForeground(uid);
+ }
+
+ @Override
+ public void onProcessDied(int uid, int pid) {
+ // only someone like AMS should only be calling us
+ mContext.enforceCallingOrSelfPermission(
+ MANAGE_APP_TOKENS, "requires MANAGE_APP_TOKENS permission");
+
+ // clear records and recompute, when they exist
+ final SparseBooleanArray pidForeground = mUidPidForeground.get(uid);
+ if (pidForeground != null) {
+ pidForeground.delete(pid);
+ computeUidForeground(uid);
+ }
+ }
+
+ @Override
+ public void setUidPolicy(int uid, int policy) {
+ mContext.enforceCallingOrSelfPermission(
+ UPDATE_DEVICE_STATS, "requires UPDATE_DEVICE_STATS permission");
+ mUidPolicy.put(uid, policy);
+ }
+
+ @Override
+ public int getUidPolicy(int uid) {
+ return mUidPolicy.get(uid, POLICY_NONE);
+ }
+
+ /**
+ * Foreground for PID changed; recompute foreground at UID level. If
+ * changed, will trigger {@link #updateRulesForUid(int)}.
+ */
+ private void computeUidForeground(int uid) {
+ final SparseBooleanArray pidForeground = mUidPidForeground.get(uid);
+
+ // current pid is dropping foreground; examine other pids
+ boolean uidForeground = false;
+ final int size = pidForeground.size();
+ for (int i = 0; i < size; i++) {
+ if (pidForeground.valueAt(i)) {
+ uidForeground = true;
+ break;
+ }
+ }
+
+ final boolean oldUidForeground = mUidForeground.get(uid, false);
+ if (oldUidForeground != uidForeground) {
+ // foreground changed, push updated rules
+ mUidForeground.put(uid, uidForeground);
+ updateRulesForUid(uid);
+ }
+ }
+
+ private void updateRulesForUid(int uid) {
+ final boolean uidForeground = mUidForeground.get(uid, false);
+ final int uidPolicy = getUidPolicy(uid);
+
+ if (LOGD) {
+ Log.d(TAG, "updateRulesForUid(uid=" + uid + ") found foreground=" + uidForeground
+ + " and policy=" + uidPolicy);
+ }
+
+ if (!uidForeground && (uidPolicy & POLICY_REJECT_BACKGROUND) != 0) {
+ // TODO: build updated rules and push to NMS
+ } else if ((uidPolicy & POLICY_REJECT_PAID) != 0) {
+ // TODO: build updated rules and push to NMS
+ } else {
+ // TODO: build updated rules and push to NMS
+ }
+ }
+
+}
diff --git a/services/java/com/android/server/pm/PackageManagerService.java b/services/java/com/android/server/pm/PackageManagerService.java
index de439ca..e1fbe1c 100644
--- a/services/java/com/android/server/pm/PackageManagerService.java
+++ b/services/java/com/android/server/pm/PackageManagerService.java
@@ -59,6 +59,7 @@
import android.content.pm.PackageManager;
import android.content.pm.PackageParser;
import android.content.pm.PackageStats;
+import android.content.pm.ParceledListSlice;
import android.content.pm.PermissionGroupInfo;
import android.content.pm.PermissionInfo;
import android.content.pm.ProviderInfo;
@@ -2371,63 +2372,112 @@
}
}
- public List<PackageInfo> getInstalledPackages(int flags) {
- final ArrayList<PackageInfo> finalList = new ArrayList<PackageInfo>();
+ private static final int getContinuationPoint(final String[] keys, final String key) {
+ final int index;
+ if (key == null) {
+ index = 0;
+ } else {
+ final int insertPoint = Arrays.binarySearch(keys, key);
+ if (insertPoint < 0) {
+ index = -insertPoint;
+ } else {
+ index = insertPoint + 1;
+ }
+ }
+ return index;
+ }
+
+ public ParceledListSlice<PackageInfo> getInstalledPackages(int flags, String lastRead) {
+ final ParceledListSlice<PackageInfo> list = new ParceledListSlice<PackageInfo>();
+ final boolean listUninstalled = (flags & PackageManager.GET_UNINSTALLED_PACKAGES) != 0;
+ final String[] keys;
// writer
synchronized (mPackages) {
- if((flags & PackageManager.GET_UNINSTALLED_PACKAGES) != 0) {
- final Iterator<PackageSetting> i = mSettings.mPackages.values().iterator();
- while (i.hasNext()) {
- final PackageSetting ps = i.next();
- final PackageInfo psPkg = generatePackageInfoFromSettingsLPw(ps.name, flags);
- if (psPkg != null) {
- finalList.add(psPkg);
+ if (listUninstalled) {
+ keys = mSettings.mPackages.keySet().toArray(new String[mSettings.mPackages.size()]);
+ } else {
+ keys = mPackages.keySet().toArray(new String[mPackages.size()]);
+ }
+
+ Arrays.sort(keys);
+ int i = getContinuationPoint(keys, lastRead);
+ final int N = keys.length;
+
+ while (i < N) {
+ final String packageName = keys[i++];
+
+ PackageInfo pi = null;
+ if (listUninstalled) {
+ final PackageSetting ps = mSettings.mPackages.get(packageName);
+ if (ps != null) {
+ pi = generatePackageInfoFromSettingsLPw(ps.name, flags);
+ }
+ } else {
+ final PackageParser.Package p = mPackages.get(packageName);
+ if (p != null) {
+ pi = generatePackageInfo(p, flags);
}
}
- } else {
- final Iterator<PackageParser.Package> i = mPackages.values().iterator();
- while (i.hasNext()) {
- final PackageParser.Package p = i.next();
- if (p.applicationInfo != null) {
- final PackageInfo pi = generatePackageInfo(p, flags);
- if (pi != null) {
- finalList.add(pi);
- }
- }
+
+ if (pi != null && !list.append(pi)) {
+ break;
}
}
+
+ if (i == N) {
+ list.setLastSlice(true);
+ }
}
- return finalList;
+
+ return list;
}
- public List<ApplicationInfo> getInstalledApplications(int flags) {
- final ArrayList<ApplicationInfo> finalList = new ArrayList<ApplicationInfo>();
+ public ParceledListSlice<ApplicationInfo> getInstalledApplications(int flags,
+ String lastRead) {
+ final ParceledListSlice<ApplicationInfo> list = new ParceledListSlice<ApplicationInfo>();
+ final boolean listUninstalled = (flags & PackageManager.GET_UNINSTALLED_PACKAGES) != 0;
+ final String[] keys;
+
// writer
- synchronized(mPackages) {
- if((flags & PackageManager.GET_UNINSTALLED_PACKAGES) != 0) {
- final Iterator<PackageSetting> i = mSettings.mPackages.values().iterator();
- while (i.hasNext()) {
- final PackageSetting ps = i.next();
- ApplicationInfo ai = generateApplicationInfoFromSettingsLPw(ps.name, flags);
- if(ai != null) {
- finalList.add(ai);
+ synchronized (mPackages) {
+ if (listUninstalled) {
+ keys = mSettings.mPackages.keySet().toArray(new String[mSettings.mPackages.size()]);
+ } else {
+ keys = mPackages.keySet().toArray(new String[mPackages.size()]);
+ }
+
+ Arrays.sort(keys);
+ int i = getContinuationPoint(keys, lastRead);
+ final int N = keys.length;
+
+ while (i < N) {
+ final String packageName = keys[i++];
+
+ ApplicationInfo ai = null;
+ if (listUninstalled) {
+ final PackageSetting ps = mSettings.mPackages.get(packageName);
+ if (ps != null) {
+ ai = generateApplicationInfoFromSettingsLPw(ps.name, flags);
+ }
+ } else {
+ final PackageParser.Package p = mPackages.get(packageName);
+ if (p != null) {
+ ai = PackageParser.generateApplicationInfo(p, flags);
}
}
- } else {
- final Iterator<PackageParser.Package> i = mPackages.values().iterator();
- while (i.hasNext()) {
- final PackageParser.Package p = i.next();
- if (p.applicationInfo != null) {
- ApplicationInfo ai = PackageParser.generateApplicationInfo(p, flags);
- if(ai != null) {
- finalList.add(ai);
- }
- }
+
+ if (ai != null && !list.append(ai)) {
+ break;
}
}
+
+ if (i == N) {
+ list.setLastSlice(true);
+ }
}
- return finalList;
+
+ return list;
}
public List<ApplicationInfo> getPersistentApplications(int flags) {
@@ -8052,7 +8102,8 @@
}
public UserInfo createUser(String name, int flags) {
- UserInfo userInfo = mUserManager.createUser(name, flags, getInstalledApplications(0));
+ // TODO(kroot): fix this API
+ UserInfo userInfo = mUserManager.createUser(name, flags, new ArrayList<ApplicationInfo>());
return userInfo;
}
diff --git a/services/java/com/android/server/wm/BlackFrame.java b/services/java/com/android/server/wm/BlackFrame.java
new file mode 100644
index 0000000..f9f5758
--- /dev/null
+++ b/services/java/com/android/server/wm/BlackFrame.java
@@ -0,0 +1,139 @@
+/*
+ * 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.server.wm;
+
+import android.graphics.Matrix;
+import android.graphics.PixelFormat;
+import android.graphics.Rect;
+import android.util.Slog;
+import android.view.Surface;
+import android.view.SurfaceSession;
+
+/**
+ * Four black surfaces put together to make a black frame.
+ */
+public class BlackFrame {
+ class BlackSurface {
+ final int left;
+ final int top;
+ final Surface surface;
+
+ BlackSurface(SurfaceSession session, int layer, int l, int t, int w, int h)
+ throws Surface.OutOfResourcesException {
+ left = l;
+ top = t;
+ surface = new Surface(session, 0, "BlackSurface",
+ -1, w, h, PixelFormat.OPAQUE, Surface.FX_SURFACE_DIM);
+ surface.setAlpha(1.0f);
+ surface.setLayer(layer);
+ }
+
+ void setMatrix(Matrix matrix) {
+ mTmpMatrix.setTranslate(left, top);
+ mTmpMatrix.postConcat(matrix);
+ mTmpMatrix.getValues(mTmpFloats);
+ surface.setPosition((int)mTmpFloats[Matrix.MTRANS_X],
+ (int)mTmpFloats[Matrix.MTRANS_Y]);
+ surface.setMatrix(
+ mTmpFloats[Matrix.MSCALE_X], mTmpFloats[Matrix.MSKEW_Y],
+ mTmpFloats[Matrix.MSKEW_X], mTmpFloats[Matrix.MSCALE_Y]);
+ if (false) {
+ Slog.i(WindowManagerService.TAG, "Black Surface @ (" + left + "," + top + "): ("
+ + mTmpFloats[Matrix.MTRANS_X] + ","
+ + mTmpFloats[Matrix.MTRANS_Y] + ") matrix=["
+ + mTmpFloats[Matrix.MSCALE_X] + ","
+ + mTmpFloats[Matrix.MSCALE_Y] + "]["
+ + mTmpFloats[Matrix.MSKEW_X] + ","
+ + mTmpFloats[Matrix.MSKEW_Y] + "]");
+ }
+ }
+
+ void clearMatrix() {
+ surface.setMatrix(1, 0, 0, 1);
+ }
+ }
+
+ final Matrix mTmpMatrix = new Matrix();
+ final float[] mTmpFloats = new float[9];
+ final BlackSurface[] mBlackSurfaces = new BlackSurface[4];
+
+ public BlackFrame(SurfaceSession session, Rect outer, Rect inner,
+ int layer) throws Surface.OutOfResourcesException {
+ boolean success = false;
+
+ try {
+ if (outer.top < inner.top) {
+ mBlackSurfaces[0] = new BlackSurface(session, layer,
+ outer.left, outer.top, inner.right, inner.top);
+ }
+ if (outer.left < inner.left) {
+ mBlackSurfaces[1] = new BlackSurface(session, layer,
+ outer.left, inner.top, inner.left, outer.bottom);
+ }
+ if (outer.bottom > inner.bottom) {
+ mBlackSurfaces[2] = new BlackSurface(session, layer,
+ inner.left, inner.bottom, outer.right, outer.bottom);
+ }
+ if (outer.right > inner.right) {
+ mBlackSurfaces[3] = new BlackSurface(session, layer,
+ inner.right, outer.top, outer.right, inner.bottom);
+ }
+ success = true;
+ } finally {
+ if (!success) {
+ kill();
+ }
+ }
+ }
+
+ public void kill() {
+ if (mBlackSurfaces != null) {
+ for (int i=0; i<mBlackSurfaces.length; i++) {
+ if (mBlackSurfaces[i] != null) {
+ mBlackSurfaces[i].surface.destroy();
+ mBlackSurfaces[i] = null;
+ }
+ }
+ }
+ }
+
+ public void hide() {
+ if (mBlackSurfaces != null) {
+ for (int i=0; i<mBlackSurfaces.length; i++) {
+ if (mBlackSurfaces[i] != null) {
+ mBlackSurfaces[i].surface.hide();
+ }
+ }
+ }
+ }
+
+ public void setMatrix(Matrix matrix) {
+ for (int i=0; i<mBlackSurfaces.length; i++) {
+ if (mBlackSurfaces[i] != null) {
+ mBlackSurfaces[i].setMatrix(matrix);
+ }
+ }
+ }
+
+ public void clearMatrix() {
+ for (int i=0; i<mBlackSurfaces.length; i++) {
+ if (mBlackSurfaces[i] != null) {
+ mBlackSurfaces[i].clearMatrix();
+ }
+ }
+ }
+}
diff --git a/services/java/com/android/server/wm/DragState.java b/services/java/com/android/server/wm/DragState.java
index c8f8ff3..118cd55 100644
--- a/services/java/com/android/server/wm/DragState.java
+++ b/services/java/com/android/server/wm/DragState.java
@@ -156,9 +156,8 @@
}
if (mDragInProgress && newWin.isPotentialDragTarget()) {
- DragEvent event = DragEvent.obtain(DragEvent.ACTION_DRAG_STARTED,
- touchX - newWin.mFrame.left, touchY - newWin.mFrame.top,
- null, desc, null, false);
+ DragEvent event = obtainDragEvent(newWin, DragEvent.ACTION_DRAG_STARTED,
+ touchX, touchY, null, desc, null, false);
try {
newWin.mClient.dispatchDragEvent(event);
// track each window that we've notified that the drag is starting
@@ -267,9 +266,8 @@
Slog.d(WindowManagerService.TAG, "sending DRAG_EXITED to " + mTargetWindow);
}
// force DRAG_EXITED_EVENT if appropriate
- DragEvent evt = DragEvent.obtain(DragEvent.ACTION_DRAG_EXITED,
- x - mTargetWindow.mFrame.left, y - mTargetWindow.mFrame.top,
- null, null, null, false);
+ DragEvent evt = obtainDragEvent(mTargetWindow, DragEvent.ACTION_DRAG_EXITED,
+ x, y, null, null, null, false);
mTargetWindow.mClient.dispatchDragEvent(evt);
if (myPid != mTargetWindow.mSession.mPid) {
evt.recycle();
@@ -279,9 +277,8 @@
if (false && WindowManagerService.DEBUG_DRAG) {
Slog.d(WindowManagerService.TAG, "sending DRAG_LOCATION to " + touchedWin);
}
- DragEvent evt = DragEvent.obtain(DragEvent.ACTION_DRAG_LOCATION,
- x - touchedWin.mFrame.left, y - touchedWin.mFrame.top,
- null, null, null, false);
+ DragEvent evt = obtainDragEvent(touchedWin, DragEvent.ACTION_DRAG_LOCATION,
+ x, y, null, null, null, false);
touchedWin.mClient.dispatchDragEvent(evt);
if (myPid != touchedWin.mSession.mPid) {
evt.recycle();
@@ -310,8 +307,7 @@
}
final int myPid = Process.myPid();
final IBinder token = touchedWin.mClient.asBinder();
- DragEvent evt = DragEvent.obtain(DragEvent.ACTION_DROP,
- x - touchedWin.mFrame.left, y - touchedWin.mFrame.top,
+ DragEvent evt = obtainDragEvent(touchedWin, DragEvent.ACTION_DROP, x, y,
null, null, mData, false);
try {
touchedWin.mClient.dispatchDragEvent(evt);
@@ -365,4 +361,16 @@
return touchedWin;
}
+
+ private static DragEvent obtainDragEvent(WindowState win, int action,
+ float x, float y, Object localState,
+ ClipDescription description, ClipData data, boolean result) {
+ float winX = x - win.mFrame.left;
+ float winY = y - win.mFrame.top;
+ if (win.mEnforceSizeCompat) {
+ winX *= win.mGlobalScale;
+ winY *= win.mGlobalScale;
+ }
+ return DragEvent.obtain(action, winX, winY, localState, description, data, result);
+ }
}
\ No newline at end of file
diff --git a/services/java/com/android/server/wm/FadeInOutAnimation.java b/services/java/com/android/server/wm/FadeInOutAnimation.java
deleted file mode 100644
index 06f7657..0000000
--- a/services/java/com/android/server/wm/FadeInOutAnimation.java
+++ /dev/null
@@ -1,44 +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.
- */
-
-package com.android.server.wm;
-
-import android.view.animation.AccelerateInterpolator;
-import android.view.animation.Animation;
-import android.view.animation.Transformation;
-
-/**
- * Animation that fade in after 0.5 interpolate time, or fade out in reverse order.
- * This is used for opening/closing transition for apps in compatible mode.
- */
-class FadeInOutAnimation extends Animation {
- boolean mFadeIn;
-
- public FadeInOutAnimation(boolean fadeIn) {
- setInterpolator(new AccelerateInterpolator());
- setDuration(WindowManagerService.DEFAULT_FADE_IN_OUT_DURATION);
- mFadeIn = fadeIn;
- }
-
- @Override
- protected void applyTransformation(float interpolatedTime, Transformation t) {
- float x = interpolatedTime;
- if (!mFadeIn) {
- x = 1.0f - x; // reverse the interpolation for fade out
- }
- t.setAlpha(x);
- }
-}
\ No newline at end of file
diff --git a/services/java/com/android/server/wm/InputMonitor.java b/services/java/com/android/server/wm/InputMonitor.java
index a3e8be0..9dc92d3 100644
--- a/services/java/com/android/server/wm/InputMonitor.java
+++ b/services/java/com/android/server/wm/InputMonitor.java
@@ -205,7 +205,7 @@
inputWindow.ownerPid = child.mSession.mPid;
inputWindow.ownerUid = child.mSession.mUid;
- final Rect frame = child.mScaledFrame;
+ final Rect frame = child.mFrame;
inputWindow.frameLeft = frame.left;
inputWindow.frameTop = frame.top;
inputWindow.frameRight = frame.right;
diff --git a/services/java/com/android/server/wm/ScreenRotationAnimation.java b/services/java/com/android/server/wm/ScreenRotationAnimation.java
index fbf1ec3..bb01633 100644
--- a/services/java/com/android/server/wm/ScreenRotationAnimation.java
+++ b/services/java/com/android/server/wm/ScreenRotationAnimation.java
@@ -19,7 +19,6 @@
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
-import android.graphics.Color;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.PixelFormat;
@@ -41,46 +40,10 @@
static final int FREEZE_LAYER = WindowManagerService.TYPE_LAYER_MULTIPLIER * 200;
- class BlackSurface {
- final int left;
- final int top;
- final Surface surface;
-
- BlackSurface(SurfaceSession session, int layer, int l, int t, int w, int h)
- throws Surface.OutOfResourcesException {
- left = l;
- top = t;
- surface = new Surface(session, 0, "BlackSurface",
- -1, w, h, PixelFormat.OPAQUE, Surface.FX_SURFACE_DIM);
- surface.setAlpha(1.0f);
- surface.setLayer(FREEZE_LAYER);
- }
-
- void setMatrix(Matrix matrix) {
- mTmpMatrix.setTranslate(left, top);
- mTmpMatrix.postConcat(matrix);
- mTmpMatrix.getValues(mTmpFloats);
- surface.setPosition((int)mTmpFloats[Matrix.MTRANS_X],
- (int)mTmpFloats[Matrix.MTRANS_Y]);
- surface.setMatrix(
- mTmpFloats[Matrix.MSCALE_X], mTmpFloats[Matrix.MSKEW_Y],
- mTmpFloats[Matrix.MSKEW_X], mTmpFloats[Matrix.MSCALE_Y]);
- if (false) {
- Slog.i(TAG, "Black Surface @ (" + left + "," + top + "): ("
- + mTmpFloats[Matrix.MTRANS_X] + ","
- + mTmpFloats[Matrix.MTRANS_Y] + ") matrix=["
- + mTmpFloats[Matrix.MSCALE_X] + ","
- + mTmpFloats[Matrix.MSCALE_Y] + "]["
- + mTmpFloats[Matrix.MSKEW_X] + ","
- + mTmpFloats[Matrix.MSKEW_Y] + "]");
- }
- }
- }
-
final Context mContext;
final Display mDisplay;
Surface mSurface;
- BlackSurface[] mBlackSurfaces;
+ BlackFrame mBlackFrame;
int mWidth, mHeight;
int mSnapshotRotation;
@@ -302,14 +265,12 @@
">>> OPEN TRANSACTION ScreenRotationAnimation.dismiss");
Surface.openTransaction();
- mBlackSurfaces = new BlackSurface[4];
try {
final int w = mDisplayMetrics.widthPixels;
final int h = mDisplayMetrics.heightPixels;
- mBlackSurfaces[0] = new BlackSurface(session, FREEZE_LAYER, -w, -h, w, h*2);
- mBlackSurfaces[1] = new BlackSurface(session, FREEZE_LAYER, 0, -h, w*2, h);
- mBlackSurfaces[2] = new BlackSurface(session, FREEZE_LAYER, w, 0, w, h*2);
- mBlackSurfaces[3] = new BlackSurface(session, FREEZE_LAYER, -w, h, w*2, h);
+ Rect outer = new Rect(-w, -h, w*2, h*2);
+ Rect inner = new Rect(0, 0, w, h);
+ mBlackFrame = new BlackFrame(session, outer, inner, FREEZE_LAYER);
} catch (Surface.OutOfResourcesException e) {
Slog.w(TAG, "Unable to allocate black surface", e);
} finally {
@@ -326,13 +287,8 @@
mSurface.destroy();
mSurface = null;
}
- if (mBlackSurfaces != null) {
- for (int i=0; i<mBlackSurfaces.length; i++) {
- if (mBlackSurfaces[i] != null) {
- mBlackSurfaces[i].surface.destroy();
- }
- }
- mBlackSurfaces = null;
+ if (mBlackFrame != null) {
+ mBlackFrame.kill();
}
if (mExitAnimation != null) {
mExitAnimation.cancel();
@@ -383,20 +339,12 @@
mEnterAnimation.cancel();
mEnterAnimation = null;
mEnterTransformation.clear();
- if (mBlackSurfaces != null) {
- for (int i=0; i<mBlackSurfaces.length; i++) {
- if (mBlackSurfaces[i] != null) {
- mBlackSurfaces[i].surface.hide();
- }
- }
+ if (mBlackFrame != null) {
+ mBlackFrame.hide();
}
} else {
- if (mBlackSurfaces != null) {
- for (int i=0; i<mBlackSurfaces.length; i++) {
- if (mBlackSurfaces[i] != null) {
- mBlackSurfaces[i].setMatrix(mEnterTransformation.getMatrix());
- }
- }
+ if (mBlackFrame != null) {
+ mBlackFrame.setMatrix(mEnterTransformation.getMatrix());
}
}
}
diff --git a/services/java/com/android/server/wm/ViewServer.java b/services/java/com/android/server/wm/ViewServer.java
index 9fb35b96..70cb26a 100644
--- a/services/java/com/android/server/wm/ViewServer.java
+++ b/services/java/com/android/server/wm/ViewServer.java
@@ -73,19 +73,6 @@
private ExecutorService mThreadPool;
/**
- * Creates a new ViewServer associated with the specified window manager.
- * The server uses the default port {@link #VIEW_SERVER_DEFAULT_PORT}. The server
- * is not started by default.
- *
- * @param windowManager The window manager used to communicate with the views.
- *
- * @see #start()
- */
- ViewServer(WindowManagerService windowManager) {
- this(windowManager, VIEW_SERVER_DEFAULT_PORT);
- }
-
- /**
* Creates a new ViewServer associated with the specified window manager on the
* specified local port. The server is not started by default.
*
@@ -177,7 +164,7 @@
// Any uncaught exception will crash the system process
try {
Socket client = mServer.accept();
- if(mThreadPool != null) {
+ if (mThreadPool != null) {
mThreadPool.submit(new ViewServerWorker(client));
} else {
try {
@@ -220,6 +207,7 @@
private Socket mClient;
private boolean mNeedWindowListUpdate;
private boolean mNeedFocusedWindowUpdate;
+
public ViewServerWorker(Socket client) {
mClient = client;
mNeedWindowListUpdate = false;
@@ -255,7 +243,7 @@
result = mWindowManager.viewServerListWindows(mClient);
} else if (COMMAND_WINDOW_MANAGER_GET_FOCUS.equalsIgnoreCase(command)) {
result = mWindowManager.viewServerGetFocusedWindow(mClient);
- } else if(COMMAND_WINDOW_MANAGER_AUTOLIST.equalsIgnoreCase(command)) {
+ } else if (COMMAND_WINDOW_MANAGER_AUTOLIST.equalsIgnoreCase(command)) {
result = windowManagerAutolistLoop();
} else {
result = mWindowManager.viewServerWindowCommand(mClient,
@@ -263,7 +251,7 @@
}
if (!result) {
- Slog.w(LOG_TAG, "An error occured with the command: " + command);
+ Slog.w(LOG_TAG, "An error occurred with the command: " + command);
}
} catch(IOException e) {
Slog.w(LOG_TAG, "Connection error: ", e);
@@ -321,11 +309,11 @@
needFocusedWindowUpdate = true;
}
}
- if(needWindowListUpdate) {
+ if (needWindowListUpdate) {
out.write("LIST UPDATE\n");
out.flush();
}
- if(needFocusedWindowUpdate) {
+ if (needFocusedWindowUpdate) {
out.write("FOCUS UPDATE\n");
out.flush();
}
@@ -337,6 +325,7 @@
try {
out.close();
} catch (IOException e) {
+ // Ignore
}
}
mWindowManager.removeWindowChangeListener(this);
diff --git a/services/java/com/android/server/wm/WindowManagerService.java b/services/java/com/android/server/wm/WindowManagerService.java
index 12a5000..9890bec 100644
--- a/services/java/com/android/server/wm/WindowManagerService.java
+++ b/services/java/com/android/server/wm/WindowManagerService.java
@@ -190,6 +190,16 @@
*/
static final int LAYER_OFFSET_BLUR = 2;
+ /**
+ * Layer at which to put the rotation freeze snapshot.
+ */
+ static final int FREEZE_LAYER = (TYPE_LAYER_MULTIPLIER * 200) + 1;
+
+ /**
+ * Layer at which to put the mask for emulated screen sizes.
+ */
+ static final int MASK_LAYER = TYPE_LAYER_MULTIPLIER * 200;
+
/** The maximum length we will accept for a loaded animation duration:
* this is 10 seconds.
*/
@@ -383,6 +393,8 @@
StrictModeFlash mStrictModeFlash;
ScreenRotationAnimation mScreenRotationAnimation;
+ BlackFrame mBlackFrame;
+
int mTransactionSequence = 0;
final float[] mTmpFloats = new float[9];
@@ -392,6 +404,8 @@
boolean mSystemBooted = false;
int mInitialDisplayWidth = 0;
int mInitialDisplayHeight = 0;
+ int mBaseDisplayWidth = 0;
+ int mBaseDisplayHeight = 0;
int mCurDisplayWidth = 0;
int mCurDisplayHeight = 0;
int mRotation = 0;
@@ -589,9 +603,6 @@
// The frame use to limit the size of the app running in compatibility mode.
Rect mCompatibleScreenFrame = new Rect();
float mCompatibleScreenScale;
- // The surface used to fill the outer rim of the app running in compatibility mode.
- Surface mBackgroundFillerSurface = null;
- WindowState mBackgroundFillerTarget = null;
public static WindowManagerService main(Context context,
PowerManagerService pm, boolean haveInputMethods) {
@@ -1760,7 +1771,7 @@
boolean rawChanged = false;
float wpx = mLastWallpaperX >= 0 ? mLastWallpaperX : 0.5f;
float wpxs = mLastWallpaperXStep >= 0 ? mLastWallpaperXStep : -1.0f;
- int availw = wallpaperWin.mScaledFrame.right-wallpaperWin.mScaledFrame.left-dw;
+ int availw = wallpaperWin.mFrame.right-wallpaperWin.mFrame.left-dw;
int offset = availw > 0 ? -(int)(availw*wpx+.5f) : 0;
changed = wallpaperWin.mXOffset != offset;
if (changed) {
@@ -2355,6 +2366,11 @@
w.mGivenVisibleInsets.set(visibleInsets);
w.mGivenTouchableRegion.set(touchableRegion);
w.mTouchableInsets = touchableInsets;
+ if (w.mGlobalScale != 1) {
+ w.mGivenContentInsets.scale(w.mGlobalScale);
+ w.mGivenVisibleInsets.scale(w.mGlobalScale);
+ w.mGivenTouchableRegion.scale(w.mGlobalScale);
+ }
mLayoutNeeded = true;
performLayoutAndPlaceSurfacesLocked();
}
@@ -2690,7 +2706,7 @@
if (win.mAppToken != null) {
win.mAppToken.updateReportedVisibilityLocked();
}
- outFrame.set(win.mFrame);
+ outFrame.set(win.mCompatFrame);
outContentInsets.set(win.mContentInsets);
outVisibleInsets.set(win.mVisibleInsets);
if (localLOGV) Slog.v(
@@ -2889,18 +2905,14 @@
}
private boolean applyAnimationLocked(AppWindowToken wtoken,
- WindowManager.LayoutParams lp, int transit, boolean enter, boolean bgFiller) {
+ WindowManager.LayoutParams lp, int transit, boolean enter) {
// Only apply an animation if the display isn't frozen. If it is
// frozen, there is no reason to animate and it can cause strange
// artifacts when we unfreeze the display if some different animation
// is running.
if (!mDisplayFrozen && mPolicy.isScreenOn()) {
Animation a;
- if (bgFiller) {
- a = new FadeInOutAnimation(enter);
- if (DEBUG_ANIM) Slog.v(TAG,
- "applying FadeInOutAnimation for a window in compatibility mode");
- } else if (mNextAppTransitionPackage != null) {
+ if (mNextAppTransitionPackage != null) {
a = loadAnimation(mNextAppTransitionPackage, enter ?
mNextAppTransitionEnter : mNextAppTransitionExit);
} else {
@@ -3264,36 +3276,46 @@
long ident = Binder.clearCallingIdentity();
synchronized(mWindowMap) {
- if (updateOrientationFromAppTokensLocked(false)) {
- if (freezeThisOneIfNeeded != null) {
- AppWindowToken wtoken = findAppWindowToken(
- freezeThisOneIfNeeded);
- if (wtoken != null) {
- startAppFreezingScreenLocked(wtoken,
- ActivityInfo.CONFIG_ORIENTATION);
- }
+ config = updateOrientationFromAppTokensLocked(currentConfig,
+ freezeThisOneIfNeeded);
+ }
+
+ Binder.restoreCallingIdentity(ident);
+ return config;
+ }
+
+ private Configuration updateOrientationFromAppTokensLocked(
+ Configuration currentConfig, IBinder freezeThisOneIfNeeded) {
+ Configuration config = null;
+
+ if (updateOrientationFromAppTokensLocked(false)) {
+ if (freezeThisOneIfNeeded != null) {
+ AppWindowToken wtoken = findAppWindowToken(
+ freezeThisOneIfNeeded);
+ if (wtoken != null) {
+ startAppFreezingScreenLocked(wtoken,
+ ActivityInfo.CONFIG_ORIENTATION);
}
- config = computeNewConfigurationLocked();
-
- } else if (currentConfig != null) {
- // No obvious action we need to take, but if our current
- // state mismatches the activity manager's, update it,
- // disregarding font scale, which should remain set to
- // the value of the previous configuration.
- mTempConfiguration.setToDefaults();
- mTempConfiguration.fontScale = currentConfig.fontScale;
- if (computeNewConfigurationLocked(mTempConfiguration)) {
- if (currentConfig.diff(mTempConfiguration) != 0) {
- mWaitingForConfig = true;
- mLayoutNeeded = true;
- startFreezingDisplayLocked(false);
- config = new Configuration(mTempConfiguration);
- }
+ }
+ config = computeNewConfigurationLocked();
+
+ } else if (currentConfig != null) {
+ // No obvious action we need to take, but if our current
+ // state mismatches the activity manager's, update it,
+ // disregarding font scale, which should remain set to
+ // the value of the previous configuration.
+ mTempConfiguration.setToDefaults();
+ mTempConfiguration.fontScale = currentConfig.fontScale;
+ if (computeNewConfigurationLocked(mTempConfiguration)) {
+ if (currentConfig.diff(mTempConfiguration) != 0) {
+ mWaitingForConfig = true;
+ mLayoutNeeded = true;
+ startFreezingDisplayLocked(false);
+ config = new Configuration(mTempConfiguration);
}
}
}
- Binder.restoreCallingIdentity(ident);
return config;
}
@@ -3682,7 +3704,7 @@
}
boolean setTokenVisibilityLocked(AppWindowToken wtoken, WindowManager.LayoutParams lp,
- boolean visible, int transit, boolean performLayout, boolean bgFiller) {
+ boolean visible, int transit, boolean performLayout) {
boolean delayed = false;
if (wtoken.clientHidden == visible) {
@@ -3704,7 +3726,7 @@
if (wtoken.animation == sDummyAnimation) {
wtoken.animation = null;
}
- applyAnimationLocked(wtoken, lp, transit, visible, bgFiller);
+ applyAnimationLocked(wtoken, lp, transit, visible);
changed = true;
if (wtoken.animation != null) {
delayed = runningAppAnimation = true;
@@ -3858,7 +3880,7 @@
final long origId = Binder.clearCallingIdentity();
setTokenVisibilityLocked(wtoken, null, visible, WindowManagerPolicy.TRANSIT_UNSET,
- true, false);
+ true);
wtoken.updateReportedVisibilityLocked();
Binder.restoreCallingIdentity(origId);
}
@@ -3985,7 +4007,7 @@
if (basewtoken != null && (wtoken=basewtoken.appWindowToken) != null) {
if (DEBUG_APP_TRANSITIONS) Slog.v(TAG, "Removing app token: " + wtoken);
delayed = setTokenVisibilityLocked(wtoken, null, false,
- WindowManagerPolicy.TRANSIT_UNSET, true, false);
+ WindowManagerPolicy.TRANSIT_UNSET, true);
wtoken.inPendingTransaction = false;
mOpeningApps.remove(wtoken);
wtoken.waitingToShow = false;
@@ -4810,7 +4832,7 @@
// Don't include wallpaper in bounds calculation
if (!ws.mIsWallpaper) {
- final Rect wf = ws.mScaledFrame;
+ final Rect wf = ws.mFrame;
final Rect cr = ws.mContentInsets;
int left = wf.left + cr.left;
int top = wf.top + cr.top;
@@ -5046,6 +5068,7 @@
} else {
Surface.setOrientation(0, rotation, animFlags);
}
+ rebuildBlackFrame(inTransaction);
}
for (int i=mWindows.size()-1; i>=0; i--) {
@@ -5488,8 +5511,8 @@
// Use the effective "visual" dimensions based on current rotation
final boolean rotated = (mRotation == Surface.ROTATION_90
|| mRotation == Surface.ROTATION_270);
- final int realdw = rotated ? mInitialDisplayHeight : mInitialDisplayWidth;
- final int realdh = rotated ? mInitialDisplayWidth : mInitialDisplayHeight;
+ final int realdw = rotated ? mBaseDisplayHeight : mBaseDisplayWidth;
+ final int realdh = rotated ? mBaseDisplayWidth : mBaseDisplayHeight;
if (mAltOrientation) {
mCurDisplayWidth = realdw;
@@ -5528,8 +5551,8 @@
// Override display width and height with what we are computing,
// to be sure they remain consistent.
- dm.widthPixels = mPolicy.getNonDecorDisplayWidth(dw);
- dm.heightPixels = mPolicy.getNonDecorDisplayHeight(dh);
+ dm.widthPixels = dm.realWidthPixels = mPolicy.getNonDecorDisplayWidth(dw);
+ dm.heightPixels = dm.realHeightPixels = mPolicy.getNonDecorDisplayHeight(dh);
mCompatibleScreenScale = CompatibilityInfo.updateCompatibleScreenFrame(
dm, mCompatibleScreenFrame, null);
@@ -5926,8 +5949,18 @@
}
WindowManager wm = (WindowManager)mContext.getSystemService(Context.WINDOW_SERVICE);
mDisplay = wm.getDefaultDisplay();
- mInitialDisplayWidth = mCurDisplayWidth = mDisplay.getRealWidth();
- mInitialDisplayHeight = mCurDisplayHeight = mDisplay.getRealHeight();
+ mInitialDisplayWidth = mDisplay.getRealWidth();
+ mInitialDisplayHeight = mDisplay.getRealHeight();
+ int rot = mDisplay.getRotation();
+ if (rot == Surface.ROTATION_90 || rot == Surface.ROTATION_270) {
+ // If the screen is currently rotated, we need to swap the
+ // initial width and height to get the true natural values.
+ int tmp = mInitialDisplayWidth;
+ mInitialDisplayWidth = mInitialDisplayHeight;
+ mInitialDisplayHeight = tmp;
+ }
+ mBaseDisplayWidth = mCurDisplayWidth = mInitialDisplayWidth;
+ mBaseDisplayHeight = mCurDisplayHeight = mInitialDisplayHeight;
mInputManager.setDisplaySize(0, mDisplay.getRawWidth(), mDisplay.getRawHeight());
mPolicy.setInitialDisplaySize(mInitialDisplayWidth, mInitialDisplayHeight);
}
@@ -6433,8 +6466,102 @@
public int getMaximumSizeDimension() {
synchronized(mWindowMap) {
// Do this based on the raw screen size, until we are smarter.
- return mInitialDisplayWidth > mInitialDisplayHeight
- ? mInitialDisplayWidth : mInitialDisplayHeight;
+ return mBaseDisplayWidth > mBaseDisplayHeight
+ ? mBaseDisplayWidth : mBaseDisplayHeight;
+ }
+ }
+
+ public void setForcedDisplaySize(int longDimen, int shortDimen) {
+ synchronized(mWindowMap) {
+ int width, height;
+ if (mInitialDisplayWidth < mInitialDisplayHeight) {
+ width = shortDimen < mInitialDisplayWidth
+ ? shortDimen : mInitialDisplayWidth;
+ height = longDimen < mInitialDisplayHeight
+ ? longDimen : mInitialDisplayHeight;
+ } else {
+ width = longDimen < mInitialDisplayWidth
+ ? longDimen : mInitialDisplayWidth;
+ height = shortDimen < mInitialDisplayHeight
+ ? shortDimen : mInitialDisplayHeight;
+ }
+ setForcedDisplaySizeLocked(width, height);
+ }
+ }
+
+ private void rebuildBlackFrame(boolean inTransaction) {
+ if (!inTransaction) {
+ if (SHOW_TRANSACTIONS) Slog.i(TAG,
+ ">>> OPEN TRANSACTION rebuildBlackFrame");
+ Surface.openTransaction();
+ }
+ try {
+ if (mBlackFrame != null) {
+ mBlackFrame.kill();
+ mBlackFrame = null;
+ }
+ if (mBaseDisplayWidth < mInitialDisplayWidth
+ || mBaseDisplayHeight < mInitialDisplayHeight) {
+ int initW, initH, baseW, baseH;
+ final boolean rotated = (mRotation == Surface.ROTATION_90
+ || mRotation == Surface.ROTATION_270);
+ if (rotated) {
+ initW = mInitialDisplayHeight;
+ initH = mInitialDisplayWidth;
+ baseW = mBaseDisplayHeight;
+ baseH = mBaseDisplayWidth;
+ } else {
+ initW = mInitialDisplayWidth;
+ initH = mInitialDisplayHeight;
+ baseW = mBaseDisplayWidth;
+ baseH = mBaseDisplayHeight;
+ }
+ Rect outer = new Rect(0, 0, initW, initH);
+ Rect inner = new Rect(0, 0, baseW, baseH);
+ try {
+ mBlackFrame = new BlackFrame(mFxSession, outer, inner, MASK_LAYER);
+ } catch (Surface.OutOfResourcesException e) {
+ }
+ }
+ } finally {
+ if (!inTransaction) {
+ Surface.closeTransaction();
+ if (SHOW_TRANSACTIONS) Slog.i(TAG,
+ "<<< CLOSE TRANSACTION rebuildBlackFrame");
+ }
+ }
+ }
+
+ private void setForcedDisplaySizeLocked(int width, int height) {
+ mBaseDisplayWidth = width;
+ mBaseDisplayHeight = height;
+ mPolicy.setInitialDisplaySize(mBaseDisplayWidth, mBaseDisplayHeight);
+
+ mLayoutNeeded = true;
+
+ boolean configChanged = updateOrientationFromAppTokensLocked(false);
+ mTempConfiguration.setToDefaults();
+ mTempConfiguration.fontScale = mCurConfiguration.fontScale;
+ if (computeNewConfigurationLocked(mTempConfiguration)) {
+ if (mCurConfiguration.diff(mTempConfiguration) != 0) {
+ configChanged = true;
+ }
+ }
+
+ if (configChanged) {
+ mWaitingForConfig = true;
+ startFreezingDisplayLocked(false);
+ mH.sendEmptyMessage(H.SEND_NEW_CONFIGURATION);
+ }
+
+ rebuildBlackFrame(false);
+
+ performLayoutAndPlaceSurfacesLocked();
+ }
+
+ public void clearForcedDisplaySize() {
+ synchronized(mWindowMap) {
+ setForcedDisplaySizeLocked(mInitialDisplayWidth, mInitialDisplayHeight);
}
}
@@ -6740,7 +6867,6 @@
}
win.prelayout();
mPolicy.layoutWindowLw(win, win.mAttrs, null);
- win.evalNeedsBackgroundFiller(innerDw, innerDh);
win.mLayoutSeq = seq;
if (DEBUG_LAYOUT) Slog.v(TAG, "-> mFrame="
+ win.mFrame + " mContainingFrame="
@@ -6777,7 +6903,6 @@
}
win.prelayout();
mPolicy.layoutWindowLw(win, win.mAttrs, win.mAttachedWindow);
- win.evalNeedsBackgroundFiller(innerDw, innerDh);
win.mLayoutSeq = seq;
if (DEBUG_LAYOUT) Slog.v(TAG, "-> mFrame="
+ win.mFrame + " mContainingFrame="
@@ -7229,7 +7354,6 @@
LayoutParams animLp = null;
int bestAnimLayer = -1;
boolean fullscreenAnim = false;
- boolean needBgFiller = false;
if (DEBUG_APP_TRANSITIONS) Slog.v(TAG,
"New wallpaper target=" + mWallpaperTarget
@@ -7267,16 +7391,8 @@
if (wtoken.appFullscreen) {
WindowState ws = wtoken.findMainWindow();
if (ws != null) {
- // If this is a compatibility mode
- // window, we will always use its anim.
- if (ws.mNeedsBackgroundFiller) {
- animLp = ws.mAttrs;
- bestAnimLayer = Integer.MAX_VALUE;
- needBgFiller = true;
- } else if (!fullscreenAnim || ws.mLayer > bestAnimLayer) {
- animLp = ws.mAttrs;
- bestAnimLayer = ws.mLayer;
- }
+ animLp = ws.mAttrs;
+ bestAnimLayer = ws.mLayer;
fullscreenAnim = true;
}
} else if (!fullscreenAnim) {
@@ -7338,7 +7454,7 @@
wtoken.inPendingTransaction = false;
wtoken.animation = null;
setTokenVisibilityLocked(wtoken, animLp, true,
- transit, false, needBgFiller);
+ transit, false);
wtoken.updateReportedVisibilityLocked();
wtoken.waitingToShow = false;
wtoken.showAllWindowsLocked();
@@ -7351,7 +7467,7 @@
wtoken.inPendingTransaction = false;
wtoken.animation = null;
setTokenVisibilityLocked(wtoken, animLp, false,
- transit, false, needBgFiller);
+ transit, false);
wtoken.updateReportedVisibilityLocked();
wtoken.waitingToHide = false;
// Force the allDrawn flag, because we want to start
@@ -7518,8 +7634,6 @@
boolean dimming = false;
boolean covered = false;
boolean syswin = false;
- boolean backgroundFillerWasShown = mBackgroundFillerTarget != null;
- mBackgroundFillerTarget = null;
final int N = mWindows.size();
@@ -7548,8 +7662,7 @@
w.computeShownFrameLocked();
if (localLOGV) Slog.v(
TAG, "Placing surface #" + i + " " + w.mSurface
- + ": new=" + w.mShownFrame + ", old="
- + w.mLastShownFrame);
+ + ": new=" + w.mShownFrame);
int width, height;
if ((w.mAttrs.flags & w.mAttrs.FLAG_SCALED) != 0) {
@@ -7557,13 +7670,9 @@
// the requested size.
width = w.mRequestedWidth;
height = w.mRequestedHeight;
- w.mLastRequestedWidth = width;
- w.mLastRequestedHeight = height;
- w.mLastShownFrame.set(w.mShownFrame);
} else {
- width = w.mShownFrame.width();
- height = w.mShownFrame.height();
- w.mLastShownFrame.set(w.mShownFrame);
+ width = w.mCompatFrame.width();
+ height = w.mCompatFrame.height();
}
if (w.mSurface != null) {
@@ -7630,8 +7739,8 @@
}
if (localLOGV) Slog.v(TAG, "Resizing " + w
+ ": configChanged=" + configChanged
- + " last=" + w.mLastFrame + " frame=" + w.mFrame);
- boolean frameChanged = !w.mLastFrame.equals(w.mFrame);
+ + " last=" + w.mLastCompatFrame + " frame=" + w.mCompatFrame);
+ boolean frameChanged = !w.mLastCompatFrame.equals(w.mCompatFrame);
if (frameChanged
|| w.mContentInsetsChanged
|| w.mVisibleInsetsChanged
@@ -7647,6 +7756,7 @@
}
w.mLastFrame.set(w.mFrame);
+ w.mLastCompatFrame.set(w.mCompatFrame);
w.mLastContentInsets.set(w.mContentInsets);
w.mLastVisibleInsets.set(w.mVisibleInsets);
// If the screen is currently frozen, then keep
@@ -7682,7 +7792,7 @@
}
}
if (DEBUG_RESIZE || DEBUG_ORIENTATION) Slog.v(TAG,
- "Resizing window " + w + " to " + w.mFrame);
+ "Resizing window " + w + " to " + w.mCompatFrame);
mResizingWindows.add(w);
} else if (w.mOrientationChanging) {
if (!w.mDrawPending && !w.mCommitDrawPending) {
@@ -7821,16 +7931,6 @@
final boolean obscuredChanged = w.mObscured != obscured;
- if (mBackgroundFillerTarget != null) {
- if (w.isAnimating()) {
- // Background filler is below all other windows that
- // are animating.
- mBackgroundFillerTarget = w;
- } else if (w.mIsWallpaper) {
- mBackgroundFillerTarget = w;
- }
- }
-
// Update effect.
if (!(w.mObscured=obscured)) {
if (w.mSurface != null) {
@@ -7859,12 +7959,6 @@
// so we want to leave all of them as unblurred (for
// performance reasons).
obscured = true;
- } else if (w.mNeedsBackgroundFiller && w.mHasDrawn
- && w.mViewVisibility == View.VISIBLE
- && (canBeSeen || w.isAnimating())) {
- // This window is in compatibility mode, and needs background filler.
- obscured = true;
- mBackgroundFillerTarget = w;
} else if (canBeSeen && !obscured &&
(attrFlags&FLAG_BLUR_BEHIND|FLAG_DIM_BEHIND) != 0) {
if (localLOGV) Slog.v(TAG, "Win " + w
@@ -7931,47 +8025,6 @@
}
}
- if (mBackgroundFillerTarget != null) {
- if (mBackgroundFillerSurface == null) {
- try {
- mBackgroundFillerSurface = new Surface(mFxSession, 0,
- "BackGroundFiller",
- 0, dw, dh,
- PixelFormat.OPAQUE,
- Surface.FX_SURFACE_NORMAL);
- } catch (Exception e) {
- Slog.e(TAG, "Exception creating filler surface", e);
- }
- if (SHOW_TRANSACTIONS) Slog.i(TAG, " BG FILLER "
- + mBackgroundFillerSurface + ": CREATE");
- }
- try {
- if (SHOW_TRANSACTIONS) Slog.i(TAG, " BG FILLER "
- + mBackgroundFillerSurface + " SHOW: pos=(0,0) ("
- + dw + "x" + dh + ") layer="
- + (mBackgroundFillerTarget.mLayer - 1));
- mBackgroundFillerSurface.setPosition(0, 0);
- mBackgroundFillerSurface.setSize(dw, dh);
- // Using the same layer as Dim because they will never be shown at the
- // same time. NOTE: we do NOT use mAnimLayer, because we don't
- // want this surface dragged up in front of stuff that is animating.
- mBackgroundFillerSurface.setLayer(mBackgroundFillerTarget.mLayer
- - LAYER_OFFSET_DIM);
- mBackgroundFillerSurface.show();
- } catch (RuntimeException e) {
- Slog.e(TAG, "Exception showing filler surface");
- }
- } else if (backgroundFillerWasShown) {
- mBackgroundFillerTarget = null;
- if (SHOW_TRANSACTIONS) Slog.i(TAG, " BG FILLER "
- + mBackgroundFillerSurface + " HIDE");
- try {
- mBackgroundFillerSurface.hide();
- } catch (RuntimeException e) {
- Slog.e(TAG, "Exception hiding filler surface", e);
- }
- }
-
if (mDimAnimator != null && mDimAnimator.mDimShown) {
animating |= mDimAnimator.updateSurface(dimming, currentTime,
mDisplayFrozen || !mPolicy.isScreenOn());
@@ -7987,6 +8040,15 @@
}
mBlurShown = false;
}
+
+ if (mBlackFrame != null) {
+ if (mScreenRotationAnimation != null) {
+ mBlackFrame.setMatrix(
+ mScreenRotationAnimation.getEnterTransformation().getMatrix());
+ } else {
+ mBlackFrame.clearMatrix();
+ }
+ }
} catch (RuntimeException e) {
Slog.e(TAG, "Unhandled exception in Window Manager", e);
}
@@ -8017,7 +8079,7 @@
WindowState win = mResizingWindows.get(i);
try {
if (DEBUG_RESIZE || DEBUG_ORIENTATION) Slog.v(TAG,
- "Reporting new frame to " + win + ": " + win.mFrame);
+ "Reporting new frame to " + win + ": " + win.mCompatFrame);
int diff = 0;
boolean configChanged =
win.mConfiguration != mCurConfiguration
@@ -8026,13 +8088,13 @@
if ((DEBUG_RESIZE || DEBUG_ORIENTATION || DEBUG_CONFIGURATION)
&& configChanged) {
Slog.i(TAG, "Sending new config to window " + win + ": "
- + win.mFrame.width() + "x" + win.mFrame.height()
+ + win.mCompatFrame.width() + "x" + win.mCompatFrame.height()
+ " / " + mCurConfiguration + " / 0x"
+ Integer.toHexString(diff));
}
win.mConfiguration = mCurConfiguration;
- win.mClient.resized(win.mFrame.width(),
- win.mFrame.height(), win.mLastContentInsets,
+ win.mClient.resized(win.mCompatFrame.width(),
+ win.mCompatFrame.height(), win.mLastContentInsets,
win.mLastVisibleInsets, win.mDrawPending,
configChanged ? win.mConfiguration : null);
win.mContentInsetsChanged = false;
@@ -8840,7 +8902,9 @@
}
if (mDisplay != null) {
pw.print(" Display: init="); pw.print(mInitialDisplayWidth); pw.print("x");
- pw.print(mInitialDisplayHeight); pw.print(" cur=");
+ pw.print(mInitialDisplayHeight); pw.print(" base=");
+ pw.print(mBaseDisplayWidth); pw.print("x"); pw.print(mBaseDisplayHeight);
+ pw.print(" cur=");
pw.print(mCurDisplayWidth); pw.print("x"); pw.print(mCurDisplayHeight);
pw.print(" real="); pw.print(mDisplay.getRealWidth());
pw.print("x"); pw.print(mDisplay.getRealHeight());
diff --git a/services/java/com/android/server/wm/WindowState.java b/services/java/com/android/server/wm/WindowState.java
index 2014e9d..144341b 100644
--- a/services/java/com/android/server/wm/WindowState.java
+++ b/services/java/com/android/server/wm/WindowState.java
@@ -18,7 +18,6 @@
import static android.view.WindowManager.LayoutParams.FIRST_SUB_WINDOW;
import static android.view.WindowManager.LayoutParams.FLAG_COMPATIBLE_WINDOW;
-import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS;
import static android.view.WindowManager.LayoutParams.LAST_SUB_WINDOW;
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING;
import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD;
@@ -83,23 +82,30 @@
boolean mAttachedHidden; // is our parent window hidden?
boolean mLastHidden; // was this window last hidden?
boolean mWallpaperVisible; // for wallpaper, what was last vis report?
+
+ /**
+ * The window size that was requested by the application. These are in
+ * the application's coordinate space (without compatibility scale applied).
+ */
int mRequestedWidth;
int mRequestedHeight;
- int mLastRequestedWidth;
- int mLastRequestedHeight;
+
int mLayer;
int mAnimLayer;
int mLastLayer;
boolean mHaveFrame;
boolean mObscured;
- boolean mNeedsBackgroundFiller;
boolean mTurnOnScreen;
int mLayoutSeq = -1;
Configuration mConfiguration = null;
- // Actual frame shown on-screen (may be modified by animation)
+ /**
+ * Actual frame shown on-screen (may be modified by animation). These
+ * are in the screen's coordinate space (WITH the compatibility scale
+ * applied).
+ */
final Rect mShownFrame = new Rect();
final Rect mLastShownFrame = new Rect();
@@ -110,14 +116,16 @@
boolean mSurfaceResized;
/**
- * Insets that determine the actually visible area
+ * Insets that determine the actually visible area. These are in the application's
+ * coordinate space (without compatibility scale applied).
*/
final Rect mVisibleInsets = new Rect();
final Rect mLastVisibleInsets = new Rect();
boolean mVisibleInsetsChanged;
/**
- * Insets that are covered by system windows
+ * Insets that are covered by system windows. These are in the application's
+ * coordinate space (without compatibility scale applied).
*/
final Rect mContentInsets = new Rect();
final Rect mLastContentInsets = new Rect();
@@ -157,16 +165,20 @@
// Current transformation being applied.
boolean mHaveMatrix;
float mGlobalScale=1;
+ float mInvGlobalScale=1;
float mDsDx=1, mDtDx=0, mDsDy=0, mDtDy=1;
float mLastDsDx=1, mLastDtDx=0, mLastDsDy=0, mLastDtDy=1;
float mHScale=1, mVScale=1;
float mLastHScale=1, mLastVScale=1;
final Matrix mTmpMatrix = new Matrix();
- // "Real" frame that the application sees.
+ // "Real" frame that the application sees, in display coordinate space.
final Rect mFrame = new Rect();
final Rect mLastFrame = new Rect();
- final Rect mScaledFrame = new Rect();
+ // Frame that is scaled to the application's coordinate space when in
+ // screen size compatibility mode.
+ final Rect mCompatFrame = new Rect();
+ final Rect mLastCompatFrame = new Rect();
final Rect mContainingFrame = new Rect();
final Rect mDisplayFrame = new Rect();
@@ -346,8 +358,6 @@
mSurface = null;
mRequestedWidth = 0;
mRequestedHeight = 0;
- mLastRequestedWidth = 0;
- mLastRequestedHeight = 0;
mXOffset = 0;
mYOffset = 0;
mLayer = 0;
@@ -373,23 +383,40 @@
final Rect display = mDisplayFrame;
display.set(df);
- if (mEnforceSizeCompat) {
- container.intersect(mService.mCompatibleScreenFrame);
- if ((mAttrs.flags & FLAG_LAYOUT_NO_LIMITS) == 0) {
- display.intersect(mService.mCompatibleScreenFrame);
- }
- }
-
final int pw = container.right - container.left;
final int ph = container.bottom - container.top;
int w,h;
- if ((mAttrs.flags & mAttrs.FLAG_SCALED) != 0) {
- w = mAttrs.width < 0 ? pw : mAttrs.width;
- h = mAttrs.height< 0 ? ph : mAttrs.height;
+ if ((mAttrs.flags & WindowManager.LayoutParams.FLAG_SCALED) != 0) {
+ if (mAttrs.width < 0) {
+ w = pw;
+ } else if (mEnforceSizeCompat) {
+ w = (int)(mAttrs.width * mGlobalScale + .5f);
+ } else {
+ w = mAttrs.width;
+ }
+ if (mAttrs.height < 0) {
+ h = ph;
+ } else if (mEnforceSizeCompat) {
+ h = (int)(mAttrs.height * mGlobalScale + .5f);
+ } else {
+ h = mAttrs.height;
+ }
} else {
- w = mAttrs.width == mAttrs.MATCH_PARENT ? pw : mRequestedWidth;
- h = mAttrs.height== mAttrs.MATCH_PARENT ? ph : mRequestedHeight;
+ if (mAttrs.width == WindowManager.LayoutParams.MATCH_PARENT) {
+ w = pw;
+ } else if (mEnforceSizeCompat) {
+ w = (int)(mRequestedWidth * mGlobalScale + .5f);
+ } else {
+ w = mRequestedWidth;
+ }
+ if (mAttrs.height == WindowManager.LayoutParams.MATCH_PARENT) {
+ h = ph;
+ } else if (mEnforceSizeCompat) {
+ h = (int)(mRequestedHeight * mGlobalScale + .5f);
+ } else {
+ h = mRequestedHeight;
+ }
}
if (!mParentFrame.equals(pf)) {
@@ -412,37 +439,24 @@
//System.out.println("In: w=" + w + " h=" + h + " container=" +
// container + " x=" + mAttrs.x + " y=" + mAttrs.y);
+ float x, y;
+ if (mEnforceSizeCompat) {
+ x = mAttrs.x * mGlobalScale;
+ y = mAttrs.y * mGlobalScale;
+ } else {
+ x = mAttrs.x;
+ y = mAttrs.y;
+ }
+
Gravity.apply(mAttrs.gravity, w, h, container,
- (int) (mAttrs.x + mAttrs.horizontalMargin * pw),
- (int) (mAttrs.y + mAttrs.verticalMargin * ph), frame);
+ (int) (x + mAttrs.horizontalMargin * pw),
+ (int) (y + mAttrs.verticalMargin * ph), frame);
//System.out.println("Out: " + mFrame);
// Now make sure the window fits in the overall display.
Gravity.applyDisplay(mAttrs.gravity, df, frame);
- int adjRight=0, adjBottom=0;
-
- if (mEnforceSizeCompat) {
- // Adjust window offsets by the scaling factor.
- int xoff = (int)((frame.left-mService.mCompatibleScreenFrame.left)*mGlobalScale)
- - (frame.left-mService.mCompatibleScreenFrame.left);
- int yoff = (int)((frame.top-mService.mCompatibleScreenFrame.top)*mGlobalScale)
- - (frame.top-mService.mCompatibleScreenFrame.top);
- frame.offset(xoff, yoff);
-
- // We are temporarily going to apply the compatibility scale
- // to the window so that we can correctly associate it with the
- // content and visible frame.
- adjRight = frame.right - frame.left;
- adjRight = (int)((adjRight)*mGlobalScale + .5f) - adjRight;
- adjBottom = frame.bottom - frame.top;
- adjBottom = (int)((adjBottom)*mGlobalScale + .5f) - adjBottom;
- frame.right += adjRight;
- frame.bottom += adjBottom;
- }
- mScaledFrame.set(frame);
-
// Make sure the content and visible frames are inside of the
// final window frame.
if (content.left < frame.left) content.left = frame.left;
@@ -466,20 +480,17 @@
visibleInsets.right = frame.right-visible.right;
visibleInsets.bottom = frame.bottom-visible.bottom;
+ mCompatFrame.set(frame);
if (mEnforceSizeCompat) {
- // Scale the computed insets back to the window's compatibility
- // coordinate space, and put frame back to correct size.
- final float invScale = 1.0f/mGlobalScale;
- contentInsets.left = (int)(contentInsets.left*invScale);
- contentInsets.top = (int)(contentInsets.top*invScale);
- contentInsets.right = (int)(contentInsets.right*invScale);
- contentInsets.bottom = (int)(contentInsets.bottom*invScale);
- visibleInsets.left = (int)(visibleInsets.left*invScale);
- visibleInsets.top = (int)(visibleInsets.top*invScale);
- visibleInsets.right = (int)(visibleInsets.right*invScale);
- visibleInsets.bottom = (int)(visibleInsets.bottom*invScale);
- frame.right -= adjRight;
- frame.bottom -= adjBottom;
+ // If there is a size compatibility scale being applied to the
+ // window, we need to apply this to its insets so that they are
+ // reported to the app in its coordinate space.
+ contentInsets.scale(mInvGlobalScale);
+ visibleInsets.scale(mInvGlobalScale);
+
+ // Also the scaled frame that we report to the app needs to be
+ // adjusted to be in its coordinate space.
+ mCompatFrame.scale(mInvGlobalScale);
}
if (mIsWallpaper && (fw != frame.width() || fh != frame.height())) {
@@ -592,12 +603,12 @@
if (WindowManagerService.DEBUG_VISIBILITY) Slog.v(
WindowManagerService.TAG, "Creating surface in session "
+ mSession.mSurfaceSession + " window " + this
- + " w=" + mFrame.width()
- + " h=" + mFrame.height() + " format="
+ + " w=" + mCompatFrame.width()
+ + " h=" + mCompatFrame.height() + " format="
+ mAttrs.format + " flags=" + flags);
- int w = mFrame.width();
- int h = mFrame.height();
+ int w = mCompatFrame.width();
+ int h = mCompatFrame.height();
if ((mAttrs.flags & LayoutParams.FLAG_SCALED) != 0) {
// for a scaled surface, we always want the requested
// size.
@@ -650,8 +661,9 @@
+ ", animLayer=" + mAnimLayer);
if (WindowManagerService.SHOW_TRANSACTIONS) {
Slog.i(WindowManagerService.TAG, ">>> OPEN TRANSACTION createSurfaceLocked");
- WindowManagerService.logSurface(this, "CREATE pos=(" + mFrame.left + "," + mFrame.top + ") (" +
- mFrame.width() + "x" + mFrame.height() + "), layer=" +
+ WindowManagerService.logSurface(this, "CREATE pos=(" + mFrame.left
+ + "," + mFrame.top + ") (" +
+ mCompatFrame.width() + "x" + mCompatFrame.height() + "), layer=" +
mAnimLayer + " HIDE", null);
}
Surface.openTransaction();
@@ -862,10 +874,10 @@
if (!mLocalAnimating) {
if (WindowManagerService.DEBUG_ANIM) Slog.v(
WindowManagerService.TAG, "Starting animation in " + this +
- " @ " + currentTime + ": ww=" + mScaledFrame.width() +
- " wh=" + mScaledFrame.height() +
+ " @ " + currentTime + ": ww=" + mFrame.width() +
+ " wh=" + mFrame.height() +
" dw=" + dw + " dh=" + dh + " scale=" + mService.mWindowAnimationScale);
- mAnimation.initialize(mScaledFrame.width(), mScaledFrame.height(), dw, dh);
+ mAnimation.initialize(mFrame.width(), mFrame.height(), dw, dh);
mAnimation.setStartTime(currentTime);
mLocalAnimating = true;
mAnimating = true;
@@ -1035,8 +1047,9 @@
void prelayout() {
if (mEnforceSizeCompat) {
mGlobalScale = mService.mCompatibleScreenScale;
+ mInvGlobalScale = 1/mGlobalScale;
} else {
- mGlobalScale = 1;
+ mGlobalScale = mInvGlobalScale = 1;
}
}
@@ -1334,35 +1347,9 @@
&& mService.mPolicy.isScreenOn();
}
- void evalNeedsBackgroundFiller(int screenWidth, int screenHeight) {
- mNeedsBackgroundFiller =
- // only if the application is requesting compatible window
- mEnforceSizeCompat &&
- // only if it's visible
- mHasDrawn && mViewVisibility == View.VISIBLE &&
- // not needed if the compat window is actually full screen
- !isFullscreenIgnoringCompat(screenWidth, screenHeight) &&
- // and only if the application fills the compatible screen
- mFrame.left <= mService.mCompatibleScreenFrame.left &&
- mFrame.top <= mService.mCompatibleScreenFrame.top &&
- mFrame.right >= mService.mCompatibleScreenFrame.right &&
- mFrame.bottom >= mService.mCompatibleScreenFrame.bottom;
- }
-
boolean isFullscreen(int screenWidth, int screenHeight) {
- if (mEnforceSizeCompat) {
- return mFrame.left <= mService.mCompatibleScreenFrame.left &&
- mFrame.top <= mService.mCompatibleScreenFrame.top &&
- mFrame.right >= mService.mCompatibleScreenFrame.right &&
- mFrame.bottom >= mService.mCompatibleScreenFrame.bottom;
- } else {
- return isFullscreenIgnoringCompat(screenWidth, screenHeight);
- }
- }
-
- boolean isFullscreenIgnoringCompat(int screenWidth, int screenHeight) {
- return mScaledFrame.left <= 0 && mScaledFrame.top <= 0 &&
- mScaledFrame.right >= screenWidth && mScaledFrame.bottom >= screenHeight;
+ return mFrame.left <= 0 && mFrame.top <= 0 &&
+ mFrame.right >= screenWidth && mFrame.bottom >= screenHeight;
}
void removeLocked() {
@@ -1492,38 +1479,28 @@
return true;
}
- private static void applyScaledInsets(Region outRegion, Rect frame, Rect inset, float scale) {
- if (scale != 1) {
- outRegion.set(frame.left + (int)(inset.left*scale),
- frame.top + (int)(inset.top*scale),
- frame.right - (int)(inset.right*scale),
- frame.bottom - (int)(inset.bottom*scale));
- } else {
- outRegion.set(
- frame.left + inset.left, frame.top + inset.top,
- frame.right - inset.right, frame.bottom - inset.bottom);
- }
+ private static void applyInsets(Region outRegion, Rect frame, Rect inset) {
+ outRegion.set(
+ frame.left + inset.left, frame.top + inset.top,
+ frame.right - inset.right, frame.bottom - inset.bottom);
}
public void getTouchableRegion(Region outRegion) {
- final Rect frame = mScaledFrame;
+ final Rect frame = mFrame;
switch (mTouchableInsets) {
default:
case ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_FRAME:
outRegion.set(frame);
break;
case ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_CONTENT:
- applyScaledInsets(outRegion, frame, mGivenContentInsets, mGlobalScale);
+ applyInsets(outRegion, frame, mGivenContentInsets);
break;
case ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_VISIBLE:
- applyScaledInsets(outRegion, frame, mGivenVisibleInsets, mGlobalScale);
+ applyInsets(outRegion, frame, mGivenVisibleInsets);
break;
case ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_REGION: {
final Region givenTouchableRegion = mGivenTouchableRegion;
outRegion.set(givenTouchableRegion);
- if (mGlobalScale != 1) {
- outRegion.scale(mGlobalScale);
- }
outRegion.translate(frame.left, frame.top);
break;
}
@@ -1586,8 +1563,7 @@
}
pw.print(prefix); pw.print("Requested w="); pw.print(mRequestedWidth);
pw.print(" h="); pw.print(mRequestedHeight);
- pw.print(" mLayoutSeq="); pw.print(mLayoutSeq);
- pw.print(" mNeedsBackgroundFiller="); pw.println(mNeedsBackgroundFiller);
+ pw.print(" mLayoutSeq="); pw.println(mLayoutSeq);
if (mXOffset != 0 || mYOffset != 0) {
pw.print(prefix); pw.print("Offsets x="); pw.print(mXOffset);
pw.print(" y="); pw.println(mYOffset);
@@ -1608,8 +1584,12 @@
pw.println();
pw.print(prefix); pw.print("mFrame="); mFrame.printShortString(pw);
pw.print(" last="); mLastFrame.printShortString(pw);
- pw.print(" scaled="); mScaledFrame.printShortString(pw);
pw.println();
+ if (mEnforceSizeCompat) {
+ pw.print(prefix); pw.print("mCompatFrame="); mCompatFrame.printShortString(pw);
+ pw.print(" last="); mLastCompatFrame.printShortString(pw);
+ pw.println();
+ }
pw.print(prefix); pw.print("mContainingFrame=");
mContainingFrame.printShortString(pw);
pw.print(" mParentFrame=");
diff --git a/services/sensorservice/SensorService.cpp b/services/sensorservice/SensorService.cpp
index ce1ab3d..c5e69ff 100644
--- a/services/sensorservice/SensorService.cpp
+++ b/services/sensorservice/SensorService.cpp
@@ -44,8 +44,7 @@
// ---------------------------------------------------------------------------
SensorService::SensorService()
- : Thread(false),
- mDump("android.permission.DUMP"),
+ : mDump("android.permission.DUMP"),
mInitCheck(NO_INIT)
{
}
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index bbf1814..8df2b92 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -655,8 +655,9 @@
// update the layer size and release freeze-lock
const Layer::State& front(drawingState());
- if (newFrontBuffer->getWidth() == front.requested_w &&
- newFrontBuffer->getHeight() == front.requested_h)
+ if ((newFrontBuffer->getWidth() == front.requested_w &&
+ newFrontBuffer->getHeight() == front.requested_h) ||
+ isFixedSize())
{
if ((front.w != front.requested_w) ||
(front.h != front.requested_h))
diff --git a/telephony/java/com/android/internal/telephony/ApnContext.java b/telephony/java/com/android/internal/telephony/ApnContext.java
index ce1a3b6..496c43c 100644
--- a/telephony/java/com/android/internal/telephony/ApnContext.java
+++ b/telephony/java/com/android/internal/telephony/ApnContext.java
@@ -85,12 +85,10 @@
public synchronized DataConnectionAc getDataConnectionAc() {
- log("getDataConnectionAc dcac=" + mDataConnectionAc);
return mDataConnectionAc;
}
public synchronized void setDataConnectionAc(DataConnectionAc dcac) {
- log("setDataConnectionAc dcac=" + dcac);
mDataConnectionAc = dcac;
}
diff --git a/telephony/java/com/android/internal/telephony/DataConnection.java b/telephony/java/com/android/internal/telephony/DataConnection.java
index 0188cf1..2e781b2 100644
--- a/telephony/java/com/android/internal/telephony/DataConnection.java
+++ b/telephony/java/com/android/internal/telephony/DataConnection.java
@@ -509,24 +509,56 @@
result.mFailCause = FailCause.fromInt(response.status);
} else {
log("onSetupConnectionCompleted received DataCallState: " + response);
-
- // Check if system property dns usable
- boolean okToUseSystemPropertyDns = false;
cid = response.cid;
- String propertyPrefix = "net." + response.ifname + ".";
- String dnsServers[] = new String[2];
- dnsServers[0] = SystemProperties.get(propertyPrefix + "dns1");
- dnsServers[1] = SystemProperties.get(propertyPrefix + "dns2");
- okToUseSystemPropertyDns = isDnsOk(dnsServers);
-
// set link properties based on data call response
- result = response.setLinkProperties(mLinkProperties,
- okToUseSystemPropertyDns);
+ result = setLinkProperties(response, mLinkProperties);
}
return result;
}
+ private DataCallState.SetupResult setLinkProperties(DataCallState response,
+ LinkProperties lp) {
+ // Check if system property dns usable
+ boolean okToUseSystemPropertyDns = false;
+ String propertyPrefix = "net." + response.ifname + ".";
+ String dnsServers[] = new String[2];
+ dnsServers[0] = SystemProperties.get(propertyPrefix + "dns1");
+ dnsServers[1] = SystemProperties.get(propertyPrefix + "dns2");
+ okToUseSystemPropertyDns = isDnsOk(dnsServers);
+
+ // set link properties based on data call response
+ return response.setLinkProperties(lp, okToUseSystemPropertyDns);
+ }
+
+ private boolean updateLinkProperty(DataCallState newState) {
+ boolean changed = false;
+
+ if (newState == null) return changed;
+
+ DataCallState.SetupResult result;
+ LinkProperties newLp = new LinkProperties();
+
+ // set link properties based on data call response
+ result = setLinkProperties(newState, newLp);
+ if (result != DataCallState.SetupResult.SUCCESS) {
+ if (DBG) log("UpdateLinkProperty failed : " + result);
+ return changed;
+ }
+ // copy HTTP proxy as it is not part DataCallState.
+ newLp.setHttpProxy(mLinkProperties.getHttpProxy());
+
+ if (DBG) log("old LP=" + mLinkProperties);
+ if (DBG) log("new LP=" + newLp);
+
+ if (mLinkProperties == null || !mLinkProperties.equals(newLp)) {
+ mLinkProperties = newLp;
+ changed = true;
+ }
+
+ return changed;
+ }
+
/**
* The parent state for all other states.
*/
@@ -597,17 +629,25 @@
mAc.replyToMessage(msg, DataConnectionAc.RSP_SET_LINK_PROPERTIES_HTTP_PROXY);
break;
}
+ case DataConnectionAc.REQ_UPDATE_LINK_PROPERTIES_DATA_CALL_STATE: {
+ DataCallState newState = (DataCallState) msg.obj;
+ int updated = updateLinkProperty(newState) ? 1 : 0;
+ if (DBG) {
+ log("REQ_UPDATE_LINK_PROPERTIES_DATA_CALL_STATE updated="
+ + (updated == 1)
+ + " newState=" + newState);
+ }
+ mAc.replyToMessage(msg,
+ DataConnectionAc.RSP_UPDATE_LINK_PROPERTIES_DATA_CALL_STATE,
+ updated);
+ break;
+ }
case DataConnectionAc.REQ_GET_LINK_CAPABILITIES: {
LinkCapabilities lc = new LinkCapabilities(mCapabilities);
log("REQ_GET_LINK_CAPABILITIES linkCapabilities" + lc);
mAc.replyToMessage(msg, DataConnectionAc.RSP_GET_LINK_CAPABILITIES, lc);
break;
}
- case DataConnectionAc.REQ_UPDATE_LINK_PROPERTIES_DATA_CALL_STATE: {
- Bundle data = msg.getData();
- mLinkProperties = (LinkProperties) data.get("linkProperties");
- break;
- }
case DataConnectionAc.REQ_RESET:
if (DBG) log("DcDefaultState: msg.what=REQ_RESET");
clearSettings();
diff --git a/telephony/java/com/android/internal/telephony/DataConnectionAc.java b/telephony/java/com/android/internal/telephony/DataConnectionAc.java
index a9796dd..2ab6184 100644
--- a/telephony/java/com/android/internal/telephony/DataConnectionAc.java
+++ b/telephony/java/com/android/internal/telephony/DataConnectionAc.java
@@ -226,6 +226,38 @@
}
/**
+ * Request update LinkProperties from DataCallState
+ * Response {@link #rspUpdateLinkPropertiesDataCallState}
+ */
+ public void reqUpdateLinkPropertiesDataCallState(DataCallState newState) {
+ sendMessage(REQ_UPDATE_LINK_PROPERTIES_DATA_CALL_STATE, newState);
+ if (DBG) log("reqUpdateLinkPropertiesDataCallState");
+ }
+
+ public boolean rspUpdateLinkPropertiesDataCallState(Message response) {
+ boolean retVal = response.arg1 == 1;
+ if (DBG) log("rspUpdateLinkPropertiesState=" + retVal);
+ return retVal;
+ }
+
+ /**
+ * Update link properties in the data connection
+ *
+ * @return true if link property has been updated. false otherwise.
+ */
+ public boolean updateLinkPropertiesDataCallStateSync(DataCallState newState) {
+ Message response =
+ sendMessageSynchronously(REQ_UPDATE_LINK_PROPERTIES_DATA_CALL_STATE, newState);
+ if ((response != null) &&
+ (response.what == RSP_UPDATE_LINK_PROPERTIES_DATA_CALL_STATE)) {
+ return rspUpdateLinkPropertiesDataCallState(response);
+ } else {
+ log("getLinkProperties error response=" + response);
+ return false;
+ }
+ }
+
+ /**
* Request the connections LinkCapabilities.
* Response {@link #rspLinkCapabilities}
*/
diff --git a/telephony/java/com/android/internal/telephony/Phone.java b/telephony/java/com/android/internal/telephony/Phone.java
index ddf066e..48c5318 100644
--- a/telephony/java/com/android/internal/telephony/Phone.java
+++ b/telephony/java/com/android/internal/telephony/Phone.java
@@ -178,6 +178,7 @@
static final String REASON_NW_TYPE_CHANGED = "nwTypeChanged";
static final String REASON_DATA_DEPENDENCY_MET = "dependencyMet";
static final String REASON_DATA_DEPENDENCY_UNMET = "dependencyUnmet";
+ static final String REASON_LINK_PROPERTIES_CHANGED = "linkPropertiesChanged";
// Used for band mode selection methods
static final int BM_UNSPECIFIED = 0; // selected by baseband automatically
diff --git a/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java b/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java
index e61af31..6b4054a 100644
--- a/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java
+++ b/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java
@@ -970,23 +970,6 @@
return true;
}
- private boolean dataCallStatesHasCID (ArrayList<DataCallState> states, int cid) {
- for (int i = 0, s = states.size() ; i < s ; i++) {
- if (states.get(i).cid == cid) return true;
- }
- return false;
- }
-
- private boolean dataCallStatesHasActiveCID (ArrayList<DataCallState> states, int cid) {
- for (int i = 0, s = states.size() ; i < s ; i++) {
- if ((states.get(i).cid == cid) && (states.get(i).active != 0)) {
- return true;
- }
- }
-
- return false;
- }
-
/**
* Handles changes to the APN database.
*/
@@ -1014,15 +997,13 @@
}
/**
- * @param explicitPoll if true, indicates that *we* polled for this
- * update while state == CONNECTED rather than having it delivered
- * via an unsolicited response (which could have happened at any
- * previous state
+ * @param ar is the result of RIL_REQUEST_DATA_CALL_LIST
+ * or RIL_UNSOL_DATA_CALL_LIST_CHANGED
*/
private void onDataStateChanged (AsyncResult ar) {
ArrayList<DataCallState> dataCallStates;
- if (DBG) log("onDataStateChanged(ar) E");
+ if (DBG) log("onDataStateChanged(ar): E");
dataCallStates = (ArrayList<DataCallState>)(ar.result);
if (ar.exception != null) {
@@ -1033,65 +1014,79 @@
return;
}
+ // Create a hash map to store the dataCallState of each call id
+ // TODO: Depends on how frequent the DATA_CALL_LIST got updated,
+ // may cache response to reduce comparison.
+ HashMap<Integer, DataCallState> response;
+ response = new HashMap<Integer, DataCallState>();
+ if (DBG) log("onDataStateChanged(ar): DataCallState size=" + dataCallStates.size());
+ for (DataCallState dc : dataCallStates) {
+ response.put(dc.cid, dc);
+ if (DBG) log("onDataStateChanged(ar): " + dc.cid + ": " + dc.toString());
+ }
+
+ // For each connected apn, check if there is a matched active
+ // data call state, which has the same link properties.
+ if (DBG) log(" ApnContext size=" + mApnContexts.values().size());
for (ApnContext apnContext : mApnContexts.values()) {
- onDataStateChanged(dataCallStates, apnContext);
- }
- if (DBG) log("onDataStateChanged(ar) X");
- }
-
- private void onDataStateChanged (ArrayList<DataCallState> dataCallStates,
- ApnContext apnContext) {
- if (DBG) log("onDataStateChanged(dataCallState, apnContext): apnContext=" + apnContext);
-
- if (apnContext == null) {
- // Should not happen
- if (DBG) log("onDataStateChanged(dataCallState, apnContext): ignore apnContext=null");
- return;
- }
-
- if (apnContext.getState() == State.CONNECTED) {
- // The way things are supposed to work, the PDP list
- // should not contain the CID after it disconnects.
- // However, the way things really work, sometimes the PDP
- // context is still listed with active = false, which
- // makes it hard to distinguish an activating context from
- // an activated-and-then deactivated one.
+ if (DBG){
+ log("onDataStateChanged(ar): " + apnContext.toString());
+ if (apnContext.getDataConnection() != null) {
+ log("onDataStateChanged(ar): " + apnContext.getDataConnection().toString());
+ }
+ }
DataConnectionAc dcac = apnContext.getDataConnectionAc();
if (dcac == null) {
- if (DBG) log("onDataStateChanged(dataCallState, apnContext): dcac==null BAD NEWS");
- return;
+ continue;
}
- int cid = dcac.getCidSync();
- if (!dataCallStatesHasCID(dataCallStates, cid)) {
- // It looks like the PDP context has deactivated.
- // Tear everything down and try to reconnect.
+ int connectionId = dcac.getCidSync();
- if (DBG) {
- log("onDataStateChanged(dataCallStates,apnContext) " +
- "PDP connection has dropped. Reconnecting");
+ if (apnContext.getState() == State.CONNECTED) {
+ // The way things are supposed to work, the PDP list
+ // should not contain the CID after it disconnects.
+ // However, the way things really work, sometimes the PDP
+ // context is still listed with active = false, which
+ // makes it hard to distinguish an activating context from
+ // an activated-and-then de-activated one.
+ if (response.containsKey(connectionId)) {
+ DataCallState newState = response.get(connectionId);
+ if (DBG) log("onDataStateChanged(ar): Found ConnId=" + connectionId
+ + " newState=" + newState.toString());
+ if (newState.active != 0) {
+ boolean changed
+ = dcac.updateLinkPropertiesDataCallStateSync(newState);
+ if (changed) {
+ if (DBG) log("onDataStateChanged(ar): Found and changed, notify");
+ mPhone.notifyDataConnection(Phone.REASON_LINK_PROPERTIES_CHANGED,
+ apnContext.getApnType());
+ // Temporary hack, if false we'll reset connections and at this
+ // time a transition from CDMA -> Global fails. The DEACTIVATE
+ // fails with a GENERIC_FAILURE and the VZWINTERNET connection is
+ // never setup. @see bug/
+ if (SystemProperties.getBoolean("telephony.ignore-state-changes",
+ true)) {
+ log("onDataStateChanged(ar): STOPSHIP don't reset, continue");
+ continue;
+ }
+ } else {
+ if (DBG) log("onDataStateChanged(ar): Found but no change, skip");
+ continue;
+ }
+ }
}
+
+ if (DBG) log("onDataStateChanged(ar): reset connection.");
+
// Add an event log when the network drops PDP
- int cellLocationId = getCellLocationId();
- EventLog.writeEvent(EventLogTags.PDP_NETWORK_DROP, cellLocationId,
- TelephonyManager.getDefault().getNetworkType());
-
- cleanUpConnection(true, apnContext);
- } else if (!dataCallStatesHasActiveCID(dataCallStates,
- apnContext.getDataConnectionAc().getCidSync())) {
-
- if (DBG) {
- log("onDataStateChanged(dataCallStates,apnContext) " +
- "PDP connection has dropped (active=false case). Reconnecting");
- }
-
- // Log the network drop on the event log.
- int cellLocationId = getCellLocationId();
- EventLog.writeEvent(EventLogTags.PDP_NETWORK_DROP, cellLocationId,
+ int cid = getCellLocationId();
+ EventLog.writeEvent(EventLogTags.PDP_NETWORK_DROP, cid,
TelephonyManager.getDefault().getNetworkType());
cleanUpConnection(true, apnContext);
}
}
+
+ if (DBG) log("onDataStateChanged(ar): X");
}
private void notifyDefaultData(ApnContext apnContext) {
@@ -2121,7 +2116,7 @@
@Override
protected void log(String s) {
- Log.d(LOG_TAG, "[GsmDCT] " + s);
+ Log.d(LOG_TAG, "[GsmDCT] "+ s);
}
@Override
diff --git a/telephony/java/com/android/internal/telephony/gsm/SIMRecords.java b/telephony/java/com/android/internal/telephony/gsm/SIMRecords.java
index 27cde78..891c7cb 100755
--- a/telephony/java/com/android/internal/telephony/gsm/SIMRecords.java
+++ b/telephony/java/com/android/internal/telephony/gsm/SIMRecords.java
@@ -496,11 +496,6 @@
return null;
}
- // STOPSHIP: to be removed
- if (BaseCommands.getLteOnCdmaModeStatic() == Phone.LTE_ON_CDMA_TRUE) {
- Log.e(LOG_TAG, "getOperatorNumeric: STOPSHIP bad numeric operators in lte");
- return SystemProperties.get("ro.cdma.home.operator.numeric", "310004");
- }
// Length = length of MCC + length of MNC
// length of mcc = 3 (TS 23.003 Section 2.2)
return imsi.substring(0, 3 + mncLength);
diff --git a/tests/DumpRenderTree/src/com/android/dumprendertree/LoadTestsAutoTest.java b/tests/DumpRenderTree/src/com/android/dumprendertree/LoadTestsAutoTest.java
index ee5bb5d..d883a32 100644
--- a/tests/DumpRenderTree/src/com/android/dumprendertree/LoadTestsAutoTest.java
+++ b/tests/DumpRenderTree/src/com/android/dumprendertree/LoadTestsAutoTest.java
@@ -100,7 +100,7 @@
throw new RuntimeException("No test specified");
}
- TestShellActivity activity = (TestShellActivity) getActivity();
+ final TestShellActivity activity = (TestShellActivity) getActivity();
Log.v(LOGTAG, "About to run tests, calling gc first...");
freeMem();
@@ -109,7 +109,13 @@
runTestAndWaitUntilDone(activity, runner.mTestPath, runner.mTimeoutInMillis,
runner.mGetDrawTime, runner.mSaveImagePath);
- activity.clearCache();
+ getInstrumentation().runOnMainSync(new Runnable() {
+
+ @Override
+ public void run() {
+ activity.clearCache();
+ }
+ });
if (mForwardServer != null) {
mForwardServer.stop();
mForwardServer = null;
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/Bridge.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/Bridge.java
index 3c0c9a4..144ec42 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/Bridge.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/Bridge.java
@@ -201,7 +201,8 @@
Capability.VIEW_MANIPULATION,
Capability.PLAY_ANIMATION,
Capability.ANIMATED_VIEW_MANIPULATION,
- Capability.ADAPTER_BINDING);
+ Capability.ADAPTER_BINDING,
+ Capability.EXTENDED_VIEWINFO);
BridgeAssetManager.initSystem();
@@ -399,15 +400,6 @@
throw new IllegalArgumentException("viewObject is not a View");
}
- @Override
- public int getViewBaseline(Object viewObject) {
- if (viewObject instanceof View) {
- return ((View) viewObject).getBaseline();
- }
-
- throw new IllegalArgumentException("viewObject is not a View");
- }
-
/**
* Returns the lock for the bridge
*/
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/MockView.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/MockView.java
index 1ca3182..3d50b2a 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/MockView.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/MockView.java
@@ -19,21 +19,23 @@
import android.content.Context;
import android.graphics.Canvas;
import android.util.AttributeSet;
+import android.view.Gravity;
import android.widget.TextView;
/**
* Base class for mocked views.
- *
+ *
* TODO: implement onDraw and draw a rectangle in a random color with the name of the class
* (or better the id of the view).
*/
public class MockView extends TextView {
-
+
public MockView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
-
+
setText(this.getClass().getSimpleName());
setTextColor(0xFF000000);
+ setGravity(Gravity.CENTER);
}
@Override
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 c53cb23..b800519 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
@@ -74,6 +74,7 @@
import android.view.View.AttachInfo;
import android.view.View.MeasureSpec;
import android.view.ViewGroup.LayoutParams;
+import android.view.ViewGroup.MarginLayoutParams;
import android.widget.AbsListView;
import android.widget.AbsSpinner;
import android.widget.AdapterView;
@@ -513,7 +514,7 @@
mViewRoot.draw(mCanvas);
}
- mViewInfoList = startVisitingViews(mViewRoot, 0);
+ mViewInfoList = startVisitingViews(mViewRoot, 0, params.getExtendedViewInfoMode());
// success!
return SUCCESS.createResult();
@@ -1255,7 +1256,7 @@
}
}
- private List<ViewInfo> startVisitingViews(View view, int offset) {
+ private List<ViewInfo> startVisitingViews(View view, int offset, boolean setExtendedInfo) {
if (view == null) {
return null;
}
@@ -1264,7 +1265,7 @@
offset += view.getTop();
if (view == mContentRoot) {
- return visitAllChildren(mContentRoot, offset);
+ return visitAllChildren(mContentRoot, offset, setExtendedInfo);
}
// otherwise, look for mContentRoot in the children
@@ -1272,7 +1273,8 @@
ViewGroup group = ((ViewGroup) view);
for (int i = 0; i < group.getChildCount(); i++) {
- List<ViewInfo> list = startVisitingViews(group.getChildAt(i), offset);
+ List<ViewInfo> list = startVisitingViews(group.getChildAt(i), offset,
+ setExtendedInfo);
if (list != null) {
return list;
}
@@ -1287,8 +1289,9 @@
* bounds of all the views.
* @param view the root View
* @param offset an offset for the view bounds.
+ * @param setExtendedInfo whether to set the extended view info in the {@link ViewInfo} object.
*/
- private ViewInfo visit(View view, int offset) {
+ private ViewInfo visit(View view, int offset, boolean setExtendedInfo) {
if (view == null) {
return null;
}
@@ -1298,9 +1301,22 @@
view.getLeft(), view.getTop() + offset, view.getRight(), view.getBottom() + offset,
view, view.getLayoutParams());
+ if (setExtendedInfo) {
+ MarginLayoutParams marginParams = null;
+ LayoutParams params = view.getLayoutParams();
+ if (params instanceof MarginLayoutParams) {
+ marginParams = (MarginLayoutParams) params;
+ }
+ result.setExtendedInfo(view.getBaseline(),
+ marginParams != null ? marginParams.leftMargin : 0,
+ marginParams != null ? marginParams.topMargin : 0,
+ marginParams != null ? marginParams.rightMargin : 0,
+ marginParams != null ? marginParams.bottomMargin : 0);
+ }
+
if (view instanceof ViewGroup) {
ViewGroup group = ((ViewGroup) view);
- result.setChildren(visitAllChildren(group, 0 /*offset*/));
+ result.setChildren(visitAllChildren(group, 0 /*offset*/, setExtendedInfo));
}
return result;
@@ -1311,15 +1327,17 @@
* containing the bounds of all the views.
* @param view the root View
* @param offset an offset for the view bounds.
+ * @param setExtendedInfo whether to set the extended view info in the {@link ViewInfo} object.
*/
- private List<ViewInfo> visitAllChildren(ViewGroup viewGroup, int offset) {
+ private List<ViewInfo> visitAllChildren(ViewGroup viewGroup, int offset,
+ boolean setExtendedInfo) {
if (viewGroup == null) {
return null;
}
List<ViewInfo> children = new ArrayList<ViewInfo>();
for (int i = 0; i < viewGroup.getChildCount(); i++) {
- children.add(visit(viewGroup.getChildAt(i), offset));
+ children.add(visit(viewGroup.getChildAt(i), offset, setExtendedInfo));
}
return children;
}
diff --git a/wifi/java/android/net/wifi/IWifiManager.aidl b/wifi/java/android/net/wifi/IWifiManager.aidl
index 16a61db..0757efd 100644
--- a/wifi/java/android/net/wifi/IWifiManager.aidl
+++ b/wifi/java/android/net/wifi/IWifiManager.aidl
@@ -87,7 +87,7 @@
void releaseMulticastLock();
- boolean setWifiApEnabled(in WifiConfiguration wifiConfig, boolean enable);
+ void setWifiApEnabled(in WifiConfiguration wifiConfig, boolean enable);
int getWifiApEnabledState();
diff --git a/wifi/java/android/net/wifi/WifiApConfigStore.java b/wifi/java/android/net/wifi/WifiApConfigStore.java
new file mode 100644
index 0000000..bb5427d
--- /dev/null
+++ b/wifi/java/android/net/wifi/WifiApConfigStore.java
@@ -0,0 +1,181 @@
+/*
+ * 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 android.net.wifi;
+
+import android.content.Context;
+import android.net.wifi.WifiConfiguration.KeyMgmt;
+import android.os.Environment;
+import android.os.Message;
+import android.os.Handler;
+import android.os.HandlerThread;
+import android.util.Log;
+
+import java.io.BufferedInputStream;
+import java.io.BufferedOutputStream;
+import java.io.DataInputStream;
+import java.io.DataOutputStream;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.net.InetAddress;
+import java.util.UUID;
+
+import com.android.internal.R;
+
+
+/**
+ * Provides API to the WifiStateMachine for doing read/write access
+ * to soft access point configuration
+ */
+class WifiApConfigStore {
+
+ private static Context sContext;
+ private static final String TAG = "WifiApConfigStore";
+
+ private static final String AP_CONFIG_FILE = Environment.getDataDirectory() +
+ "/misc/wifi/softap.conf";
+
+ private static final int AP_CONFIG_FILE_VERSION = 1;
+
+ private static WifiConfiguration sApConfig = new WifiConfiguration();
+ private static final Object sApConfigLock = new Object();
+
+ private static FileReadWriteHandler sFileReadWriteHandler;
+ private static final int READ_AP_CONFIG = 1;
+ private static final int WRITE_AP_CONFIG = 2;
+
+ static void initialize(Context context) {
+ sContext = context;
+
+ /* File operations happen on a seperate thread */
+ HandlerThread configThread = new HandlerThread("WifiApConfigStore");
+ configThread.start();
+ sFileReadWriteHandler = new FileReadWriteHandler(configThread.getLooper());
+ Message.obtain(sFileReadWriteHandler, READ_AP_CONFIG).sendToTarget();
+ }
+
+
+ static void setApConfiguration(WifiConfiguration config) {
+ synchronized (sApConfigLock) {
+ sApConfig = config;
+ }
+ Message.obtain(sFileReadWriteHandler, WRITE_AP_CONFIG, new WifiConfiguration(config))
+ .sendToTarget();
+ }
+
+ static WifiConfiguration getApConfiguration() {
+ synchronized (sApConfigLock) {
+ return new WifiConfiguration(sApConfig);
+ }
+ }
+
+ /**
+ * File read/write handler
+ */
+ private static class FileReadWriteHandler extends Handler {
+
+ public FileReadWriteHandler(android.os.Looper looper) {
+ super(looper);
+ }
+
+ @Override
+ public void handleMessage(Message msg) {
+ switch (msg.what) {
+ case WRITE_AP_CONFIG:
+ writeApConfiguration((WifiConfiguration) msg.obj);
+ break;
+ case READ_AP_CONFIG:
+ readApConfiguration();
+ break;
+ default:
+ Log.e(TAG, "Unknown command in FileReadWriteHandler: " + msg);
+ break;
+ }
+ }
+
+ private static void writeApConfiguration(final WifiConfiguration config) {
+ DataOutputStream out = null;
+ try {
+ out = new DataOutputStream(new BufferedOutputStream(
+ new FileOutputStream(AP_CONFIG_FILE)));
+
+ out.writeInt(AP_CONFIG_FILE_VERSION);
+ out.writeUTF(config.SSID);
+ int authType = config.getAuthType();
+ out.writeInt(authType);
+ if(authType != KeyMgmt.NONE) {
+ out.writeUTF(config.preSharedKey);
+ }
+ } catch (IOException e) {
+ Log.e(TAG, "Error writing hotspot configuration" + e);
+ } finally {
+ if (out != null) {
+ try {
+ out.close();
+ } catch (IOException e) {}
+ }
+ }
+ }
+
+ private static void readApConfiguration() {
+ DataInputStream in = null;
+ try {
+ WifiConfiguration config = new WifiConfiguration();
+ in = new DataInputStream(new BufferedInputStream(new FileInputStream(
+ AP_CONFIG_FILE)));
+
+ int version = in.readInt();
+ if (version != 1) {
+ Log.e(TAG, "Bad version on hotspot configuration file, set defaults");
+ setDefaultApConfiguration();
+ return;
+ }
+ config.SSID = in.readUTF();
+ int authType = in.readInt();
+ config.allowedKeyManagement.set(authType);
+ if (authType != KeyMgmt.NONE) {
+ config.preSharedKey = in.readUTF();
+ }
+ synchronized (sApConfigLock) {
+ sApConfig = config;
+ }
+ } catch (IOException ignore) {
+ setDefaultApConfiguration();
+ } finally {
+ if (in != null) {
+ try {
+ in.close();
+ } catch (IOException e) {}
+ }
+ }
+ }
+
+ /* Generate a default WPA2 based configuration with a random password.
+ We are changing the Wifi Ap configuration storage from secure settings to a
+ flat file accessible only by the system. A WPA2 based default configuration
+ will keep the device secure after the update */
+ private static void setDefaultApConfiguration() {
+ WifiConfiguration config = new WifiConfiguration();
+ config.SSID = sContext.getString(R.string.wifi_tether_configure_ssid_default);
+ config.allowedKeyManagement.set(KeyMgmt.WPA2_PSK);
+ String randomUUID = UUID.randomUUID().toString();
+ //first 12 chars from xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx
+ config.preSharedKey = randomUUID.substring(0, 8) + randomUUID.substring(9,13);
+ setApConfiguration(config);
+ }
+ }
+}
diff --git a/wifi/java/android/net/wifi/WifiManager.java b/wifi/java/android/net/wifi/WifiManager.java
index d40f146..9d1bdd4 100644
--- a/wifi/java/android/net/wifi/WifiManager.java
+++ b/wifi/java/android/net/wifi/WifiManager.java
@@ -898,7 +898,8 @@
*/
public boolean setWifiApEnabled(WifiConfiguration wifiConfig, boolean enabled) {
try {
- return mService.setWifiApEnabled(wifiConfig, enabled);
+ mService.setWifiApEnabled(wifiConfig, enabled);
+ return true;
} catch (RemoteException e) {
return false;
}
diff --git a/wifi/java/android/net/wifi/WifiStateMachine.java b/wifi/java/android/net/wifi/WifiStateMachine.java
index 9125037..134f29f 100644
--- a/wifi/java/android/net/wifi/WifiStateMachine.java
+++ b/wifi/java/android/net/wifi/WifiStateMachine.java
@@ -200,8 +200,12 @@
static final int CMD_START_AP = BASE + 21;
/* Stop the soft access point */
static final int CMD_STOP_AP = BASE + 22;
+ /* Set the soft access point configuration */
+ static final int CMD_SET_AP_CONFIG = BASE + 23;
+ /* Get the soft access point configuration */
+ static final int CMD_GET_AP_CONFIG = BASE + 24;
- static final int CMD_BLUETOOTH_ADAPTER_STATE_CHANGE = BASE + 23;
+ static final int CMD_BLUETOOTH_ADAPTER_STATE_CHANGE = BASE + 25;
/* Supplicant events */
/* Connection to supplicant established */
@@ -365,6 +369,10 @@
private static final int MIN_RSSI = -200;
private static final int MAX_RSSI = 256;
+ /* Constants to indicate if soft ap is running or stopped */
+ private static final int SOFT_AP_STOPPED = 0;
+ private static final int SOFT_AP_RUNNING = 1;
+
/* Default parent state */
private State mDefaultState = new DefaultState();
/* Temporary initial state */
@@ -609,6 +617,17 @@
}
}
+ public void setWifiApConfiguration(WifiConfiguration config) {
+ sendMessage(obtainMessage(CMD_SET_AP_CONFIG, config));
+ }
+
+ public WifiConfiguration syncGetWifiApConfiguration(AsyncChannel channel) {
+ Message resultMsg = channel.sendMessageSynchronously(CMD_GET_AP_CONFIG);
+ WifiConfiguration ret = (WifiConfiguration) resultMsg.obj;
+ resultMsg.recycle();
+ return ret;
+ }
+
/**
* TODO: doc
*/
@@ -1533,7 +1552,31 @@
*/
WifiNative.disconnectCommand();
WifiNative.reconnectCommand();
+ }
+ private boolean startSoftApWithConfig(WifiConfiguration config, int currentStatus) {
+ if (config == null) {
+ config = WifiApConfigStore.getApConfiguration();
+ } else {
+ WifiApConfigStore.setApConfiguration(config);
+ }
+ try {
+ if (currentStatus == SOFT_AP_STOPPED) {
+ nwService.startAccessPoint(config, mInterfaceName, SOFTAP_IFACE);
+ } else if (currentStatus == SOFT_AP_RUNNING) {
+ nwService.setAccessPoint(config, mInterfaceName, SOFTAP_IFACE);
+ }
+ } catch (Exception e) {
+ Log.e(TAG, "Exception in softap start " + e);
+ try {
+ nwService.stopAccessPoint();
+ nwService.startAccessPoint(config, mInterfaceName, SOFTAP_IFACE);
+ } catch (Exception ee) {
+ Log.e(TAG, "Exception during softap restart : " + ee);
+ return false;
+ }
+ }
+ return true;
}
@@ -1671,6 +1714,13 @@
case CMD_ENABLE_BACKGROUND_SCAN:
mEnableBackgroundScan = (message.arg1 == 1);
break;
+ case CMD_SET_AP_CONFIG:
+ WifiApConfigStore.setApConfiguration((WifiConfiguration) message.obj);
+ break;
+ case CMD_GET_AP_CONFIG:
+ WifiConfiguration config = WifiApConfigStore.getApConfiguration();
+ mReplyChannel.replyToMessage(message, message.what, config);
+ break;
/* Discard */
case CMD_LOAD_DRIVER:
case CMD_UNLOAD_DRIVER:
@@ -1733,6 +1783,8 @@
// 50021 wifi_state_changed (custom|1|5)
EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName());
+ WifiApConfigStore.initialize(mContext);
+
if (WifiNative.isDriverLoaded()) {
transitionTo(mDriverLoadedState);
}
@@ -1845,26 +1897,14 @@
}
break;
case CMD_START_AP:
- try {
- nwService.startAccessPoint((WifiConfiguration) message.obj,
- mInterfaceName,
- SOFTAP_IFACE);
- } catch (Exception e) {
- Log.e(TAG, "Exception in softap start " + e);
- try {
- nwService.stopAccessPoint();
- nwService.startAccessPoint((WifiConfiguration) message.obj,
- mInterfaceName,
- SOFTAP_IFACE);
- } catch (Exception ee) {
- Log.e(TAG, "Exception during softap restart : " + ee);
- sendMessage(obtainMessage(CMD_UNLOAD_DRIVER, WIFI_AP_STATE_FAILED, 0));
- break;
- }
+ if (startSoftApWithConfig((WifiConfiguration) message.obj, SOFT_AP_STOPPED)) {
+ Log.d(TAG, "Soft AP start successful");
+ setWifiApState(WIFI_AP_STATE_ENABLED);
+ transitionTo(mSoftApStartedState);
+ } else {
+ Log.d(TAG, "Soft AP start failed");
+ sendMessage(obtainMessage(CMD_UNLOAD_DRIVER, WIFI_AP_STATE_FAILED, 0));
}
- Log.d(TAG, "Soft AP start successful");
- setWifiApState(WIFI_AP_STATE_ENABLED);
- transitionTo(mSoftApStartedState);
break;
default:
return NOT_HANDLED;
@@ -3025,21 +3065,13 @@
break;
case CMD_START_AP:
Log.d(TAG,"SoftAP set on a running access point");
- try {
- nwService.setAccessPoint((WifiConfiguration) message.obj,
- mInterfaceName,
- SOFTAP_IFACE);
- } catch(Exception e) {
- Log.e(TAG, "Exception in softap set " + e);
- try {
- nwService.stopAccessPoint();
- nwService.startAccessPoint((WifiConfiguration) message.obj,
- mInterfaceName,
- SOFTAP_IFACE);
- } catch (Exception ee) {
- Log.e(TAG, "Could not restart softap after set failed " + ee);
- sendMessage(obtainMessage(CMD_UNLOAD_DRIVER, WIFI_AP_STATE_FAILED, 0));
- }
+ if (startSoftApWithConfig((WifiConfiguration) message.obj, SOFT_AP_RUNNING)) {
+ Log.d(TAG, "Soft AP start successful");
+ setWifiApState(WIFI_AP_STATE_ENABLED);
+ transitionTo(mSoftApStartedState);
+ } else {
+ Log.d(TAG, "Soft AP start failed");
+ sendMessage(obtainMessage(CMD_UNLOAD_DRIVER, WIFI_AP_STATE_FAILED, 0));
}
break;
/* Fail client mode operation when soft AP is enabled */